Files
go_bt/tests/openai_auth_account_details.test.js
T

177 lines
6.0 KiB
JavaScript

'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;
});