diff --git a/src/lib/db.ts b/src/lib/db.ts index 9d6aff6..9a6fce0 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -120,6 +120,43 @@ export const isDomainAvailable = async (handle: string): Promise => { return rows.length === 0; }; +export const isDomainRegistered = async (domain: string) => { + const domainLower = domain.toLowerCase().trim(); + + // Check wisp.place subdomains + const wispDomain = await db` + SELECT did, domain, rkey FROM domains WHERE domain = ${domainLower} + `; + + if (wispDomain.length > 0) { + return { + registered: true, + type: 'wisp' as const, + domain: wispDomain[0].domain, + did: wispDomain[0].did, + rkey: wispDomain[0].rkey + }; + } + + // Check custom domains + const customDomain = await db` + SELECT id, domain, did, rkey, verified FROM custom_domains WHERE domain = ${domainLower} + `; + + if (customDomain.length > 0) { + return { + registered: true, + type: 'custom' as const, + domain: customDomain[0].domain, + did: customDomain[0].did, + rkey: customDomain[0].rkey, + verified: customDomain[0].verified + }; + } + + return { registered: false }; +}; + export const claimDomain = async (did: string, handle: string): Promise => { const h = handle.trim().toLowerCase(); if (!isValidHandle(h)) throw new Error('invalid_handle'); diff --git a/src/routes/domain.ts b/src/routes/domain.ts index eb5bf23..0db9cd5 100644 --- a/src/routes/domain.ts +++ b/src/routes/domain.ts @@ -6,6 +6,7 @@ import { claimDomain, getDomainByDid, isDomainAvailable, + isDomainRegistered, isValidHandle, toDomain, updateDomain, @@ -22,23 +23,20 @@ import { verifyCustomDomain } from '../lib/dns-verify' export const domainRoutes = (client: NodeOAuthClient) => new Elysia({ prefix: '/api/domain' }) - .derive(async ({ cookie }) => { - const auth = await requireAuth(client, cookie) - return { auth } - }) + // Public endpoints (no auth required) .get('/check', async ({ query }) => { try { const handle = (query.handle || "") .trim() .toLowerCase(); - + if (!isValidHandle(handle)) { return { available: false, reason: "invalid" }; } - + const available = await isDomainAvailable(handle); return { available, @@ -51,6 +49,36 @@ export const domainRoutes = (client: NodeOAuthClient) => }; } }) + .get('/registered', async ({ query, set }) => { + try { + const domain = (query.domain || "").trim().toLowerCase(); + + if (!domain) { + set.status = 400; + return { error: 'Domain parameter required' }; + } + + const result = await isDomainRegistered(domain); + + // For Caddy on-demand TLS: 200 = allow, 404 = deny + if (result.registered) { + set.status = 200; + return result; + } else { + set.status = 404; + return { registered: false }; + } + } catch (err) { + console.error("domain/registered error", err); + set.status = 500; + return { error: 'Failed to check domain' }; + } + }) + // Authenticated endpoints (require auth) + .derive(async ({ cookie }) => { + const auth = await requireAuth(client, cookie) + return { auth } + }) .post('/claim', async ({ body, auth }) => { try { const { handle } = body as { handle?: string };