mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-17 13:55:50 +00:00
- hostGuard: workspace API key 仅限 api.anthropic.com,OAuth 限定 subscription plane - saveWorkspaceKey: sk-ant-api03- 前缀校验,安全写入缓存 - AuthPlaneSummary/WorkspaceKeyInput: 登录 UI 组件 - getAuthStatus: 认证状态查询 Co-Authored-By: glm-5-turbo <zai-org@claude-code-best.win>
96 lines
3.5 KiB
TypeScript
96 lines
3.5 KiB
TypeScript
/**
|
|
* Host guard utilities for multi-auth routing.
|
|
*
|
|
* These guards enforce that workspace API key requests only go to Anthropic's
|
|
* API host and that subscription OAuth requests stay on the subscription plane.
|
|
* This prevents credential leakage to third-party hosts.
|
|
*
|
|
* Design: ~/.claude/rules/deep-debug/security.md §2 (read-only investigation first,
|
|
* then minimal guard at earliest detection point).
|
|
*/
|
|
|
|
import { logError } from '../../utils/log.js'
|
|
|
|
/** The canonical Anthropic API host for workspace (non-subscription) endpoints. */
|
|
const WORKSPACE_API_HOST = 'api.anthropic.com'
|
|
|
|
/**
|
|
* Asserts that `url` points to Anthropic's workspace API host.
|
|
*
|
|
* Called before every workspace API key request (agents, vaults, memory_stores,
|
|
* skills) to prevent the API key from being sent to a third-party host.
|
|
*
|
|
* @throws {Error} if the URL does not resolve to api.anthropic.com
|
|
*/
|
|
export function assertWorkspaceHost(url: string): void {
|
|
let hostname: string
|
|
try {
|
|
hostname = new URL(url).hostname
|
|
} catch {
|
|
throw new Error(
|
|
`assertWorkspaceHost: invalid URL "${url}". Workspace API key requests must target ${WORKSPACE_API_HOST}.`,
|
|
)
|
|
}
|
|
|
|
if (hostname !== WORKSPACE_API_HOST) {
|
|
throw new Error(
|
|
`assertWorkspaceHost: refusing to send workspace API key to non-Anthropic host "${hostname}". ` +
|
|
`Workspace API key requests must target ${WORKSPACE_API_HOST}. ` +
|
|
`If you are using a custom base URL, workspace endpoints are only available on the Anthropic API.`,
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Asserts that `url` points to the Anthropic subscription base URL.
|
|
*
|
|
* Called before subscription-OAuth requests (schedule, ultrareview, teleport)
|
|
* to ensure they only target the expected host. Less strict than assertWorkspaceHost —
|
|
* it still allows the configured BASE_API_URL which may vary in test/staging.
|
|
*
|
|
* @throws {Error} if the URL does not resolve to api.anthropic.com
|
|
*/
|
|
export function assertSubscriptionBaseUrl(url: string): void {
|
|
let hostname: string
|
|
try {
|
|
hostname = new URL(url).hostname
|
|
} catch {
|
|
throw new Error(
|
|
`assertSubscriptionBaseUrl: invalid URL "${url}". Subscription OAuth requests must target ${WORKSPACE_API_HOST}.`,
|
|
)
|
|
}
|
|
|
|
if (hostname !== WORKSPACE_API_HOST) {
|
|
throw new Error(
|
|
`assertSubscriptionBaseUrl: refusing subscription OAuth request to non-Anthropic host "${hostname}". ` +
|
|
`Subscription OAuth requests must target ${WORKSPACE_API_HOST}.`,
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Warns (but does not throw) when Anthropic API environment variables are set
|
|
* alongside OpenAI-compat configuration.
|
|
*
|
|
* This prevents silent credential confusion when a user has both
|
|
* ANTHROPIC_API_KEY and OPENAI_API_KEY / CLAUDE_CODE_USE_OPENAI set.
|
|
* The warning is informational — the calling code decides what to do.
|
|
*/
|
|
export function assertNoAnthropicEnvForOpenAI(): void {
|
|
const hasOpenAIMode =
|
|
process.env['CLAUDE_CODE_USE_OPENAI'] === '1' ||
|
|
Boolean(process.env['OPENAI_API_KEY'])
|
|
const hasAnthropicKey = Boolean(process.env['ANTHROPIC_API_KEY'])
|
|
|
|
if (hasOpenAIMode && hasAnthropicKey) {
|
|
logError(
|
|
new Error(
|
|
'assertNoAnthropicEnvForOpenAI: Both ANTHROPIC_API_KEY and OpenAI-compat mode are set. ' +
|
|
'ANTHROPIC_API_KEY is for Anthropic workspace endpoints (/v1/agents, /v1/vaults, /v1/memory_stores). ' +
|
|
'OpenAI-compat mode routes /v1/messages to a third-party provider. ' +
|
|
'These are separate credential planes and will not interfere, but verify this is intentional.',
|
|
),
|
|
)
|
|
}
|
|
}
|