64cf9c330d
The encrypted .infiplot format (AES-256-GCM via GALLERY_SECRET) provided no meaningful security — the payload is AI-generated story content with no credentials or PII, and the project is open source. Replace with plaintext + SHA-256 integrity check (format v2). Story share is now always enabled without requiring a server secret. - galleryCrypto.ts: AES-256-GCM → plaintext + SHA-256 hash; remove secret param - 4 API routes: remove GALLERY_SECRET guard and 503 fallback - story-unpack: forward specific error messages (v1 compat, hash mismatch) - gallery/page.tsx: remove stale AES-GCM comment - AGENTS.md: document gallery-pack/gallery-unpack routes - .env.example, wrangler.jsonc: remove GALLERY_SECRET references Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
31 lines
801 B
TypeScript
31 lines
801 B
TypeScript
import { unpackDoc } from "@/lib/galleryCrypto";
|
|
|
|
export const runtime = "nodejs";
|
|
|
|
const MAX_FILE_BYTES = 13_000_000;
|
|
|
|
export async function POST(req: Request): Promise<Response> {
|
|
let ab: ArrayBuffer;
|
|
try {
|
|
ab = await req.arrayBuffer();
|
|
} catch {
|
|
return Response.json({ error: "Bad request body" }, { status: 400 });
|
|
}
|
|
if (ab.byteLength > MAX_FILE_BYTES) {
|
|
return Response.json({ error: "文件太大" }, { status: 413 });
|
|
}
|
|
if (ab.byteLength === 0) {
|
|
return Response.json({ error: "文件为空" }, { status: 400 });
|
|
}
|
|
|
|
try {
|
|
const docStr = await unpackDoc(new Uint8Array(ab));
|
|
return Response.json({ docStr });
|
|
} catch (e) {
|
|
return Response.json(
|
|
{ error: e instanceof Error ? e.message : "解包失败" },
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
}
|