fix: Cookie parsing for JSON format in upload and generate APIs
Some checks are pending
CI / build (18.x) (push) Waiting to run
CI / build (20.x) (push) Waiting to run

- Fixed upload route to properly trim and parse JSON-formatted cookies
- Added same cookie normalization logic to generate route
- Handles pretty-printed JSON with leading newlines from Cookie-Editor export
This commit is contained in:
Khoa.vo 2026-01-05 15:01:24 +07:00
parent 6209665659
commit 2a8125f6d7
3 changed files with 103 additions and 4 deletions

View file

@ -12,12 +12,28 @@ export async function POST(req: NextRequest) {
// Use cookies provided in request or fallback to server-side logic if implemented later // Use cookies provided in request or fallback to server-side logic if implemented later
// For now, we expect the frontend to pass the 'whisk_cookies' it has stored. // For now, we expect the frontend to pass the 'whisk_cookies' it has stored.
const cookieString = clientCookies || req.cookies.get('whisk_cookies')?.value; let cookieString = clientCookies || req.cookies.get('whisk_cookies')?.value;
if (!cookieString) { if (!cookieString) {
return NextResponse.json({ error: "Whisk cookies not found. Please configure settings." }, { status: 401 }); return NextResponse.json({ error: "Whisk cookies not found. Please configure settings." }, { status: 401 });
} }
// Normalize cookies: handle JSON-formatted cookies (from Cookie-Editor export)
const trimmedCookies = cookieString.trim();
if (trimmedCookies.startsWith('[') || trimmedCookies.startsWith('{')) {
try {
const cookieArray = JSON.parse(trimmedCookies);
if (Array.isArray(cookieArray)) {
cookieString = cookieArray
.map((c: any) => `${c.name}=${c.value}`)
.join('; ');
console.log(`[Generate] Parsed ${cookieArray.length} cookies from JSON.`);
}
} catch (e) {
console.warn("[Generate] Failed to parse cookie JSON:", e);
}
}
const client = new WhiskClient(cookieString); const client = new WhiskClient(cookieString);
// Generate images in parallel if imageCount > 1 // Generate images in parallel if imageCount > 1

View file

@ -26,10 +26,12 @@ export async function POST(req: Request) {
let parsedCookies = ""; let parsedCookies = "";
// Auto-fix: Handle JSON array (e.g. from Cookie-Editor export) // Auto-fix: Handle JSON array (e.g. from Cookie-Editor export)
if (validCookies.startsWith('[') || validCookies.startsWith('{')) { // Check for JSON after trimming (handles pretty-printed JSON with leading newlines)
const trimmedForCheck = validCookies.trim();
if (trimmedForCheck.startsWith('[') || trimmedForCheck.startsWith('{')) {
isJson = true; isJson = true;
try { try {
const cookieArray = JSON.parse(validCookies); const cookieArray = JSON.parse(trimmedForCheck);
if (Array.isArray(cookieArray)) { if (Array.isArray(cookieArray)) {
// Convert ALL cookies to a string, not just 1PSID // Convert ALL cookies to a string, not just 1PSID
@ -71,7 +73,8 @@ export async function POST(req: Request) {
} }
console.log(`[API] Uploading reference image (${category}, ${mimeType})...`); console.log(`[API] Uploading reference image (${category}, ${mimeType})...`);
console.log(`[API] Using cookies (first 50 chars): ${validCookies.substring(0, 50)}...`); console.log(`[API] Using cookies (first 100 chars): ${validCookies.substring(0, 100)}...`);
console.log(`[API] Cookie was JSON: ${isJson}, parsed cookies count: ${parsedCookies.split(';').length}`);
const client = new WhiskClient(validCookies); const client = new WhiskClient(validCookies);

View file

@ -0,0 +1,80 @@
import { WhiskClient } from '../lib/whisk-client';
// User-provided Whisk cookies
const WHISK_COOKIES = JSON.stringify([
{
"domain": "labs.google",
"hostOnly": true,
"httpOnly": true,
"name": "__Host-next-auth.csrf-token",
"path": "/",
"sameSite": "lax",
"secure": true,
"session": true,
"storeId": null,
"value": "7485620ca6c96e35b3949dc2ddc79dcf4419285e50534bdba72575e4901324a1%7C1a14ffc355e181cb4ef8c01a6446d33c583ca940be54c20e157c1851a3313e8f"
},
{
"domain": "labs.google",
"hostOnly": true,
"httpOnly": true,
"name": "__Secure-next-auth.callback-url",
"path": "/",
"sameSite": "lax",
"secure": true,
"session": true,
"storeId": null,
"value": "https%3A%2F%2Flabs.google%2Ffx%2Ftools%2Fmusic-fx%2Funsupported-country"
},
{
"domain": "labs.google",
"expirationDate": 1770190006.527353,
"hostOnly": true,
"httpOnly": true,
"name": "__Secure-next-auth.session-token",
"path": "/",
"sameSite": "lax",
"secure": true,
"session": false,
"storeId": null,
"value": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..sNTX3pzNatN34d3B.CNKFzpp_4ZYRyVnB2zyVa_4kGxtHgcIgYxD_zuV1oNW5bjQteCUm83gNr3o0kM4pVYk8zkrfeWvJj9D6JbH8pu2ylhtRlI8__iGhL6ZrS2iRZ8Ia1ojVMrXnFMttv6J6PVZEsPTBaI__O4Fqe4sVp8GIkBya5PTq_hmaYFKgAao4jplGrl7f63_IYzWwUmNs5BOwQtIxfJiTulm3333jVaeazfnq3jSC93aPiPM5z-XTtV2vE1gxJqNbAyJXgli_i-aoIUMB9d-sy7YWLAdwSPZoANp8tuXjd62AaZ74IJ-9lnKUoasBnU2oogDPcArIgD5W1Bacf-Snb131_uQ_uidmvGNmk6-JfFRpfjAVTL7c_S00IDowJzODQOJ2kLVYy8hFgGfuxDGFfOCBLztrTCTmmlWB_yGHjmUSr8mrI2_fn6cDOiAEoZ75M70NU-v3oJB14tr1h3r4jmUAVwbT7Knh2fCjpv-DT1yk3kzqPHpLrdL4cx3liq0mYoszZ8W5bM0IJiKueLVXulIEpHxUkKzDglMEud0ABGWFfWO4UfZnCc8XJXRf1aLIuA3q_DgvlnCH2Wo5go7OdPR6HFKqzOASGoxpm6f1qQMhiDzFn5-Fs_wyenGauJfwap9qwINZxQWSA1_5jl6VSRbFcHMQghB0tJiMhIwV9XPlENafIszvQAVIhpA9ACniG_Mxb8wBWuYFtnphlK4w3ehTxus15G8P0CtaPWJn4I40DyHZnZqulDU2y05ozW-D66LkIGFuUlO-PpHTPQvh2hlL5fq6ac92iN_eZuSLI3qPNCv11PHRhXzDj87S3J2fRc4dzKAN6PUooSZTSQSYTJa5MJVhP1wnRdfLoEfLJ7oCt7XnLNqIEas7J3hi55s3oATuT93fi-edjF7gnZaM4zEKQKqxGKFbOmuiglV7eFADRxkGz7vEZ-kjxvPgEtO4jVCxE-SJ_s1e067bpkYVy9IHZXhJOUO61bCQykIwjlZckP2Fz2VF1W6HYnc.AXU0oelImaOeGzkoH7OxRg"
}
]);
// Use a small test image (1x1 red pixel PNG)
const TINY_TEST_IMAGE_BASE64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==";
async function testUpload() {
console.log("=== Whisk Upload Debug Test ===\n");
const client = new WhiskClient(WHISK_COOKIES);
try {
console.log("1. Testing Subject upload...");
const subjectId = await client.uploadReferenceImage(TINY_TEST_IMAGE_BASE64, "image/png", "subject");
console.log(` ✅ Subject upload SUCCESS: ${subjectId}`);
} catch (e: any) {
console.error(` ❌ Subject upload FAILED: ${e.message}`);
}
try {
console.log("\n2. Testing Scene upload...");
const sceneId = await client.uploadReferenceImage(TINY_TEST_IMAGE_BASE64, "image/png", "scene");
console.log(` ✅ Scene upload SUCCESS: ${sceneId}`);
} catch (e: any) {
console.error(` ❌ Scene upload FAILED: ${e.message}`);
}
try {
console.log("\n3. Testing Style upload...");
const styleId = await client.uploadReferenceImage(TINY_TEST_IMAGE_BASE64, "image/png", "style");
console.log(` ✅ Style upload SUCCESS: ${styleId}`);
} catch (e: any) {
console.error(` ❌ Style upload FAILED: ${e.message}`);
}
console.log("\n=== Test Complete ===");
}
testUpload();