codex-claude-proxy 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,7 +14,6 @@ It is designed primarily for **Claude Code CLI** (Anthropic-format client) while
14
14
  - [Quick Start](#quick-start)
15
15
  - [Authentication](#authenticate-codex--chatgpt)
16
16
  - [Claude Code Integration](#configure-claude-code-to-use-the-proxy)
17
- - [API Reference](#api-surface-high-level)
18
17
  - [Documentation](#documentation)
19
18
  - [Legal](#legal)
20
19
 
@@ -59,7 +58,7 @@ This proxy accepts Claude-style model IDs (what Claude Code expects) and maps th
59
58
  |---|---|---:|---|
60
59
  | `claude-sonnet-4-5` | **GPT-5.2 Codex** | Yes | Default “Sonnet” lane |
61
60
  | `claude-opus-4-5` | **GPT-5.3 Codex** | Yes | Default “Opus” lane |
62
- | `claude-haiku-4` | **GPT-5.2** (fast lane) | Yes | Lightweight / fast |
61
+ | `claude-haiku-4` | **GLM-5 / MiniMax M2.5** | No | Unlimited / No Auth required |
63
62
 
64
63
  ---
65
64
 
@@ -198,31 +197,14 @@ More details: [Claude Code Integration](./docs/CLAUDE_INTEGRATION.md).
198
197
 
199
198
  ---
200
199
 
201
- ## API surface (high level)
200
+ ## Security
202
201
 
203
- - Anthropic-compatible:
204
- - `POST /v1/messages`
205
- - `GET /v1/models`
206
- - `POST /v1/messages/count_tokens`
207
-
208
- - OpenAI-compatible:
209
- - `POST /v1/chat/completions`
210
-
211
- - Accounts:
212
- - `GET /accounts`
213
- - `POST /accounts/add`
214
- - `POST /accounts/add/manual`
215
- - `POST /accounts/switch`
216
- - `POST /accounts/refresh`, `POST /accounts/refresh/all`
217
-
218
- - Logs:
219
- - `GET /api/logs`
220
- - `GET /api/logs/stream?history=true`
221
-
222
- Full reference: [API Reference](./docs/API.md).
202
+ - **Localhost Only**: CORS is strictly restricted to `localhost` and `127.0.0.1` to prevent unauthorized cross-origin requests from external websites.
203
+ - **Credential Safety**: Credentials are not allowed in cross-origin requests.
223
204
 
224
205
  ---
225
206
 
207
+
226
208
  ## Documentation
227
209
 
228
210
  - [**Architecture**](./docs/ARCHITECTURE.md) - Design and flow
@@ -51,7 +51,7 @@ codex-claude-proxy/
51
51
  | File | Purpose |
52
52
  |------|---------|
53
53
  | `index.js` | Entry point (starts server) |
54
- | `server.js` | Express server, routes, request handling |
54
+ | `server.js` | Express server, routes, request handling (CORS restricted) |
55
55
  | `routes/api-routes.js` | API route registrations (mounted by server) |
56
56
  | `oauth.js` | OAuth 2.0 PKCE flow, token exchange |
57
57
  | `account-manager.js` | Account persistence, switching, token refresh |
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-claude-proxy",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Multi-account proxy server for OpenAI Codex CLI with Claude API compatibility",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/public/js/app.js CHANGED
@@ -1,6 +1,6 @@
1
1
  document.addEventListener('alpine:init', () => {
2
2
  Alpine.data('app', () => ({
3
- version: '1.0.0',
3
+ version: '1.0.2',
4
4
  connectionStatus: 'connecting',
5
5
  activeTab: 'dashboard',
6
6
  sidebarOpen: window.innerWidth >= 1024,
@@ -26,10 +26,10 @@ const tokenCache = new Map();
26
26
 
27
27
  function ensureConfigDir() {
28
28
  if (!existsSync(CONFIG_DIR)) {
29
- mkdirSync(CONFIG_DIR, { recursive: true });
29
+ mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
30
30
  }
31
31
  if (!existsSync(ACCOUNTS_DIR)) {
32
- mkdirSync(ACCOUNTS_DIR, { recursive: true });
32
+ mkdirSync(ACCOUNTS_DIR, { recursive: true, mode: 0o700 });
33
33
  }
34
34
  }
35
35
 
@@ -64,7 +64,7 @@ function loadAccounts() {
64
64
 
65
65
  function saveAccounts(data) {
66
66
  ensureConfigDir();
67
- writeFileSync(ACCOUNTS_FILE, JSON.stringify(data, null, 2));
67
+ writeFileSync(ACCOUNTS_FILE, JSON.stringify(data, null, 2), { mode: 0o600 });
68
68
  }
69
69
 
70
70
  function getActiveAccount() {
@@ -80,7 +80,7 @@ function updateAccountAuth(account) {
80
80
  const authFile = getAccountAuthFile(account.email);
81
81
 
82
82
  if (!existsSync(accountDir)) {
83
- mkdirSync(accountDir, { recursive: true });
83
+ mkdirSync(accountDir, { recursive: true, mode: 0o700 });
84
84
  }
85
85
 
86
86
  const authData = {
@@ -96,7 +96,7 @@ function updateAccountAuth(account) {
96
96
  };
97
97
 
98
98
  try {
99
- writeFileSync(authFile, JSON.stringify(authData, null, 2));
99
+ writeFileSync(authFile, JSON.stringify(authData, null, 2), { mode: 0o600 });
100
100
  console.log(`[AccountManager] Updated auth for: ${account.email}`);
101
101
  } catch (e) {
102
102
  console.error('[AccountManager] Failed to update auth:', e.message);
@@ -60,13 +60,13 @@ export async function updateClaudeConfig(updates) {
60
60
 
61
61
  const configDir = path.dirname(configPath);
62
62
  try {
63
- await fs.mkdir(configDir, { recursive: true });
63
+ await fs.mkdir(configDir, { recursive: true, mode: 0o700 });
64
64
  } catch (error) {
65
65
  // Ignore if exists
66
66
  }
67
67
 
68
68
  try {
69
- await fs.writeFile(configPath, JSON.stringify(newConfig, null, 2), 'utf8');
69
+ await fs.writeFile(configPath, JSON.stringify(newConfig, null, 2), { encoding: 'utf8', mode: 0o600 });
70
70
  console.log(`[ClaudeConfig] Updated config at ${configPath}`);
71
71
  return newConfig;
72
72
  } catch (error) {
@@ -39,9 +39,9 @@ function saveAccounts(data) {
39
39
  try {
40
40
  const dir = dirname(ACCOUNTS_FILE);
41
41
  if (!existsSync(dir)) {
42
- mkdirSync(dir, { recursive: true });
42
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
43
43
  }
44
- writeFileSync(ACCOUNTS_FILE, JSON.stringify(data, null, 2));
44
+ writeFileSync(ACCOUNTS_FILE, JSON.stringify(data, null, 2), { mode: 0o600 });
45
45
  console.log(`\n✓ Saved ${data.accounts.length} account(s) to ${ACCOUNTS_FILE}`);
46
46
  } catch (error) {
47
47
  console.error('Error saving accounts:', error.message);
package/src/index.js CHANGED
@@ -13,7 +13,7 @@ startServer({ port: PORT });
13
13
 
14
14
  console.log(`
15
15
  ╔══════════════════════════════════════════════════════════════╗
16
- ║ Codex Claude Proxy v1.0.1
16
+ ║ Codex Claude Proxy v1.0.2
17
17
  ║ (Direct API Mode) ║
18
18
  ╠══════════════════════════════════════════════════════════════╣
19
19
  ║ Server: http://localhost:${PORT} ║
@@ -10,7 +10,7 @@ const DEFAULT_SETTINGS = {
10
10
 
11
11
  function ensureConfigDir() {
12
12
  if (!existsSync(CONFIG_DIR)) {
13
- mkdirSync(CONFIG_DIR, { recursive: true });
13
+ mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
14
14
  }
15
15
  }
16
16
 
@@ -35,7 +35,7 @@ export function setServerSettings(patch = {}) {
35
35
  const next = { ...current, ...patch };
36
36
 
37
37
  ensureConfigDir();
38
- writeFileSync(SETTINGS_FILE, JSON.stringify(next, null, 2));
38
+ writeFileSync(SETTINGS_FILE, JSON.stringify(next, null, 2), { mode: 0o600 });
39
39
  return next;
40
40
  }
41
41
 
package/src/server.js CHANGED
@@ -14,7 +14,34 @@ export function createServer({ port }) {
14
14
  startAutoRefresh();
15
15
 
16
16
  const app = express();
17
- app.use(cors());
17
+ app.disable('x-powered-by');
18
+
19
+ // High-level request logging
20
+ app.use((req, res, next) => {
21
+ const start = Date.now();
22
+ res.on('finish', () => {
23
+ const duration = Date.now() - start;
24
+ const msg = `[${req.method}] ${req.originalUrl} ${res.statusCode} (${duration}ms)`;
25
+ if (res.statusCode >= 400) {
26
+ console.log(`\x1b[31m${msg}\x1b[0m`); // Red for error
27
+ } else if (req.originalUrl !== '/health') { // Skip health check logs to reduce noise
28
+ console.log(`\x1b[36m${msg}\x1b[0m`); // Cyan for success
29
+ }
30
+ });
31
+ next();
32
+ });
33
+
34
+ app.use(cors({
35
+ origin: [
36
+ `http://localhost:${port}`,
37
+ `http://127.0.0.1:${port}`,
38
+ 'http://localhost',
39
+ 'http://127.0.0.1'
40
+ ],
41
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
42
+ allowedHeaders: ['Content-Type', 'Authorization'],
43
+ credentials: false
44
+ }));
18
45
  app.use(express.json({ limit: '10mb' }));
19
46
 
20
47
  registerApiRoutes(app, { port });