API: Add endpoint to check custom domain resolution (#6110)

This commit is contained in:
Tom Moor
2023-11-04 15:21:47 -04:00
committed by GitHub
parent b2ad6ca9bc
commit c769a95f65
4 changed files with 108 additions and 2 deletions

View File

@@ -1,5 +1,6 @@
import dns from "dns";
import Router from "koa-router";
import { parseDomain } from "@shared/utils/domains";
import { getBaseDomain, parseDomain } from "@shared/utils/domains";
import parseDocumentSlug from "@shared/utils/parseDocumentSlug";
import parseMentionUrl from "@shared/utils/parseMentionUrl";
import { isInternalUrl } from "@shared/utils/urls";
@@ -7,7 +8,7 @@ import { NotFoundError, ValidationError } from "@server/errors";
import auth from "@server/middlewares/authentication";
import { rateLimiter } from "@server/middlewares/rateLimiter";
import validate from "@server/middlewares/validate";
import { Document, User } from "@server/models";
import { Document, Share, Team, User } from "@server/models";
import { authorize } from "@server/policies";
import { presentDocument, presentMention } from "@server/presenters/unfurls";
import presentUnfurl from "@server/presenters/unfurls/unfurl";
@@ -84,4 +85,63 @@ router.post(
}
);
router.post(
"urls.validateCustomDomain",
rateLimiter(RateLimiterStrategy.OneHundredPerHour),
auth(),
validate(T.UrlsCheckCnameSchema),
async (ctx: APIContext<T.UrlsCheckCnameReq>) => {
const { hostname } = ctx.input.body;
const [team, share] = await Promise.all([
Team.findOne({
where: {
domain: hostname,
},
}),
Share.findOne({
where: {
domain: hostname,
},
}),
]);
if (team || share) {
throw ValidationError("Domain is already in use");
}
let addresses;
try {
addresses = await new Promise<string[]>((resolve, reject) => {
dns.resolveCname(hostname, (err, addresses) => {
if (err) {
return reject(err);
}
return resolve(addresses);
});
});
} catch (err) {
if (err.code === "ENOTFOUND") {
throw NotFoundError("No CNAME record found");
}
throw ValidationError("Invalid domain");
}
if (addresses.length === 0) {
throw ValidationError("No CNAME record found");
}
const address = addresses[0];
const likelyValid = address.endsWith(getBaseDomain());
if (!likelyValid) {
throw ValidationError("CNAME is not configured correctly");
}
ctx.body = {
success: true,
};
}
);
export default router;