import { timingSafeEqual } from "node:crypto"; import { NextResponse } from "next/server"; import { hasConvexUrl } from "@/lib/convex-config"; function readBearerToken(request: Request) { const authHeader = request.headers.get("authorization") || ""; if (!authHeader.toLowerCase().startsWith("bearer ")) { return ""; } return authHeader.slice("bearer ".length).trim(); } function tokensMatch(expected: string, provided: string) { const expectedBuffer = Buffer.from(expected); const providedBuffer = Buffer.from(provided); if (expectedBuffer.length !== providedBuffer.length) { return false; } return timingSafeEqual(expectedBuffer, providedBuffer); } export function getPhoneAgentInternalToken() { return String(process.env.PHONE_AGENT_INTERNAL_TOKEN || "").trim(); } export async function requirePhoneAgentInternalAuth(request: Request) { if (!hasConvexUrl()) { return NextResponse.json( { error: "Convex is not configured for phone call sync" }, { status: 503 }, ); } const configuredToken = getPhoneAgentInternalToken(); if (!configuredToken) { return NextResponse.json( { error: "Phone call sync token is not configured" }, { status: 503 }, ); } const providedToken = readBearerToken(request); if (!providedToken || !tokensMatch(configuredToken, providedToken)) { return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } return null; }