'use strict'; const assert = require('assert'); const { _private } = require('../src/services/openai_oauth_service'); function jwt(payload) { const header = Buffer.from(JSON.stringify({ alg: 'none' })).toString('base64url'); const body = Buffer.from(JSON.stringify(payload)).toString('base64url'); return `${header}.${body}.signature`; } function createMockPage(responses) { let currentUrl = 'https://auth.openai.com/oauth/token'; const requests = []; return { requests, url: () => currentUrl, goto: async url => { currentUrl = url; return null; }, evaluate: async (_fn, payload) => { requests.push(payload); const response = responses.find(item => ( typeof item.match === 'string' ? payload.targetUrl.startsWith(item.match) : item.match(payload) )); if (!response) throw new Error(`未配置模拟响应:${payload.targetUrl}`); return typeof response.reply === 'function' ? response.reply(payload) : response.reply; }, }; } (async () => { const selected = _private.selectChatGPTAccountInfo({ accounts: { expired: { account: { account_id: 'expired', plan_type: 'plus', is_default: true }, entitlement: { expires_at: '2020-01-01T00:00:00.000Z' }, }, free: { account: { account_id: 'free', plan_type: 'free' }, entitlement: { expires_at: '2099-01-01T00:00:00.000Z' }, }, paid: { account: { account_id: 'paid', plan_type: 'team' }, entitlement: { expires_at: '2099-06-01T00:00:00.000Z' }, }, }, }, 'paid', Date.parse('2026-01-01T00:00:00.000Z')); assert.strictEqual(selected.account_id, 'paid'); assert.strictEqual(selected.plan_type, 'team'); const oldRefreshToken = 'refresh-old'; const refreshedAccessToken = jwt({ exp: Math.floor(Date.now() / 1000) + 3600, email: 'user@gmail.com', 'https://api.openai.com/auth': { user_id: 'user-1', chatgpt_account_id: 'account-1', }, }); const page = createMockPage([ { match: 'https://auth.openai.com/oauth/token', reply: { ok: true, status: 200, data: { access_token: refreshedAccessToken, id_token: jwt({ sub: 'user-1', email: 'user@gmail.com' }), token_type: 'Bearer', expires_in: 3600, }, }, }, { match: _private.CHATGPT_ACCOUNTS_CHECK_URL, reply: { ok: true, status: 200, data: { accounts: { 'account-1': { account: { account_id: 'account-1', email: 'user@gmail.com', plan_type: 'plus', is_default: true, }, entitlement: { expires_at: '2027-01-01T00:00:00.000Z' }, }, }, }, }, }, { match: _private.CHATGPT_USAGE_URL, reply: { ok: true, status: 200, data: { account_id: 'account-1', email: 'user@gmail.com', plan_type: 'plus', rate_limit: { allowed: true, limit_reached: false, primary_window: { used_percent: 25, reset_at: 1800000000 }, }, unrelated_large_field: 'must not be stored', }, }, }, { match: _private.CHATGPT_SUBSCRIPTIONS_URL, reply: { ok: true, status: 200, data: { id: 'sub-1', plan_type: 'plus', active_until: '2027-02-01T00:00:00.000Z', will_renew: true, }, }, }, ]); const authJson = { access_token: jwt({ exp: Math.floor(Date.now() / 1000) - 3600, email: 'user@gmail.com', 'https://api.openai.com/auth': { chatgpt_account_id: 'account-1' }, }), refresh_token: oldRefreshToken, id_token: jwt({ sub: 'user-1', email: 'user@gmail.com' }), expires_at: '2020-01-01T00:00:00.000Z', tokens: { refresh_token: oldRefreshToken, account_id: 'account-1' }, }; const logs = []; const enriched = await _private.enrichOpenAIAuthJson(page, authJson, message => logs.push(message)); assert.strictEqual(enriched.access_token, refreshedAccessToken); assert.strictEqual(enriched.refresh_token, oldRefreshToken, '刷新接口不返回新 RT 时必须保留旧 RT'); assert.strictEqual(enriched.tokens.refresh_token, oldRefreshToken); assert.strictEqual(enriched.chatgpt_account_id, 'account-1'); assert.strictEqual(enriched.plan_type, 'plus'); assert.strictEqual(enriched.subscription_expires_at, '2027-02-01T00:00:00.000Z'); assert.strictEqual(enriched.usage.rate_limit.primary_window.used_percent, 25); assert.strictEqual(enriched.usage.unrelated_large_field, undefined); assert.strictEqual(enriched.subscription.will_renew, true); assert.ok(enriched.usage_fetched_at); assert.ok(enriched.account_info_fetched_at); assert.ok(logs.some(message => message.includes('正在使用 refresh_token 刷新'))); assert.ok(logs.some(message => message.includes('主窗口已用 25%'))); const refreshRequest = page.requests.find(item => item.targetUrl === 'https://auth.openai.com/oauth/token'); assert.strictEqual(refreshRequest.form.grant_type, 'refresh_token'); assert.strictEqual(refreshRequest.form.refresh_token, oldRefreshToken); const usageRequest = page.requests.find(item => item.targetUrl === _private.CHATGPT_USAGE_URL); assert.strictEqual(usageRequest.headers['ChatGPT-Account-Id'], 'account-1'); assert.strictEqual(usageRequest.headers['OpenAI-Beta'], 'codex-1'); const failingPage = createMockPage([]); failingPage.goto = async url => { throw new Error(`无法访问 ${url}`); }; const original = { access_token: 'still-save-me', refresh_token: 'refresh-1' }; const fallback = await _private.enrichOpenAIAuthJson(failingPage, original, () => {}); assert.strictEqual(fallback.access_token, original.access_token, '附加查询失败不能影响 Token 保存'); console.log('openai_auth_account_details.test.js passed'); })().catch(error => { console.error(error); process.exitCode = 1; });