deep-research / src /middleware.ts
Leon4gr45's picture
Deploy app
c16e487 verified
import { NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { verifySignature } from "@/utils/signature";
const accessPassword = process.env.ACCESS_PASSWORD || "";
const DISABLED_AI_PROVIDER = process.env.NEXT_PUBLIC_DISABLED_AI_PROVIDER || "";
const DISABLED_SEARCH_PROVIDER = process.env.NEXT_PUBLIC_DISABLED_SEARCH_PROVIDER || "";
// Limit the middleware to paths starting with `/api/`
export const config = {
matcher: "/api/:path*",
};
const ERRORS = {
NO_PERMISSIONS: {
code: 403,
message: "No permissions",
status: "FORBIDDEN",
},
};
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
const requestId = Math.random().toString(36).substring(7);
try {
// Skip authorization for non-sensitive API routes
if (!pathname.startsWith("/api/ai") && !pathname.startsWith("/api/search") && !pathname.startsWith("/api/sse") && !pathname.startsWith("/api/mcp") && !pathname.startsWith("/api/crawler")) {
return NextResponse.next();
}
console.log(`[${requestId}] [Middleware] Incoming: ${request.method} ${pathname}`);
const isAuthorized = (authStr: string) => {
if (!accessPassword) return { ok: true, msg: "No password set" };
if (!authStr) {
return { ok: false, msg: "Missing authorization header" };
}
const token = authStr.startsWith("Bearer ") ? authStr.substring(7) : authStr;
const verified = verifySignature(token, accessPassword, Date.now());
return { ok: verified, msg: verified ? "Verified" : "Invalid signature" };
};
// 1. Check AI Provider restrictions
if (pathname.startsWith("/api/ai")) {
const provider = pathname.split("/")[3];
const disabledAIProviders = DISABLED_AI_PROVIDER ? DISABLED_AI_PROVIDER.split(",") : [];
const authHeader = request.headers.get("Authorization") ||
request.headers.get("authorization") ||
request.headers.get("x-goog-api-key") ||
request.headers.get("x-api-key") ||
request.headers.get("api-key") || "";
console.log(`[${requestId}] [Middleware] [AI] Auth header present: ${!!authHeader}, length: ${authHeader?.length || 0}, start: ${authHeader ? authHeader.substring(0, 10) + "..." : "none"}`);
const auth = isAuthorized(authHeader);
if (!auth.ok || disabledAIProviders.includes(provider)) {
console.warn(`[${requestId}] [Middleware] [AI] BLOCKED: provider=${provider}, auth=${auth.msg}`);
return NextResponse.json({ error: ERRORS.NO_PERMISSIONS }, { status: 403 });
}
}
// 2. Check Search Provider restrictions
if (pathname.startsWith("/api/search")) {
const provider = pathname.split("/")[3];
const disabledSearchProviders = DISABLED_SEARCH_PROVIDER ? DISABLED_SEARCH_PROVIDER.split(",") : [];
const authHeader = request.headers.get("Authorization") || request.headers.get("authorization") || "";
const auth = isAuthorized(authHeader);
if (!auth.ok || disabledSearchProviders.includes(provider)) {
console.warn(`[${requestId}] [Middleware] [Search] BLOCKED: provider=${provider}, auth=${auth.msg}`);
return NextResponse.json({ error: ERRORS.NO_PERMISSIONS }, { status: 403 });
}
}
// 3. Check SSE/MCP/Crawler restrictions
if (pathname.startsWith("/api/sse") || pathname.startsWith("/api/mcp") || pathname.startsWith("/api/crawler")) {
let authHeader = request.headers.get("Authorization") || request.headers.get("authorization") || "";
if (authHeader.startsWith("Bearer ")) authHeader = authHeader.substring(7);
else if (request.method === "GET") authHeader = request.nextUrl.searchParams.get("password") || "";
if (accessPassword && authHeader !== accessPassword) {
console.warn(`[${requestId}] [Middleware] [Special] BLOCKED: path=${pathname}, auth=Password mismatch`);
return NextResponse.json({ error: ERRORS.NO_PERMISSIONS }, { status: 403 });
}
}
console.log(`[${requestId}] [Middleware] PASS: ${pathname}`);
return NextResponse.next();
} catch (err) {
console.error(`[${requestId}] [Middleware] CRASH:`, err);
return NextResponse.next();
}
}