mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-07 07:42:13 +03:00
Wire NextAuth session-token merge/persist on successful perplexity-web responses so rotated cookies survive in provider_connections, matching chatgpt-web behavior.
79 lines
2.7 KiB
TypeScript
79 lines
2.7 KiB
TypeScript
/**
|
|
* NextAuth session-token cookie helpers shared by web-cookie providers that
|
|
* authenticate via __Secure-next-auth.session-token (chatgpt-web, perplexity-web, …).
|
|
*
|
|
* Rotation can change the shape (unchunked → chunked or vice versa). When that
|
|
* happens, every old family member must be dropped — keeping the stale variant
|
|
* alongside the new one would send both, and depending on parser precedence the
|
|
* server could read the stale value and fail auth.
|
|
*/
|
|
export const SESSION_TOKEN_FAMILY_RE = /^__Secure-next-auth\.session-token(?:\.\d+)?$/;
|
|
|
|
/**
|
|
* Merge any rotated session-token chunks from a Set-Cookie response into the
|
|
* original cookie blob, preserving every other cookie the caller pasted
|
|
* (cf_clearance, __cf_bm, _cfuvid, …). Returns null if no rotation occurred
|
|
* or the rotated chunks match what's already there.
|
|
*/
|
|
export function mergeRefreshedCookie(
|
|
originalCookie: string,
|
|
setCookieHeader: string | null
|
|
): string | null {
|
|
if (!setCookieHeader) return null;
|
|
const matches = Array.from(
|
|
setCookieHeader.matchAll(/(__Secure-next-auth\.session-token(?:\.\d+)?)=([^;,\s]+)/g)
|
|
);
|
|
if (matches.length === 0) return null;
|
|
|
|
const refreshed = new Map<string, string>();
|
|
for (const m of matches) refreshed.set(m[1], m[2]);
|
|
|
|
let blob = originalCookie.trim();
|
|
if (/^cookie\s*:\s*/i.test(blob)) blob = blob.replace(/^cookie\s*:\s*/i, "");
|
|
|
|
// Bare value (no `=`): the original was just the session-token contents.
|
|
if (!/=/.test(blob)) {
|
|
return Array.from(refreshed, ([k, v]) => `${k}=${v}`).join("; ");
|
|
}
|
|
|
|
const pairs = blob.split(/;\s*/).filter(Boolean);
|
|
const result: string[] = [];
|
|
let mutated = false;
|
|
let droppedStale = false;
|
|
for (const pair of pairs) {
|
|
const eqIdx = pair.indexOf("=");
|
|
if (eqIdx < 0) {
|
|
result.push(pair);
|
|
continue;
|
|
}
|
|
const name = pair.slice(0, eqIdx).trim();
|
|
const value = pair.slice(eqIdx + 1);
|
|
if (SESSION_TOKEN_FAMILY_RE.test(name)) {
|
|
if (!refreshed.has(name) || refreshed.get(name) !== value) mutated = true;
|
|
droppedStale = true;
|
|
continue;
|
|
}
|
|
result.push(`${name}=${value}`);
|
|
}
|
|
for (const [name, value] of refreshed) {
|
|
result.push(`${name}=${value}`);
|
|
}
|
|
if (!droppedStale) mutated = true;
|
|
return mutated ? result.join("; ") : null;
|
|
}
|
|
|
|
/**
|
|
* Build the Cookie header value from whatever the user pasted.
|
|
*
|
|
* Accepts bare values, unchunked/chunked cookie lines, and full DevTools
|
|
* "Cookie: …" headers.
|
|
*/
|
|
export function buildSessionCookieHeader(rawInput: string): string {
|
|
let s = rawInput.trim();
|
|
if (/^cookie\s*:\s*/i.test(s)) s = s.replace(/^cookie\s*:\s*/i, "");
|
|
if (/__Secure-next-auth\.session-token(?:\.\d+)?\s*=/.test(s)) {
|
|
return s;
|
|
}
|
|
return `__Secure-next-auth.session-token=${s}`;
|
|
}
|