diff --git a/src/server/__tests__/haha-openai-oauth-api.test.ts b/src/server/__tests__/haha-openai-oauth-api.test.ts index 97699c83..3a605561 100644 --- a/src/server/__tests__/haha-openai-oauth-api.test.ts +++ b/src/server/__tests__/haha-openai-oauth-api.test.ts @@ -6,8 +6,11 @@ import { describe, test, expect, beforeEach, afterEach } from 'bun:test' import * as fs from 'fs/promises' import * as path from 'path' import * as os from 'os' +import { createServer } from 'net' import { handleHahaOpenAIOAuthApi } from '../api/haha-openai-oauth.js' import { hahaOpenAIOAuthService } from '../services/hahaOpenAIOAuthService.js' +import { startServer } from '../index.js' +import { ProviderService } from '../services/providerService.js' let tmpDir: string let originalConfigDir: string | undefined @@ -44,6 +47,22 @@ function buildReq( return { req, url, segments } } +async function getFreePort(): Promise { + return await new Promise((resolve, reject) => { + const server = createServer() + server.on('error', reject) + server.listen(0, '127.0.0.1', () => { + const address = server.address() + if (!address || typeof address === 'string') { + server.close(() => reject(new Error('Failed to allocate test port'))) + return + } + const port = address.port + server.close(() => resolve(port)) + }) + }) +} + describe('POST /api/haha-openai-oauth/start', () => { beforeEach(setup) afterEach(teardown) @@ -157,3 +176,24 @@ describe('DELETE /api/haha-openai-oauth', () => { expect(await hahaOpenAIOAuthService.loadTokens()).toBeNull() }) }) + +describe('GET /auth/callback', () => { + beforeEach(setup) + afterEach(teardown) + + test('routes the OpenAI Codex redirect path to the desktop callback page', async () => { + const port = await getFreePort() + const originalServerPort = ProviderService.getServerPort() + const server = startServer(port, '127.0.0.1') + try { + const res = await fetch(`http://127.0.0.1:${port}/auth/callback`) + expect(res.status).toBe(200) + const html = await res.text() + expect(html).toContain('OpenAI Login Failed') + expect(html).toContain('Missing code or state parameter') + } finally { + server.stop(true) + ProviderService.setServerPort(originalServerPort) + } + }) +}) diff --git a/src/server/api/haha-openai-oauth.ts b/src/server/api/haha-openai-oauth.ts index 501e1a31..21f01c2b 100644 --- a/src/server/api/haha-openai-oauth.ts +++ b/src/server/api/haha-openai-oauth.ts @@ -2,7 +2,8 @@ * Haha OpenAI OAuth REST API * * POST /api/haha-openai-oauth/start — 生成 PKCE+state,返回 authorize URL - * GET /callback/openai — 用户浏览器 redirect 到此,完成 token 交换 + * GET /auth/callback — 用户浏览器 redirect 到此,完成 token 交换 + * GET /callback/openai — 兼容旧路径 * GET /api/haha-openai-oauth — 查询当前登录状态(不回传 token 本体) * DELETE /api/haha-openai-oauth — 登出,删除 token 文件 */ diff --git a/src/server/index.ts b/src/server/index.ts index f9d7dadb..5b924d78 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -15,6 +15,7 @@ import { handleProxyRequest } from './proxy/handler.js' import { ProviderService } from './services/providerService.js' import { handleHahaOAuthCallback } from './api/haha-oauth.js' import { handleHahaOpenAIOAuthCallback } from './api/haha-openai-oauth.js' +import { OPENAI_CODEX_REDIRECT_PATH } from '../services/openaiAuth/client.js' import { ensureDesktopCliLauncherInstalled } from './services/desktopCliLauncherService.js' import { enableConfigs } from '../utils/config.js' import { diagnosticsService } from './services/diagnosticsService.js' @@ -267,7 +268,10 @@ export function startServer(port = PORT, host = HOST) { return handleHahaOAuthCallback(url) } - if (url.pathname === '/callback/openai') { + if ( + url.pathname === OPENAI_CODEX_REDIRECT_PATH || + url.pathname === '/callback/openai' + ) { return handleHahaOpenAIOAuthCallback(url) }