mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
119 lines
4.7 KiB
TypeScript
119 lines
4.7 KiB
TypeScript
// Unit tests for the Codex session-JSON normalizer (#6636).
|
|
//
|
|
// Reproduces the bug: pasting the full JSON object copied from
|
|
// `https://chatgpt.com/api/auth/session` (`{user, accessToken, expires}`)
|
|
// into the Codex OAuth modal used to fall through to the OAuth-code parser
|
|
// and error out — only a bare JWT (`/^eyJ/`) was recognized. These tests
|
|
// exercise the pure normalizer in isolation (no DB, no fetch).
|
|
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import {
|
|
looksLikeCodexSessionJson,
|
|
parseCodexSessionJson,
|
|
} from "../../src/lib/oauth/utils/codexSessionImport.ts";
|
|
|
|
function b64url(obj: unknown): string {
|
|
return Buffer.from(JSON.stringify(obj))
|
|
.toString("base64")
|
|
.replace(/=+$/, "")
|
|
.replace(/\+/g, "-")
|
|
.replace(/\//g, "_");
|
|
}
|
|
|
|
function makeJwt(payload: Record<string, unknown>): string {
|
|
const header = b64url({ alg: "RS256", typ: "JWT" });
|
|
const body = b64url(payload);
|
|
return `${header}.${body}.signature`;
|
|
}
|
|
|
|
test("parseCodexSessionJson: extracts accessToken from the exact chatgpt.com/api/auth/session shape", () => {
|
|
const accessToken = makeJwt({ email: "session@example.com" });
|
|
const result = parseCodexSessionJson({
|
|
user: { email: "session@example.com" },
|
|
accessToken,
|
|
expires: new Date(Date.now() + 60_000).toISOString(),
|
|
});
|
|
assert.equal(result.ok, true);
|
|
if (result.ok) {
|
|
assert.equal(result.session.accessToken, accessToken);
|
|
assert.equal(result.session.email, "session@example.com");
|
|
}
|
|
});
|
|
|
|
test("parseCodexSessionJson: accepts access_token, sessionToken, and nested tokens.access_token aliases", () => {
|
|
const jwt = makeJwt({});
|
|
const snakeCase = parseCodexSessionJson({ access_token: jwt });
|
|
assert.equal(snakeCase.ok, true);
|
|
|
|
const sessionToken = parseCodexSessionJson({ sessionToken: jwt });
|
|
assert.equal(sessionToken.ok, true);
|
|
|
|
const nested = parseCodexSessionJson({ tokens: { access_token: jwt } });
|
|
assert.equal(nested.ok, true);
|
|
if (nested.ok) assert.equal(nested.session.accessToken, jwt);
|
|
});
|
|
|
|
test("parseCodexSessionJson: rejects malformed / non-object input with a typed error, not a throw", () => {
|
|
assert.equal(parseCodexSessionJson(null).ok, false);
|
|
assert.equal(parseCodexSessionJson("just a string").ok, false);
|
|
assert.equal(parseCodexSessionJson(42).ok, false);
|
|
assert.equal(parseCodexSessionJson([]).ok, false);
|
|
|
|
const result = parseCodexSessionJson("just a string");
|
|
assert.equal(result.ok, false);
|
|
if (!result.ok) assert.match(result.error, /not a JSON object/i);
|
|
});
|
|
|
|
test("parseCodexSessionJson: rejects an object with no recognizable token field", () => {
|
|
const result = parseCodexSessionJson({ user: { email: "no-token@example.com" } });
|
|
assert.equal(result.ok, false);
|
|
if (!result.ok) assert.match(result.error, /access token/i);
|
|
});
|
|
|
|
test("parseCodexSessionJson: rejects an expired session via the top-level `expires` field", () => {
|
|
const accessToken = makeJwt({});
|
|
const result = parseCodexSessionJson({
|
|
accessToken,
|
|
expires: new Date(Date.now() - 60_000).toISOString(),
|
|
});
|
|
assert.equal(result.ok, false);
|
|
if (!result.ok) assert.match(result.error, /expired/i);
|
|
});
|
|
|
|
test("parseCodexSessionJson: rejects an expired session via the JWT `exp` claim", () => {
|
|
const pastExpSeconds = Math.floor((Date.now() - 60_000) / 1000);
|
|
const accessToken = makeJwt({ exp: pastExpSeconds });
|
|
const result = parseCodexSessionJson({ accessToken });
|
|
assert.equal(result.ok, false);
|
|
if (!result.ok) assert.match(result.error, /expired/i);
|
|
});
|
|
|
|
test("parseCodexSessionJson: accepts a non-expired session with a future JWT `exp` claim", () => {
|
|
const futureExpSeconds = Math.floor((Date.now() + 60_000) / 1000);
|
|
const accessToken = makeJwt({ exp: futureExpSeconds });
|
|
const result = parseCodexSessionJson({ accessToken });
|
|
assert.equal(result.ok, true);
|
|
});
|
|
|
|
test("parseCodexSessionJson: rejects a token field that does not look like a JWT", () => {
|
|
const result = parseCodexSessionJson({ accessToken: "not-a-jwt" });
|
|
assert.equal(result.ok, false);
|
|
if (!result.ok) assert.match(result.error, /JWT/i);
|
|
});
|
|
|
|
test("looksLikeCodexSessionJson: true for a JSON object string", () => {
|
|
assert.equal(looksLikeCodexSessionJson('{"accessToken":"eyJ.eyJ.sig"}'), true);
|
|
assert.equal(looksLikeCodexSessionJson(' {"user":{}} '), true);
|
|
});
|
|
|
|
test("looksLikeCodexSessionJson: false for a bare JWT, an OAuth callback URL, and malformed JSON", () => {
|
|
assert.equal(looksLikeCodexSessionJson("eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIn0.sig"), false);
|
|
assert.equal(
|
|
looksLikeCodexSessionJson("https://example.com/callback?code=abc&state=xyz"),
|
|
false
|
|
);
|
|
assert.equal(looksLikeCodexSessionJson("{not valid json"), false);
|
|
assert.equal(looksLikeCodexSessionJson(""), false);
|
|
});
|