Merge pull request #256 from Yoahoug/fix/codex-oauth-callback
fix: 修复 Codex OAuth 回调监听,添加自动完成流程
This commit is contained in:
commit
84c3199c4b
5 changed files with 93 additions and 2 deletions
|
|
@ -2366,6 +2366,59 @@ export async function handleCodexOAuth(currentConfig, options = {}) {
|
||||||
createdAt: Date.now()
|
createdAt: Date.now()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听回调服务器的 auth-success 事件,自动完成 OAuth 流程
|
||||||
|
server.once('auth-success', async (result) => {
|
||||||
|
try {
|
||||||
|
console.log('[Codex Auth] Received auth callback, completing OAuth flow...');
|
||||||
|
|
||||||
|
const session = global.codexOAuthSessions.get(sessionId);
|
||||||
|
if (!session) {
|
||||||
|
console.error('[Codex Auth] Session not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完成 OAuth 流程
|
||||||
|
const credentials = await auth.completeOAuthFlow(result.code, result.state, session.state, session.pkce);
|
||||||
|
|
||||||
|
// 清理会话
|
||||||
|
global.codexOAuthSessions.delete(sessionId);
|
||||||
|
|
||||||
|
// 广播认证成功事件
|
||||||
|
broadcastEvent('oauth_success', {
|
||||||
|
provider: 'openai-codex-oauth',
|
||||||
|
credPath: credentials.credPath,
|
||||||
|
relativePath: credentials.relativePath,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
email: credentials.email,
|
||||||
|
accountId: credentials.account_id
|
||||||
|
});
|
||||||
|
|
||||||
|
// 自动关联新生成的凭据到 Pools
|
||||||
|
await autoLinkProviderConfigs(CONFIG);
|
||||||
|
|
||||||
|
console.log('[Codex Auth] OAuth flow completed successfully');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Codex Auth] Failed to complete OAuth flow:', error.message);
|
||||||
|
|
||||||
|
// 广播认证失败事件
|
||||||
|
broadcastEvent('oauth_error', {
|
||||||
|
provider: 'openai-codex-oauth',
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听 auth-error 事件
|
||||||
|
server.once('auth-error', (error) => {
|
||||||
|
console.error('[Codex Auth] Auth error:', error.message);
|
||||||
|
global.codexOAuthSessions.delete(sessionId);
|
||||||
|
|
||||||
|
broadcastEvent('oauth_error', {
|
||||||
|
provider: 'openai-codex-oauth',
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// 10 分钟后自动清理会话
|
// 10 分钟后自动清理会话
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (global.codexOAuthSessions.has(sessionId)) {
|
if (global.codexOAuthSessions.has(sessionId)) {
|
||||||
|
|
@ -2386,6 +2439,7 @@ export async function handleCodexOAuth(currentConfig, options = {}) {
|
||||||
method: 'oauth2-pkce',
|
method: 'oauth2-pkce',
|
||||||
sessionId: sessionId,
|
sessionId: sessionId,
|
||||||
redirectUri: 'http://localhost:1455/auth/callback',
|
redirectUri: 'http://localhost:1455/auth/callback',
|
||||||
|
port: 1455,
|
||||||
instructions: [
|
instructions: [
|
||||||
'1. 点击下方按钮在浏览器中打开授权链接',
|
'1. 点击下方按钮在浏览器中打开授权链接',
|
||||||
'2. 使用您的 OpenAI 账户登录',
|
'2. 使用您的 OpenAI 账户登录',
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,8 @@ import {
|
||||||
loadProviders,
|
loadProviders,
|
||||||
openProviderManager,
|
openProviderManager,
|
||||||
showAuthModal,
|
showAuthModal,
|
||||||
executeGenerateAuthUrl
|
executeGenerateAuthUrl,
|
||||||
|
handleGenerateAuthUrl
|
||||||
} from './provider-manager.js';
|
} from './provider-manager.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -226,6 +227,7 @@ window.refreshProviderConfig = refreshProviderConfig;
|
||||||
window.fileUploadHandler = fileUploadHandler;
|
window.fileUploadHandler = fileUploadHandler;
|
||||||
window.showAuthModal = showAuthModal;
|
window.showAuthModal = showAuthModal;
|
||||||
window.executeGenerateAuthUrl = executeGenerateAuthUrl;
|
window.executeGenerateAuthUrl = executeGenerateAuthUrl;
|
||||||
|
window.handleGenerateAuthUrl = handleGenerateAuthUrl;
|
||||||
|
|
||||||
// 配置管理相关全局函数
|
// 配置管理相关全局函数
|
||||||
window.viewConfig = viewConfig;
|
window.viewConfig = viewConfig;
|
||||||
|
|
|
||||||
|
|
@ -1039,6 +1039,34 @@ function showAddProviderForm(providerType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Codex OAuth 只支持授权添加,不支持手动添加
|
||||||
|
if (providerType === 'openai-codex-oauth') {
|
||||||
|
const form = document.createElement('div');
|
||||||
|
form.className = 'add-provider-form';
|
||||||
|
form.innerHTML = `
|
||||||
|
<h4 data-i18n="modal.provider.addTitle"><i class="fas fa-plus"></i> 添加新提供商配置</h4>
|
||||||
|
<div class="oauth-only-notice" style="padding: 20px; background: #fef3c7; border: 1px solid #fcd34d; border-radius: 8px; margin: 15px 0;">
|
||||||
|
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;">
|
||||||
|
<i class="fas fa-info-circle" style="color: #d97706; font-size: 24px;"></i>
|
||||||
|
<strong style="color: #92400e;">Codex 仅支持 OAuth 授权添加</strong>
|
||||||
|
</div>
|
||||||
|
<p style="color: #b45309; margin: 0 0 15px 0;">
|
||||||
|
OpenAI Codex 需要通过 OAuth 授权获取访问令牌,无法手动填写凭据。请点击下方按钮进行授权。
|
||||||
|
</p>
|
||||||
|
<button class="btn btn-primary" onclick="window.handleGenerateAuthUrl && window.handleGenerateAuthUrl('openai-codex-oauth'); this.closest('.add-provider-form').remove();">
|
||||||
|
<i class="fas fa-key"></i> 开始 OAuth 授权
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-secondary" style="margin-left: 10px;" onclick="this.closest('.add-provider-form').remove()">
|
||||||
|
<i class="fas fa-times"></i> <span data-i18n="modal.provider.cancel">取消</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const providerList = modal.querySelector('.provider-list');
|
||||||
|
providerList.parentNode.insertBefore(form, providerList);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const form = document.createElement('div');
|
const form = document.createElement('div');
|
||||||
form.className = 'add-provider-form';
|
form.className = 'add-provider-form';
|
||||||
form.innerHTML = `
|
form.innerHTML = `
|
||||||
|
|
|
||||||
|
|
@ -2198,6 +2198,7 @@ export {
|
||||||
openProviderManager,
|
openProviderManager,
|
||||||
showAuthModal,
|
showAuthModal,
|
||||||
executeGenerateAuthUrl,
|
executeGenerateAuthUrl,
|
||||||
|
handleGenerateAuthUrl,
|
||||||
checkUpdate,
|
checkUpdate,
|
||||||
performUpdate
|
performUpdate
|
||||||
};
|
};
|
||||||
|
|
@ -254,6 +254,12 @@ function getProviderTypeFields(providerType) {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'openai-codex-oauth': [
|
'openai-codex-oauth': [
|
||||||
|
{
|
||||||
|
id: 'CODEX_OAUTH_CREDS_FILE_PATH',
|
||||||
|
label: isEn ? 'OAuth Credentials File Path' : 'OAuth凭据文件路径',
|
||||||
|
type: 'text',
|
||||||
|
placeholder: isEn ? 'e.g.: configs/codex/oauth_creds.json' : '例如: configs/codex/oauth_creds.json'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'CODEX_EMAIL',
|
id: 'CODEX_EMAIL',
|
||||||
label: isEn ? 'Email (Optional)' : '邮箱 (选填)',
|
label: isEn ? 'Email (Optional)' : '邮箱 (选填)',
|
||||||
|
|
@ -264,7 +270,7 @@ function getProviderTypeFields(providerType) {
|
||||||
id: 'CODEX_BASE_URL',
|
id: 'CODEX_BASE_URL',
|
||||||
label: `Codex Base URL <span class="optional-tag">${t('config.optional')}</span>`,
|
label: `Codex Base URL <span class="optional-tag">${t('config.optional')}</span>`,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
placeholder: 'https://chatgpt.com/backend-api/codex'
|
placeholder: 'https://api.openai.com/v1/codex'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue