| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- const test = require('node:test');
- const assert = require('node:assert/strict');
- const fs = require('node:fs');
- function loadModules(fetchImpl) {
- const cpaSource = fs.readFileSync('background/cpa-api.js', 'utf8');
- const stepSource = fs.readFileSync('background/steps/sync-cpa-session.js', 'utf8');
- const scope = {};
- new Function('self', 'fetch', `${cpaSource}\n${stepSource}; return self;`)(scope, fetchImpl);
- return scope;
- }
- function base64UrlJson(value) {
- return Buffer.from(JSON.stringify(value), 'utf8')
- .toString('base64')
- .replace(/\+/g, '-')
- .replace(/\//g, '_')
- .replace(/=+$/g, '');
- }
- function jwt(payload) {
- return `${base64UrlJson({ alg: 'RS256', typ: 'JWT' })}.${base64UrlJson(payload)}.signature`;
- }
- test('step 10 reads ChatGPT session and imports CPA auth JSON', async () => {
- const accessToken = jwt({
- exp: 1893456000,
- 'https://api.openai.com/auth': {
- chatgpt_account_id: 'acct_step10',
- chatgpt_plan_type: 'plus',
- },
- 'https://api.openai.com/profile': {
- email: 'step10@example.com',
- },
- });
- const fetchCalls = [];
- const fetchImpl = async (url, options = {}) => {
- fetchCalls.push({ url, options });
- if (url === 'https://chatgpt.com/api/auth/session') {
- return {
- ok: true,
- status: 200,
- text: async () => JSON.stringify({
- accessToken,
- user: { email: 'step10@example.com' },
- }),
- };
- }
- if (url === 'https://cpa.example.com/v0/management/auth-files?name=codex-step10%40example.com-plus.json') {
- return {
- ok: true,
- status: 200,
- json: async () => ({ ok: true }),
- };
- }
- throw new Error(`unexpected fetch: ${url}`);
- };
- const scope = loadModules(fetchImpl);
- const events = {
- completed: null,
- logs: [],
- };
- const executor = scope.MultiPageBackgroundCpaSessionSync.createCpaSessionSyncExecutor({
- addLog: async (message, level = 'info') => events.logs.push({ message, level }),
- completeStepFromBackground: async (step, payload) => {
- events.completed = { step, payload };
- },
- createCpaApi: scope.MultiPageBackgroundCpaApi.createCpaApi,
- fetchImpl,
- getPanelMode: (state) => state.panelMode || 'cpa',
- });
- await executor.executeStep10({
- panelMode: 'cpa',
- vpsUrl: 'https://cpa.example.com/management.html#/oauth',
- vpsPassword: 'secret',
- });
- assert.equal(events.completed.step, 10);
- assert.deepEqual(events.completed.payload, {
- verifiedStatus: 'CPA 会话导入完成:step10@example.com',
- cpaImportedFileName: 'codex-step10@example.com-plus.json',
- cpaImportedEmail: 'step10@example.com',
- });
- assert.equal(fetchCalls.length, 2);
- assert.equal(fetchCalls[0].url, 'https://chatgpt.com/api/auth/session');
- assert.equal(fetchCalls[1].options.headers.Authorization, 'Bearer secret');
- assert.equal(JSON.parse(fetchCalls[1].options.body).access_token, accessToken);
- });
- test('step 10 skips CPA sync in sub2api mode', async () => {
- const scope = loadModules(async () => {
- throw new Error('fetch should not be called when sub2api is selected');
- });
- const events = {
- completed: null,
- logs: [],
- };
- const executor = scope.MultiPageBackgroundCpaSessionSync.createCpaSessionSyncExecutor({
- addLog: async (message, level = 'info') => events.logs.push({ message, level }),
- completeStepFromBackground: async (step, payload) => {
- events.completed = { step, payload };
- },
- createCpaApi: scope.MultiPageBackgroundCpaApi.createCpaApi,
- getPanelMode: () => 'sub2api',
- });
- await executor.executeStep10({ panelMode: 'sub2api' });
- assert.deepEqual(events.completed, {
- step: 10,
- payload: {
- cpaSyncSkipped: true,
- cpaSyncSkipReason: 'sub2api-mode',
- },
- });
- assert.equal(events.logs.some((entry) => /跳过 CPA session 同步/.test(entry.message)), true);
- });
|