mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 12:14:19 +00:00
fix(cliproxy): ensure provider-specific OAuth token detection
Fixes critical auth bug where checking any JSON file in the auth directory would incorrectly mark providers as authenticated. Now validates that token files match provider-specific prefixes (gemini-, codex-, antigravity-) to prevent OAuth skipping across providers. Updates help command examples to use placeholder syntax and updates CHANGELOG to reflect Qwen -> Antigravity provider name change.
This commit is contained in:
1 parent
e54d401656
commit
e0df6aa900
3 files changed
+45
-17
No files matched your search
+4
-4
@@ -8,7 +8,7 @@ Format: [Keep a Changelog](https://keepachangelog.com/)
|
||||
- **CLIProxy OAuth Profiles**: Three new zero-config profiles powered by CLIProxyAPI
|
||||
- `ccs gemini` - Google Gemini via OAuth (zero config)
|
||||
- `ccs codex` - OpenAI Codex via OAuth (zero config)
|
||||
- `ccs qwen` - Alibaba Qwen via OAuth (zero config)
|
||||
- `ccs agy` - Antigravity (AGY) via OAuth (zero config)
|
||||
|
||||
- **Download-on-Demand Binary**: CLIProxyAPI binary (~15MB) downloads automatically on first use
|
||||
- Supports 6 platforms: darwin/linux/windows × amd64/arm64
|
||||
@@ -25,7 +25,7 @@ Format: [Keep a Changelog](https://keepachangelog.com/)
|
||||
- **CLIProxy Diagnostics** in `ccs doctor`:
|
||||
- Binary installation status + version
|
||||
- Config file validation
|
||||
- OAuth status per provider (gemini/codex/qwen)
|
||||
- OAuth status per provider (gemini/codex/agy)
|
||||
- Port 8317 availability check
|
||||
|
||||
- **Enhanced Error Messages** (`src/utils/error-manager.ts`):
|
||||
@@ -44,7 +44,7 @@ Format: [Keep a Changelog](https://keepachangelog.com/)
|
||||
|
||||
### Changed
|
||||
- **Profile Detection**: New priority order
|
||||
1. CLIProxy profiles (gemini, codex, qwen)
|
||||
1. CLIProxy profiles (gemini, codex, agy)
|
||||
2. Settings-based profiles (glm, glmt, kimi)
|
||||
3. Account-based profiles (work, personal)
|
||||
4. Default Claude CLI
|
||||
@@ -57,7 +57,7 @@ Format: [Keep a Changelog](https://keepachangelog.com/)
|
||||
- **Model Mappings**:
|
||||
- Gemini: gemini-2.0-flash (opus: thinking-exp, haiku: flash-lite)
|
||||
- Codex: gpt-4o (opus: o1, haiku: gpt-4o-mini)
|
||||
- Qwen: qwen-max (sonnet: qwen-plus, haiku: qwen-turbo)
|
||||
- Antigravity: agy (sonnet: agy-pro, haiku: agy-turbo)
|
||||
- **Storage**:
|
||||
- Binary: `~/.ccs/bin/cliproxyapi`
|
||||
- Tokens: `~/.ccs/cliproxy-auth/<provider>/`
|
||||
|
||||
@@ -120,10 +120,21 @@ export function getProviderTokenDir(provider: CLIProxyProvider): string {
|
||||
return getProviderAuthDir(provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provider-specific auth file prefixes
|
||||
* CLIProxyAPI names auth files with provider prefix (e.g., "antigravity-user@email.json")
|
||||
*/
|
||||
const PROVIDER_AUTH_PREFIXES: Record<CLIProxyProvider, string[]> = {
|
||||
gemini: ['gemini-', 'google-'],
|
||||
codex: ['codex-', 'openai-'],
|
||||
agy: ['antigravity-', 'agy-'],
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if provider has valid authentication
|
||||
* CLIProxyAPI stores OAuth tokens as JSON files in the auth directory.
|
||||
* We check for any .json files that could contain tokens.
|
||||
* Files are named with provider prefix (e.g., "antigravity-user@email.json").
|
||||
* We MUST check for provider-specific files, not just any .json file.
|
||||
*/
|
||||
export function isAuthenticated(provider: CLIProxyProvider): boolean {
|
||||
const tokenDir = getProviderTokenDir(provider);
|
||||
@@ -132,13 +143,22 @@ export function isAuthenticated(provider: CLIProxyProvider): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for any token files created by CLIProxyAPI
|
||||
// Get valid prefixes for this provider
|
||||
const validPrefixes = PROVIDER_AUTH_PREFIXES[provider] || [];
|
||||
|
||||
// Check for provider-specific token files
|
||||
try {
|
||||
const files = fs.readdirSync(tokenDir);
|
||||
const tokenFiles = files.filter(
|
||||
(f) => f.endsWith('.json') || f.endsWith('.token') || f === 'credentials'
|
||||
);
|
||||
return tokenFiles.length > 0;
|
||||
const providerTokenFiles = files.filter((f) => {
|
||||
// Must be a token-like file
|
||||
if (!f.endsWith('.json') && !f.endsWith('.token') && f !== 'credentials') {
|
||||
return false;
|
||||
}
|
||||
// Must have provider-specific prefix
|
||||
const lowerFile = f.toLowerCase();
|
||||
return validPrefixes.some((prefix) => lowerFile.startsWith(prefix));
|
||||
});
|
||||
return providerTokenFiles.length > 0;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
@@ -152,11 +172,19 @@ export function getAuthStatus(provider: CLIProxyProvider): AuthStatus {
|
||||
let tokenFiles: string[] = [];
|
||||
let lastAuth: Date | undefined;
|
||||
|
||||
// Get valid prefixes for this provider
|
||||
const validPrefixes = PROVIDER_AUTH_PREFIXES[provider] || [];
|
||||
|
||||
if (fs.existsSync(tokenDir)) {
|
||||
const files = fs.readdirSync(tokenDir);
|
||||
tokenFiles = files.filter(
|
||||
(f) => f.endsWith('.json') || f.endsWith('.token') || f === 'credentials'
|
||||
);
|
||||
// Only include provider-specific files
|
||||
tokenFiles = files.filter((f) => {
|
||||
if (!f.endsWith('.json') && !f.endsWith('.token') && f !== 'credentials') {
|
||||
return false;
|
||||
}
|
||||
const lowerFile = f.toLowerCase();
|
||||
return validPrefixes.some((prefix) => lowerFile.startsWith(prefix));
|
||||
});
|
||||
|
||||
// Get most recent modification time
|
||||
for (const file of tokenFiles) {
|
||||
|
||||
@@ -55,10 +55,10 @@ export function handleHelpCommand(): void {
|
||||
` ${colored('ccs agy', 'yellow')} Antigravity (gemini-3-pro-preview)`
|
||||
);
|
||||
console.log('');
|
||||
console.log(` ${colored('ccs gemini --auth', 'yellow')} Authenticate only`);
|
||||
console.log(` ${colored('ccs gemini --logout', 'yellow')} Clear authentication`);
|
||||
console.log(` ${colored('ccs gemini --headless', 'yellow')} Headless auth (for SSH)`);
|
||||
console.log(` ${colored('ccs gemini "explain code"', 'yellow')} Use with prompt`);
|
||||
console.log(` ${colored('ccs <provider> --auth', 'yellow')} Authenticate only`);
|
||||
console.log(` ${colored('ccs <provider> --logout', 'yellow')} Clear authentication`);
|
||||
console.log(` ${colored('ccs <provider> --headless', 'yellow')} Headless auth (for SSH)`);
|
||||
console.log(` ${colored('ccs codex "explain code"', 'yellow')} Use with prompt`);
|
||||
console.log('');
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in new issue
Block a user