Spaces:
Sleeping
Sleeping
| 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(); | |
| } | |
| } | |