Files
zeekay 60163bce2e rebrand: Papermark → Hanzo Dataroom across user-facing surfaces
108 files: README, marketing copy, page titles, meta tags, footer
text, email templates, .env.example, UI strings. URLs swapped
from papermark.com/papermark.io to dataroom.hanzo.ai.

Internal identifiers left intact per repo policy: localStorage
keys (papermark.email/papermark.name/last_papermark_login —
changing them logs users out), type field names
(papermarkUserId), internal helper symbols (PAPERMARK_HEADERS,
PapermarkSparkle component, isPapermarkUrl helper),
internal-only filenames. LLM.md retains 'Upstream: Papermark'
attribution line. Per-locale .po translations regenerate from
source on the next lingui-extract CI run.

DB migrations untouched (append-only history; rewriting them
breaks installed schemas). LICENSE stays AGPL-3.0.
2026-06-07 12:23:40 -07:00

142 lines
3.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { NextApiRequest, NextApiResponse } from "next";
import dns from "dns/promises";
import { getServerSession } from "next-auth/next";
import { validDomainRegex } from "@/lib/domains";
import { errorhandler } from "@/lib/errorHandler";
import prisma from "@/lib/prisma";
import { CustomUser } from "@/lib/types";
import { authOptions } from "../../../../auth/[...nextauth]";
type DomainValidationStatus = "invalid" | "has site" | "available";
const sanitizeDomain = (value: string) =>
value
.trim()
.toLowerCase()
.replace(/^(?:https?:\/\/)?(?:www\.)?/i, "")
.split("/")[0];
export default async function handle(
req: NextApiRequest,
res: NextApiResponse,
) {
if (req.method !== "GET") {
res.setHeader("Allow", ["GET"]);
return res.status(405).end(`Method ${req.method} Not Allowed`);
}
const session = await getServerSession(req, res, authOptions);
if (!session) {
return res.status(401).end("Unauthorized");
}
const { teamId } = req.query as { teamId: string };
const rawDomain = Array.isArray(req.query.domain)
? req.query.domain[0]
: req.query.domain;
if (!teamId || !rawDomain) {
return res.status(400).json({ status: "invalid" });
}
const userId = (session.user as CustomUser).id;
try {
const hasTeamAccess = await prisma.userTeam.findUnique({
where: {
userId_teamId: {
userId,
teamId,
},
},
});
if (!hasTeamAccess) {
return res.status(401).end("Unauthorized");
}
const sanitizedDomain = sanitizeDomain(rawDomain);
if (
!sanitizedDomain ||
!validDomainRegex.test(sanitizedDomain) ||
sanitizedDomain.includes("hanzo")
) {
return res.status(200).json({
status: "invalid" as DomainValidationStatus,
});
}
const existingDomain = await prisma.domain.findFirst({
where: {
slug: sanitizedDomain,
},
select: {
id: true,
},
});
if (existingDomain) {
return res.status(200).json({
status: "has site" as DomainValidationStatus,
});
}
const hasSite = await hasSiteConfigured(sanitizedDomain);
if (hasSite) {
return res.status(200).json({
status: "has site" as DomainValidationStatus,
});
}
return res.status(200).json({
status: "available" as DomainValidationStatus,
});
} catch (error) {
errorhandler(error, res);
}
}
async function hasSiteConfigured(domain: string): Promise<boolean> {
try {
const urls = [`https://${domain}`, `http://${domain}`];
for (const url of urls) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);
const response = await fetch(url, {
method: "HEAD",
signal: controller.signal,
redirect: "manual",
});
clearTimeout(timeoutId);
// Any response (including redirects) means a site is configured
if (response.status < 500) return true;
} catch {
// Timeout, network error, or certificate error – try next URL
continue;
}
}
const dnsPromise = dns.resolve(domain);
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error("DNS Timeout")), 3000),
);
try {
const records = (await Promise.race([
dnsPromise,
timeoutPromise,
])) as string[];
return records.length > 0;
} catch (error) {
return false;
}
} catch (error) {
return false;
}
}