Spaces:
Sleeping
Sleeping
| import { NextResponse } from "next/server"; | |
| import type { NextRequest } from "next/server"; | |
| /** | |
| * Optional basic-auth gate for public deployments. If STUDIO_AUTH_USER and | |
| * STUDIO_AUTH_PASS are set, every request must carry matching Basic credentials; | |
| * if they're unset, the app is open (local / private-network use). | |
| * | |
| * Studio spawns paid Claude calls and runs a pipeline, so DO set these when the | |
| * app is reachable from the public internet. The browser attaches the cached | |
| * Basic credentials to fetch and EventSource (SSE) automatically after sign-in. | |
| */ | |
| export const config = { | |
| // Run on everything except Next's static assets and the favicon. | |
| matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"], | |
| }; | |
| export function proxy(request: NextRequest) { | |
| const user = process.env.STUDIO_AUTH_USER; | |
| const pass = process.env.STUDIO_AUTH_PASS; | |
| if (!user || !pass) return NextResponse.next(); | |
| const header = request.headers.get("authorization") ?? ""; | |
| const [scheme, encoded] = header.split(" "); | |
| if (scheme === "Basic" && encoded) { | |
| let decoded = ""; | |
| try { | |
| decoded = atob(encoded); | |
| } catch { | |
| decoded = ""; | |
| } | |
| const sep = decoded.indexOf(":"); | |
| if (sep !== -1) { | |
| const u = decoded.slice(0, sep); | |
| const p = decoded.slice(sep + 1); | |
| if (u === user && p === pass) return NextResponse.next(); | |
| } | |
| } | |
| return new NextResponse("Authentication required", { | |
| status: 401, | |
| headers: { "WWW-Authenticate": 'Basic realm="Seqcolyte Studio"' }, | |
| }); | |
| } | |