import { NextResponse } from "next/server"; import { isConvexEnabled } from "@/lib/convex/enabled"; import { HttpError, requireAuthContext } from "@/lib/auth/authContext"; export const dynamic = "force-dynamic"; const base64UrlEncodeUtf8 = (input: string) => { return Buffer.from(input, "utf8") .toString("base64") .replace(/\+/g, "-") .replace(/\//g, "_") .replace(/=+$/g, ""); }; const getRequestOrigin = (request: Request) => { const xfProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim(); const xfHost = request.headers.get("x-forwarded-host")?.split(",")[0]?.trim(); const host = xfHost || request.headers.get("host") || new URL(request.url).host; const protocol = (xfProto || new URL(request.url).protocol.replace(/:$/, "")) + ":"; return `${protocol}//${host}`; }; const isLocalHostname = (hostname: string) => hostname === "127.0.0.1" || hostname === "localhost" || hostname === "host.docker.internal"; const maybeProxyForBrowser = (request: Request, rawUrl: string) => { const input = String(rawUrl || "").trim(); if (!input) return input; if (input.startsWith("/api/onlyoffice/proxy")) return input; try { const u = new URL(input); if (!isLocalHostname(u.hostname)) return input; const origin = getRequestOrigin(request); const proxy = new URL("/api/onlyoffice/proxy", origin); proxy.searchParams.set("u", base64UrlEncodeUtf8(input)); return proxy.toString(); } catch { return input; } }; export async function GET(request: Request) { if (isConvexEnabled()) { try { await requireAuthContext(); } catch (err) { if (err instanceof HttpError) { return NextResponse.json({ error: "未登录" }, { status: err.status }); } return NextResponse.json({ error: "未登录" }, { status: 401 }); } const { searchParams } = new URL(request.url); const fileUrl = searchParams.get("fileUrl"); if (!fileUrl) { return NextResponse.json({ error: "缺少 fileUrl" }, { status: 400 }); } // 说明:Convex + MinIO 模式下,这个接口目前主要用于“外链文件”走 ONLYOFFICE 的场景。 // 由于外链本身已经是可访问的 URL,这里只做最小透传。 return NextResponse.json({ signedUrl: maybeProxyForBrowser(request, fileUrl) }); } return NextResponse.json({ error: "当前仅支持 Convex 模式" }, { status: 501 }); }