(rawUrl)
| 207 | } |
| 208 | |
| 209 | function parseLocalhostCallback(rawUrl) { |
| 210 | let parsed; |
| 211 | try { |
| 212 | parsed = new URL(rawUrl); |
| 213 | } catch { |
| 214 | throw new Error('提供的回调 URL 不是合法链接。'); |
| 215 | } |
| 216 | |
| 217 | if (!['http:', 'https:'].includes(parsed.protocol)) { |
| 218 | throw new Error('回调 URL 协议不正确。'); |
| 219 | } |
| 220 | if (!['localhost', '127.0.0.1'].includes(parsed.hostname)) { |
| 221 | throw new Error('步骤 9 只接受 localhost / 127.0.0.1 回调地址。'); |
| 222 | } |
| 223 | if (parsed.pathname !== '/auth/callback') { |
| 224 | throw new Error('回调 URL 路径必须是 /auth/callback。'); |
| 225 | } |
| 226 | |
| 227 | const code = (parsed.searchParams.get('code') || '').trim(); |
| 228 | const state = (parsed.searchParams.get('state') || '').trim(); |
| 229 | if (!code || !state) { |
| 230 | throw new Error('回调 URL 中缺少 code 或 state。'); |
| 231 | } |
| 232 | |
| 233 | return { |
| 234 | url: parsed.toString(), |
| 235 | code, |
| 236 | state, |
| 237 | }; |
| 238 | } |
| 239 | |
| 240 | function buildOpenAiCredentials(exchangeData) { |
| 241 | const credentials = {}; |
no outgoing calls
no test coverage detected