158 lines
5.6 KiB
JavaScript
158 lines
5.6 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const axios = require('axios');
|
|
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`;
|
|
}
|
|
|
|
(async () => {
|
|
const legacy = _private.parseOpenAIProxyDescriptor('proxy.example.com:1080@user:pass');
|
|
assert.deepStrictEqual(legacy.protocols, ['socks5', 'http']);
|
|
assert.strictEqual(legacy.host, 'proxy.example.com');
|
|
assert.strictEqual(legacy.username, 'user');
|
|
|
|
const explicitHttp = _private.parseOpenAIProxyDescriptor('http://user:pass@proxy.example.com:8080');
|
|
assert.deepStrictEqual(explicitHttp.protocols, ['http']);
|
|
assert.match(_private.buildOpenAIProxyUrl(explicitHttp, 'http'), /^http:\/\/user:pass@/);
|
|
|
|
const originalRequest = axios.request;
|
|
const calls = [];
|
|
axios.request = async config => {
|
|
const agentType = config.httpsAgent && config.httpsAgent.constructor.name;
|
|
calls.push({ url: config.url, agentType });
|
|
if (config.url === _private.CHATGPT_USAGE_URL) {
|
|
return {
|
|
status: 200,
|
|
data: JSON.stringify({
|
|
account_id: 'account-1',
|
|
plan_type: 'pro',
|
|
rate_limit: { primary_window: { used_percent: 42 } },
|
|
}),
|
|
};
|
|
}
|
|
return { status: 403, data: JSON.stringify({ detail: 'blocked in mock' }) };
|
|
};
|
|
|
|
try {
|
|
const logs = [];
|
|
const authJson = {
|
|
access_token: jwt({
|
|
exp: Math.floor(Date.now() / 1000) + 3600,
|
|
'https://api.openai.com/auth': {
|
|
chatgpt_account_id: 'account-1',
|
|
chatgpt_plan_type: 'pro',
|
|
},
|
|
}),
|
|
plan_type: 'pro',
|
|
tokens: { account_id: 'account-1' },
|
|
};
|
|
const result = await _private.queryAndEnrichOpenAIAuthJsonDirect(
|
|
authJson,
|
|
'proxy.example.com:1080:user:pass',
|
|
message => logs.push(message),
|
|
);
|
|
assert.strictEqual(result.success, true);
|
|
assert.strictEqual(result.authJson.plan_type, 'pro');
|
|
assert.strictEqual(result.authJson.usage.rate_limit.primary_window.used_percent, 42);
|
|
assert(calls.length >= 3);
|
|
assert(calls.every(call => call.agentType === 'SocksProxyAgent'));
|
|
assert(logs.some(message => message.includes('后台接口连接方式:HTTP经SOCKS5隧道')));
|
|
|
|
calls.length = 0;
|
|
const directLogs = [];
|
|
const directResult = await _private.queryAndEnrichOpenAIAuthJsonDirect(
|
|
authJson,
|
|
'',
|
|
message => directLogs.push(message),
|
|
{ connectionMode: 'direct' },
|
|
);
|
|
assert.strictEqual(directResult.success, true);
|
|
assert(calls.length >= 3);
|
|
assert(calls.every(call => call.agentType === undefined));
|
|
assert(directLogs.some(message => message.includes('后台接口连接方式:直连')));
|
|
|
|
const oldAccessToken = jwt({
|
|
exp: Math.floor(Date.now() / 1000) + 3600,
|
|
email: 'fallback.user@gmail.com',
|
|
'https://api.openai.com/auth': { chatgpt_account_id: 'account-fallback' },
|
|
});
|
|
const newAccessToken = jwt({
|
|
exp: Math.floor(Date.now() / 1000) + 7200,
|
|
email: 'fallback.user@gmail.com',
|
|
'https://api.openai.com/auth': { chatgpt_account_id: 'account-fallback' },
|
|
});
|
|
const fallbackCalls = [];
|
|
axios.request = async config => {
|
|
fallbackCalls.push(config);
|
|
if (/\/api\/auth\/session\?refresh=true/.test(config.url)) {
|
|
return {
|
|
status: 200,
|
|
data: JSON.stringify({
|
|
user: { email: 'fallbackuser@gmail.com' },
|
|
accessToken: newAccessToken,
|
|
expires: new Date(Date.now() + 7200000).toISOString(),
|
|
}),
|
|
};
|
|
}
|
|
if (config.headers.Authorization === `Bearer ${oldAccessToken}`) {
|
|
return { status: 401, data: JSON.stringify({ detail: 'expired' }) };
|
|
}
|
|
if (config.url === _private.CHATGPT_USAGE_URL) {
|
|
return {
|
|
status: 200,
|
|
data: JSON.stringify({
|
|
account_id: 'account-fallback',
|
|
plan_type: 'plus',
|
|
rate_limit: { primary_window: { used_percent: 12 } },
|
|
}),
|
|
};
|
|
}
|
|
if (/\/subscriptions\?/.test(config.url)) {
|
|
return { status: 200, data: JSON.stringify({ plan_type: 'plus' }) };
|
|
}
|
|
return {
|
|
status: 200,
|
|
data: JSON.stringify({
|
|
accounts: {
|
|
'account-fallback': {
|
|
account: { account_id: 'account-fallback', plan_type: 'plus', is_default: true },
|
|
},
|
|
},
|
|
}),
|
|
};
|
|
};
|
|
const fallbackSession = JSON.stringify({
|
|
user: { email: 'fallback.user@gmail.com' },
|
|
accessToken: oldAccessToken,
|
|
sessionToken: 'saved-session-token',
|
|
});
|
|
const fallbackResult = await _private.queryAndEnrichOpenAIAuthJsonDirect(
|
|
{},
|
|
'',
|
|
() => {},
|
|
{
|
|
connectionMode: 'direct',
|
|
sessionText: fallbackSession,
|
|
expectedEmail: 'Fallback.User@gmail.com',
|
|
},
|
|
);
|
|
assert.strictEqual(fallbackResult.success, true, '没有授权 JSON 时仍应使用 Session 完成查询');
|
|
assert.strictEqual(fallbackResult.authJson.access_token, newAccessToken);
|
|
assert.strictEqual(JSON.parse(fallbackResult.sessionText).accessToken, newAccessToken);
|
|
assert.strictEqual(JSON.parse(fallbackResult.sessionText).sessionToken, 'saved-session-token');
|
|
assert(fallbackCalls.some(call => /\/api\/auth\/session\?refresh=true/.test(call.url)));
|
|
} finally {
|
|
axios.request = originalRequest;
|
|
}
|
|
|
|
console.log('openai_plan_proxy_request.test.js: PASS');
|
|
})().catch(error => {
|
|
console.error(error);
|
|
process.exitCode = 1;
|
|
});
|