diff --git a/src/app/api/internal/validate-token/route.ts b/src/app/api/internal/validate-token/route.ts new file mode 100644 index 0000000..11e3f8a --- /dev/null +++ b/src/app/api/internal/validate-token/route.ts @@ -0,0 +1,28 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { eq } from 'drizzle-orm'; +import { db } from '@/db'; +import { clients } from '@/db/schema'; + +export async function GET(request: NextRequest) { + const token = request.nextUrl.searchParams.get('token'); + + if (!token) { + return NextResponse.json({ valid: false }, { status: 400 }); + } + + try { + const rows = await db + .select({ id: clients.id }) + .from(clients) + .where(eq(clients.token, token)) + .limit(1); + + if (rows.length === 0) { + return NextResponse.json({ valid: false }, { status: 404 }); + } + + return NextResponse.json({ valid: true }, { status: 200 }); + } catch { + return NextResponse.json({ valid: false }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..9ab66ae --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,35 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export async function middleware(request: NextRequest) { + const pathname = request.nextUrl.pathname; + + // Extract token from path: /c/[token]/... + const tokenMatch = pathname.match(/^\/c\/([a-zA-Z0-9_-]+)/); + if (!tokenMatch) { + return NextResponse.rewrite(new URL('/not-found', request.url)); + } + + const token = tokenMatch[1]; + + try { + // Call internal Node.js API route — Edge middleware cannot use postgres-js directly + // postgres-js requires Node.js net/tls which are unavailable in the Edge runtime + const validateUrl = new URL( + `/api/internal/validate-token?token=${encodeURIComponent(token)}`, + request.url + ); + const res = await fetch(validateUrl.toString()); + + if (!res.ok) { + return NextResponse.rewrite(new URL('/not-found', request.url)); + } + + return NextResponse.next(); + } catch { + return NextResponse.rewrite(new URL('/not-found', request.url)); + } +} + +export const config = { + matcher: ['/c/:path*'], +}; \ No newline at end of file