diff --git a/functions/api/short-links/new.ts b/functions/api/short-links/new.ts index 3c434f6..3a2fc6e 100644 --- a/functions/api/short-links/new.ts +++ b/functions/api/short-links/new.ts @@ -18,11 +18,66 @@ export async function onRequestPost(context: RequestContext) { 400, ); - const url = new URL(destination); + let url: URL; + + try { + url = new URL(destination); + } catch { + return jsonError("Invalid URL", 400); + } if (!["http:", "https:"].includes(url.protocol)) return jsonError("Invalid URL", 400); + const dnsCheckPromises = await Promise.allSettled([ + fetch(`https://cloudflare-dns.com/dns-query?name=${url.hostname}&type=a`, { + headers: { + accept: "application/dns-json", + }, + }), + fetch( + `https://cloudflare-dns.com/dns-query?name=${url.hostname}&type=aaaa`, + { + headers: { + accept: "application/dns-json", + }, + }, + ), + ]); + + const fulfilledResponses = dnsCheckPromises + .filter((p) => p.status === "fulfilled") + .map((p) => p.value); + + if (!fulfilledResponses.length) + return jsonError("Failed to validate hostname", 500); + + let hasAnyValidRecord = false; + + for (const response of fulfilledResponses) { + if (!response.ok) continue; + + let body: { Status: number; [k: string]: any }; + + try { + body = await response.json(); + } catch { + continue; + } + + // A DNS record exists + if (body.Status === 0) { + hasAnyValidRecord = true; + break; + } + } + + if (!hasAnyValidRecord) + return jsonError( + "This URL appears to not exist, please check and try again.", + 400, + ); + await context.env.D1.prepare( "INSERT INTO short_links (created_at, destination, path, user) VALUES (?, ?, ?, ?);", )