@kaitranntt/ccs 7.78.0-dev.1 → 7.78.0-dev.10
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/dist/commands/config-command-options.d.ts.map +1 -1
- package/dist/commands/config-command-options.js +4 -2
- package/dist/commands/config-command-options.js.map +1 -1
- package/dist/commands/config-command.js +1 -1
- package/dist/commands/config-command.js.map +1 -1
- package/dist/commands/config-dashboard-host.d.ts +1 -0
- package/dist/commands/config-dashboard-host.d.ts.map +1 -1
- package/dist/commands/config-dashboard-host.js +2 -1
- package/dist/commands/config-dashboard-host.js.map +1 -1
- package/dist/ui/assets/{accounts-BavG_0Lp.js → accounts-D_ROBWJW.js} +1 -1
- package/dist/ui/assets/{alert-dialog-CwbcF3cM.js → alert-dialog-CdBSeTf8.js} +1 -1
- package/dist/ui/assets/{api-XKc5ORgC.js → api-DZp9XoZ3.js} +1 -1
- package/dist/ui/assets/{auth-section-JYi_w0iY.js → auth-section-CBHPWh8P.js} +1 -1
- package/dist/ui/assets/{backups-section-B8rlcnmC.js → backups-section-BEfeEYNu.js} +1 -1
- package/dist/ui/assets/{channels-AoyzfHeo.js → channels-yd4p8uGF.js} +1 -1
- package/dist/ui/assets/{checkbox-BvotO8ov.js → checkbox-O4MS4m31.js} +1 -1
- package/dist/ui/assets/{claude-extension-CVxbFjPB.js → claude-extension-RX6pi5Dq.js} +1 -1
- package/dist/ui/assets/{cliproxy-x0y8HBwr.js → cliproxy-CCPBZ2hk.js} +1 -1
- package/dist/ui/assets/{cliproxy-ai-providers-CZzq109C.js → cliproxy-ai-providers-CFaY0exX.js} +1 -1
- package/dist/ui/assets/{cliproxy-control-panel-CTHL_h9B.js → cliproxy-control-panel-Co84wmaz.js} +1 -1
- package/dist/ui/assets/{codex-CSIkJL2R.js → codex-BndwF_Uy.js} +2 -2
- package/dist/ui/assets/{confirm-dialog-BTjfIKq_.js → confirm-dialog-CuqXEw3c.js} +1 -1
- package/dist/ui/assets/{copilot-BvUgiXUb.js → copilot-DwVnqcwy.js} +1 -1
- package/dist/ui/assets/{cursor-CB9xJXy9.js → cursor-DMk7oeR8.js} +1 -1
- package/dist/ui/assets/{droid--IsHK3iC.js → droid-BNzpeb07.js} +1 -1
- package/dist/ui/assets/{globalenv-section-CE2ldHJ4.js → globalenv-section-BDlzpym6.js} +1 -1
- package/dist/ui/assets/{health-DD9gcO8M.js → health-BQ7Tv1rQ.js} +1 -1
- package/dist/ui/assets/{index-IN2T_Dpm.js → index-B5Fvdc9D.js} +1 -1
- package/dist/ui/assets/{index-b5UbBJdP.js → index-BQO1Car5.js} +1 -1
- package/dist/ui/assets/index-C-pkmHvH.css +1 -0
- package/dist/ui/assets/{index-zv39jop-.js → index-C1oiTZ4n.js} +1 -1
- package/dist/ui/assets/{index-Dm_dDmYb.js → index-CHRUhYJD.js} +22 -22
- package/dist/ui/assets/{index-Dk1F8Ovl.js → index-DTFmb_cl.js} +1 -1
- package/dist/ui/assets/{index-DF8caRNZ.js → index-DgTEmJwC.js} +1 -1
- package/dist/ui/assets/{index-BeGUeif2.js → index-dIME7UaU.js} +1 -1
- package/dist/ui/assets/{logs-CyO00yGk.js → logs-BTE4BziS.js} +1 -1
- package/dist/ui/assets/{masked-input-BH4lufWZ.js → masked-input-FdlUBXx1.js} +1 -1
- package/dist/ui/assets/{proxy-status-widget-6_YTJ6Xm.js → proxy-status-widget-BHCYqiYU.js} +1 -1
- package/dist/ui/assets/raw-json-settings-editor-panel-BWEzkHEh.js +1 -0
- package/dist/ui/assets/{searchable-select-KOr7UsSu.js → searchable-select-DuJbJ_tt.js} +1 -1
- package/dist/ui/assets/{separator-mYtigESV.js → separator-ohkxsfxk.js} +1 -1
- package/dist/ui/assets/{shared-C8ZW3jNG.js → shared-1ZnvRlC8.js} +1 -1
- package/dist/ui/assets/{table-CwSuE62H.js → table-BXnQYMP2.js} +1 -1
- package/dist/ui/assets/{updates-CKsRAm2k.js → updates-Cp9b84A6.js} +1 -1
- package/dist/ui/assets/{use-accounts-BYZkfTwy.js → use-accounts-C88lVWLw.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/dist/web-server/index.d.ts.map +1 -1
- package/dist/web-server/index.js +80 -20
- package/dist/web-server/index.js.map +1 -1
- package/dist/web-server/middleware/auth-middleware.d.ts +5 -0
- package/dist/web-server/middleware/auth-middleware.d.ts.map +1 -1
- package/dist/web-server/middleware/auth-middleware.js +73 -1
- package/dist/web-server/middleware/auth-middleware.js.map +1 -1
- package/dist/web-server/routes/codex-routes.d.ts.map +1 -1
- package/dist/web-server/routes/codex-routes.js +7 -0
- package/dist/web-server/routes/codex-routes.js.map +1 -1
- package/lib/mcp/ccs-browser-server.cjs +153 -6
- package/package.json +1 -1
- package/dist/ui/assets/index-a3U2tSQf.css +0 -1
- package/dist/ui/assets/raw-json-settings-editor-panel-BErB7VIF.js +0 -1
package/dist/web-server/index.js
CHANGED
|
@@ -46,6 +46,10 @@ const proxy_target_resolver_1 = require("../cliproxy/proxy/proxy-target-resolver
|
|
|
46
46
|
const sync_1 = require("../cliproxy/sync");
|
|
47
47
|
const aggregator_1 = require("./usage/aggregator");
|
|
48
48
|
const logging_1 = require("../services/logging");
|
|
49
|
+
const config_dashboard_host_1 = require("../commands/config-dashboard-host");
|
|
50
|
+
function getListenHost(options) {
|
|
51
|
+
return options.host || config_dashboard_host_1.DEFAULT_DASHBOARD_HOST;
|
|
52
|
+
}
|
|
49
53
|
const logger = (0, logging_1.createLogger)('web-server');
|
|
50
54
|
/**
|
|
51
55
|
* Start Express server with WebSocket support
|
|
@@ -54,8 +58,7 @@ async function startServer(options) {
|
|
|
54
58
|
const app = (0, express_1.default)();
|
|
55
59
|
const server = http_1.default.createServer(app);
|
|
56
60
|
const wss = new ws_1.WebSocketServer({
|
|
57
|
-
|
|
58
|
-
path: '/ws',
|
|
61
|
+
noServer: true,
|
|
59
62
|
maxPayload: 1024 * 1024, // 1MB hard limit to prevent DoS
|
|
60
63
|
perMessageDeflate: false, // Prevent zip bomb attacks
|
|
61
64
|
});
|
|
@@ -70,7 +73,8 @@ async function startServer(options) {
|
|
|
70
73
|
});
|
|
71
74
|
app.use(request_logging_middleware_1.requestLoggingMiddleware);
|
|
72
75
|
// Session middleware (for dashboard auth)
|
|
73
|
-
|
|
76
|
+
const sessionMiddleware = (0, auth_middleware_1.createSessionMiddleware)();
|
|
77
|
+
app.use(sessionMiddleware);
|
|
74
78
|
// Auth middleware (protects API routes when enabled)
|
|
75
79
|
app.use(auth_middleware_1.authMiddleware);
|
|
76
80
|
// CLIProxy local reverse proxy (avoids cross-origin issues in Docker)
|
|
@@ -111,6 +115,33 @@ async function startServer(options) {
|
|
|
111
115
|
res.sendFile(path_1.default.join(staticDir, 'index.html'));
|
|
112
116
|
});
|
|
113
117
|
}
|
|
118
|
+
server.on('upgrade', (request, socket, head) => {
|
|
119
|
+
const pathname = getUpgradePathname(request.url);
|
|
120
|
+
if (!pathname) {
|
|
121
|
+
rejectWebSocketUpgrade(socket, 400, 'Invalid WebSocket upgrade request');
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (pathname !== '/ws') {
|
|
125
|
+
if (!options.dev) {
|
|
126
|
+
rejectWebSocketUpgrade(socket, 404, 'WebSocket endpoint not found');
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const response = new http_1.default.ServerResponse(request);
|
|
131
|
+
sessionMiddleware(request, response, (error) => {
|
|
132
|
+
if (error) {
|
|
133
|
+
rejectWebSocketUpgrade(socket, 500, 'WebSocket session validation failed');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (!(0, auth_middleware_1.isDashboardWebSocketUpgradeAllowed)(request)) {
|
|
137
|
+
rejectWebSocketUpgrade(socket, (0, auth_middleware_1.getDashboardWebSocketRejectionStatus)(request), 'WebSocket access denied');
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
141
|
+
wss.emit('connection', ws, request);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
114
145
|
// WebSocket connection handler + file watcher
|
|
115
146
|
const { cleanup: wsCleanup } = (0, websocket_1.setupWebSocket)(wss);
|
|
116
147
|
// Start auto-sync watcher (if enabled in config)
|
|
@@ -130,11 +161,12 @@ async function startServer(options) {
|
|
|
130
161
|
};
|
|
131
162
|
// Start listening
|
|
132
163
|
return new Promise((resolve, reject) => {
|
|
164
|
+
const listenHost = getListenHost(options);
|
|
133
165
|
const onError = (error) => {
|
|
134
166
|
logger.error('server.listen_failed', 'Dashboard server failed to start', {
|
|
135
167
|
code: error.code || 'unknown',
|
|
136
168
|
message: error.message,
|
|
137
|
-
host:
|
|
169
|
+
host: listenHost,
|
|
138
170
|
port: options.port,
|
|
139
171
|
});
|
|
140
172
|
cleanup();
|
|
@@ -143,8 +175,18 @@ async function startServer(options) {
|
|
|
143
175
|
server.once('error', onError);
|
|
144
176
|
const onListening = () => {
|
|
145
177
|
server.off('error', onError);
|
|
178
|
+
try {
|
|
179
|
+
assertSafeDashboardBind(options, server.address());
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
cleanup();
|
|
183
|
+
server.close(() => {
|
|
184
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
185
|
+
});
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
146
188
|
logger.info('server.listening', 'Dashboard server listening', {
|
|
147
|
-
host:
|
|
189
|
+
host: listenHost,
|
|
148
190
|
port: options.port,
|
|
149
191
|
dev: Boolean(options.dev),
|
|
150
192
|
});
|
|
@@ -153,11 +195,7 @@ async function startServer(options) {
|
|
|
153
195
|
resolve({ server, wss, cleanup });
|
|
154
196
|
};
|
|
155
197
|
try {
|
|
156
|
-
|
|
157
|
-
server.listen(options.port, options.host, onListening);
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
server.listen(options.port, onListening);
|
|
198
|
+
server.listen(options.port, listenHost, onListening);
|
|
161
199
|
}
|
|
162
200
|
catch (error) {
|
|
163
201
|
server.off('error', onError);
|
|
@@ -167,22 +205,44 @@ async function startServer(options) {
|
|
|
167
205
|
});
|
|
168
206
|
}
|
|
169
207
|
exports.startServer = startServer;
|
|
170
|
-
function
|
|
171
|
-
|
|
172
|
-
return
|
|
208
|
+
function getUpgradePathname(requestUrl) {
|
|
209
|
+
try {
|
|
210
|
+
return new URL(requestUrl ?? '/', 'http://localhost').pathname;
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return null;
|
|
173
214
|
}
|
|
215
|
+
}
|
|
216
|
+
function rejectWebSocketUpgrade(socket, statusCode, message) {
|
|
217
|
+
socket.write(`HTTP/1.1 ${statusCode} ${message}\r\n` +
|
|
218
|
+
'Connection: close\r\n' +
|
|
219
|
+
'Content-Type: text/plain; charset=utf-8\r\n' +
|
|
220
|
+
`Content-Length: ${Buffer.byteLength(message)}\r\n` +
|
|
221
|
+
'\r\n' +
|
|
222
|
+
message);
|
|
223
|
+
socket.destroy();
|
|
224
|
+
}
|
|
225
|
+
function assertSafeDashboardBind(options, address) {
|
|
226
|
+
const listenHost = getListenHost(options);
|
|
227
|
+
if (!(0, config_dashboard_host_1.isLoopbackHost)(listenHost) || typeof address === 'string' || !address) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if ((0, config_dashboard_host_1.isLoopbackHost)(address.address)) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
throw new Error(`Dashboard host ${listenHost} resolved to non-loopback address ${address.address}; pass --host explicitly to allow network exposure.`);
|
|
234
|
+
}
|
|
235
|
+
function formatListenError(error, options) {
|
|
236
|
+
const listenHost = getListenHost(options);
|
|
174
237
|
if (error.code === 'EADDRINUSE') {
|
|
175
|
-
return `
|
|
238
|
+
return `Unable to bind ${listenHost}:${options.port}; the address may be unavailable or the port may already be in use`;
|
|
176
239
|
}
|
|
177
|
-
if (error.code === 'EADDRNOTAVAIL'
|
|
178
|
-
return `Cannot bind to ${
|
|
240
|
+
if (error.code === 'EADDRNOTAVAIL') {
|
|
241
|
+
return `Cannot bind to ${listenHost}:${options.port} on this machine`;
|
|
179
242
|
}
|
|
180
243
|
if (error.code === 'EACCES') {
|
|
181
244
|
return `Permission denied while binding to port ${options.port}`;
|
|
182
245
|
}
|
|
183
|
-
|
|
184
|
-
return `Cannot bind to ${options.host}:${options.port}: ${error.message}`;
|
|
185
|
-
}
|
|
186
|
-
return error.message;
|
|
246
|
+
return `Cannot bind to ${listenHost}:${options.port}: ${error.message}`;
|
|
187
247
|
}
|
|
188
248
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/web-server/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,sDAA8B;AAC9B,gDAAwB;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/web-server/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Dashboard Authentication Middleware
|
|
3
3
|
* Session-based auth with httpOnly cookies for CCS dashboard.
|
|
4
4
|
*/
|
|
5
|
+
/// <reference types="node" />
|
|
6
|
+
import type { IncomingMessage } from 'http';
|
|
5
7
|
import type { NextFunction, Request, Response } from 'express';
|
|
6
8
|
declare module 'express-session' {
|
|
7
9
|
interface SessionData {
|
|
@@ -24,5 +26,8 @@ export declare function createSessionMiddleware(): (req: Request, res: Response,
|
|
|
24
26
|
*/
|
|
25
27
|
export declare function authMiddleware(req: Request, res: Response, next: NextFunction): void;
|
|
26
28
|
export declare function isLoopbackRemoteAddress(value: string | undefined): boolean;
|
|
29
|
+
export declare function isDashboardWebSocketOriginAllowed(req: IncomingMessage): boolean;
|
|
30
|
+
export declare function isDashboardWebSocketUpgradeAllowed(req: IncomingMessage): boolean;
|
|
31
|
+
export declare function getDashboardWebSocketRejectionStatus(req?: IncomingMessage): 401 | 403;
|
|
27
32
|
export declare function requireLocalAccessWhenAuthDisabled(req: Request, res: Response, error?: string): boolean;
|
|
28
33
|
//# sourceMappingURL=auth-middleware.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../../../src/web-server/middleware/auth-middleware.ts"],"names":[],"mappings":"AAAA;;;GAGG
|
|
1
|
+
{"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../../../src/web-server/middleware/auth-middleware.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AAC5C,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAc/D,OAAO,QAAQ,iBAAiB,CAAC;IAC/B,UAAU,WAAW;QACnB,aAAa,EAAE,OAAO,CAAC;QACvB,QAAQ,EAAE,MAAM,CAAC;KAClB;CACF;AAkDD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,sDAO3B,CAAC;AAEH;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,CACzC,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,IAAI,EAAE,YAAY,KACf,IAAI,CAeR;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAwBpF;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAU1E;AAiCD,wBAAgB,iCAAiC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CA6B/E;AAED,wBAAgB,kCAAkC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAUhF;AAED,wBAAgB,oCAAoC,CAAC,GAAG,CAAC,EAAE,eAAe,GAAG,GAAG,GAAG,GAAG,CAQrF;AAED,wBAAgB,kCAAkC,CAChD,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,QAAQ,EACb,KAAK,SAA6E,GACjF,OAAO,CAWT"}
|
|
@@ -7,7 +7,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
7
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
8
|
};
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.requireLocalAccessWhenAuthDisabled = exports.isLoopbackRemoteAddress = exports.authMiddleware = exports.createSessionMiddleware = exports.loginRateLimiter = void 0;
|
|
10
|
+
exports.requireLocalAccessWhenAuthDisabled = exports.getDashboardWebSocketRejectionStatus = exports.isDashboardWebSocketUpgradeAllowed = exports.isDashboardWebSocketOriginAllowed = exports.isLoopbackRemoteAddress = exports.authMiddleware = exports.createSessionMiddleware = exports.loginRateLimiter = void 0;
|
|
11
11
|
const express_session_1 = __importDefault(require("express-session"));
|
|
12
12
|
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
13
13
|
const crypto_1 = __importDefault(require("crypto"));
|
|
@@ -125,6 +125,78 @@ function isLoopbackRemoteAddress(value) {
|
|
|
125
125
|
normalized.startsWith('::ffff:127.'));
|
|
126
126
|
}
|
|
127
127
|
exports.isLoopbackRemoteAddress = isLoopbackRemoteAddress;
|
|
128
|
+
function isLoopbackHostname(value) {
|
|
129
|
+
if (!value)
|
|
130
|
+
return false;
|
|
131
|
+
const normalized = value
|
|
132
|
+
.trim()
|
|
133
|
+
.toLowerCase()
|
|
134
|
+
.replace(/^\[|\]$/g, '');
|
|
135
|
+
return (normalized === 'localhost' ||
|
|
136
|
+
normalized.endsWith('.localhost') ||
|
|
137
|
+
isLoopbackRemoteAddress(normalized));
|
|
138
|
+
}
|
|
139
|
+
function getSingleHeader(value) {
|
|
140
|
+
return Array.isArray(value) ? value[0] : value;
|
|
141
|
+
}
|
|
142
|
+
function parseHostHeader(value) {
|
|
143
|
+
if (!value)
|
|
144
|
+
return null;
|
|
145
|
+
try {
|
|
146
|
+
return new URL(`http://${value}`);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function isHttpOrigin(origin) {
|
|
153
|
+
return origin.protocol === 'http:' || origin.protocol === 'https:';
|
|
154
|
+
}
|
|
155
|
+
function isDashboardWebSocketOriginAllowed(req) {
|
|
156
|
+
const originHeader = getSingleHeader(req.headers.origin);
|
|
157
|
+
if (!originHeader)
|
|
158
|
+
return true;
|
|
159
|
+
let origin;
|
|
160
|
+
try {
|
|
161
|
+
origin = new URL(originHeader);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
if (!isHttpOrigin(origin)) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const host = parseHostHeader(getSingleHeader(req.headers.host));
|
|
170
|
+
if (!host) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
if (origin.host.toLowerCase() === host.host.toLowerCase()) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
return (isLoopbackHostname(origin.hostname) &&
|
|
177
|
+
isLoopbackHostname(host.hostname) &&
|
|
178
|
+
origin.port === host.port);
|
|
179
|
+
}
|
|
180
|
+
exports.isDashboardWebSocketOriginAllowed = isDashboardWebSocketOriginAllowed;
|
|
181
|
+
function isDashboardWebSocketUpgradeAllowed(req) {
|
|
182
|
+
if (!isDashboardWebSocketOriginAllowed(req)) {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
if (!(0, config_loader_facade_1.isDashboardAuthEnabled)()) {
|
|
186
|
+
return isLoopbackRemoteAddress(req.socket.remoteAddress);
|
|
187
|
+
}
|
|
188
|
+
return Boolean(req.session?.authenticated);
|
|
189
|
+
}
|
|
190
|
+
exports.isDashboardWebSocketUpgradeAllowed = isDashboardWebSocketUpgradeAllowed;
|
|
191
|
+
function getDashboardWebSocketRejectionStatus(req) {
|
|
192
|
+
if (req && !isDashboardWebSocketOriginAllowed(req)) {
|
|
193
|
+
return 403;
|
|
194
|
+
}
|
|
195
|
+
if (!(0, config_loader_facade_1.isDashboardAuthEnabled)())
|
|
196
|
+
return 403;
|
|
197
|
+
return 401;
|
|
198
|
+
}
|
|
199
|
+
exports.getDashboardWebSocketRejectionStatus = getDashboardWebSocketRejectionStatus;
|
|
128
200
|
function requireLocalAccessWhenAuthDisabled(req, res, error = 'This endpoint requires localhost access when dashboard auth is disabled.') {
|
|
129
201
|
if ((0, config_loader_facade_1.isDashboardAuthEnabled)()) {
|
|
130
202
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-middleware.js","sourceRoot":"","sources":["../../../src/web-server/middleware/auth-middleware.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;
|
|
1
|
+
{"version":3,"file":"auth-middleware.js","sourceRoot":"","sources":["../../../src/web-server/middleware/auth-middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-routes.d.ts","sourceRoot":"","sources":["../../../src/web-server/routes/codex-routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codex-routes.d.ts","sourceRoot":"","sources":["../../../src/web-server/routes/codex-routes.ts"],"names":[],"mappings":"AAYA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAqFxB,eAAe,MAAM,CAAC"}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const express_1 = require("express");
|
|
4
|
+
const auth_middleware_1 = require("../middleware/auth-middleware");
|
|
4
5
|
const codex_dashboard_service_1 = require("../services/codex-dashboard-service");
|
|
5
6
|
const router = (0, express_1.Router)();
|
|
7
|
+
const CODEX_CONFIG_ACCESS_ERROR = 'Codex configuration endpoints require localhost access when dashboard auth is disabled.';
|
|
8
|
+
router.use('/config', (req, res, next) => {
|
|
9
|
+
if ((0, auth_middleware_1.requireLocalAccessWhenAuthDisabled)(req, res, CODEX_CONFIG_ACCESS_ERROR)) {
|
|
10
|
+
next();
|
|
11
|
+
}
|
|
12
|
+
});
|
|
6
13
|
router.get('/diagnostics', async (_req, res) => {
|
|
7
14
|
try {
|
|
8
15
|
res.json(await (0, codex_dashboard_service_1.getCodexDashboardDiagnostics)());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-routes.js","sourceRoot":"","sources":["../../../src/web-server/routes/codex-routes.ts"],"names":[],"mappings":";;AACA,qCAAiC;AACjC,iFAO6C;AAE7C,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"codex-routes.js","sourceRoot":"","sources":["../../../src/web-server/routes/codex-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -151,6 +151,8 @@ const DEFAULT_DRAG_STEPS = 5;
|
|
|
151
151
|
const MAX_POINTER_ACTIONS = 25;
|
|
152
152
|
const SESSION_START_SETTLE_WINDOW_MS = 250;
|
|
153
153
|
const MAX_ARTIFACT_FILE_BYTES = 5 * 1024 * 1024;
|
|
154
|
+
const MAX_LOCAL_TRANSFER_FILE_BYTES = 10 * 1024 * 1024;
|
|
155
|
+
const MAX_LOCAL_TRANSFER_FILES = 10;
|
|
154
156
|
const SAFE_ARTIFACT_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
155
157
|
const SESSION_CANCELED_ERROR_CODE = 'SESSION_CANCELED';
|
|
156
158
|
|
|
@@ -177,6 +179,37 @@ const recentDownloads = [];
|
|
|
177
179
|
const interceptSessionsByPageId = new Map();
|
|
178
180
|
let browserDownloadSession = null;
|
|
179
181
|
let sessionDownloadDir = '';
|
|
182
|
+
const SENSITIVE_LOCAL_PATH_SEGMENTS = new Set([
|
|
183
|
+
'.ssh',
|
|
184
|
+
'.gnupg',
|
|
185
|
+
'.aws',
|
|
186
|
+
'.azure',
|
|
187
|
+
'.kube',
|
|
188
|
+
'.docker',
|
|
189
|
+
'.npmrc',
|
|
190
|
+
'.netrc',
|
|
191
|
+
'.pypirc',
|
|
192
|
+
'.config',
|
|
193
|
+
'.claude',
|
|
194
|
+
'.ccs',
|
|
195
|
+
]);
|
|
196
|
+
const SENSITIVE_LOCAL_FILE_NAMES = new Set([
|
|
197
|
+
'.env',
|
|
198
|
+
'id_rsa',
|
|
199
|
+
'id_dsa',
|
|
200
|
+
'id_ecdsa',
|
|
201
|
+
'id_ed25519',
|
|
202
|
+
'known_hosts',
|
|
203
|
+
'authorized_keys',
|
|
204
|
+
'credentials',
|
|
205
|
+
'credentials.json',
|
|
206
|
+
'config.json',
|
|
207
|
+
'settings.json',
|
|
208
|
+
'history',
|
|
209
|
+
'.bash_history',
|
|
210
|
+
'.zsh_history',
|
|
211
|
+
'.fish_history',
|
|
212
|
+
]);
|
|
180
213
|
const MAX_RECENT_REQUESTS = 100;
|
|
181
214
|
const MAX_RECENT_DOWNLOADS = 100;
|
|
182
215
|
const FETCH_FAIL_ERROR_REASON = 'Failed';
|
|
@@ -1438,10 +1471,105 @@ function getSessionDownloadPath() {
|
|
|
1438
1471
|
return sessionDownloadDir;
|
|
1439
1472
|
}
|
|
1440
1473
|
|
|
1474
|
+
function splitConfiguredPathRoots(value) {
|
|
1475
|
+
return String(value || '')
|
|
1476
|
+
.split(path.delimiter)
|
|
1477
|
+
.map((entry) => entry.trim())
|
|
1478
|
+
.filter(Boolean)
|
|
1479
|
+
.map((entry) => path.resolve(entry));
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
function getDownloadSafeRoots() {
|
|
1483
|
+
return [
|
|
1484
|
+
getSessionDownloadPath(),
|
|
1485
|
+
...splitConfiguredPathRoots(process.env.CCS_BROWSER_DOWNLOAD_ROOTS),
|
|
1486
|
+
];
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
function getUploadSafeRoots() {
|
|
1490
|
+
return [
|
|
1491
|
+
getSessionDownloadPath(),
|
|
1492
|
+
...splitConfiguredPathRoots(process.env.CCS_BROWSER_UPLOAD_ROOTS),
|
|
1493
|
+
];
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
function getNearestExistingAncestor(candidatePath) {
|
|
1497
|
+
let currentPath = candidatePath;
|
|
1498
|
+
while (!fs.existsSync(currentPath)) {
|
|
1499
|
+
const parentPath = path.dirname(currentPath);
|
|
1500
|
+
if (parentPath === currentPath) {
|
|
1501
|
+
return currentPath;
|
|
1502
|
+
}
|
|
1503
|
+
currentPath = parentPath;
|
|
1504
|
+
}
|
|
1505
|
+
return currentPath;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
function resolveExistingRoot(rootPath) {
|
|
1509
|
+
fs.mkdirSync(rootPath, { recursive: true });
|
|
1510
|
+
return fs.realpathSync(rootPath);
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
function resolvePathWithRealAncestor(candidatePath) {
|
|
1514
|
+
const resolvedPath = path.resolve(candidatePath);
|
|
1515
|
+
const ancestorPath = getNearestExistingAncestor(resolvedPath);
|
|
1516
|
+
const realAncestorPath = fs.realpathSync(ancestorPath);
|
|
1517
|
+
const relativeSuffix = path.relative(ancestorPath, resolvedPath);
|
|
1518
|
+
return relativeSuffix ? path.resolve(realAncestorPath, relativeSuffix) : realAncestorPath;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
function isPathInsideRoot(candidatePath, rootPath) {
|
|
1522
|
+
const relativePath = path.relative(rootPath, candidatePath);
|
|
1523
|
+
return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
function findContainingRoot(candidatePath, rootPaths) {
|
|
1527
|
+
return rootPaths.find((rootPath) => isPathInsideRoot(candidatePath, rootPath)) || '';
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
function getLocalPathSegments(candidatePath, rootPath) {
|
|
1531
|
+
const rootSegments = path.resolve(rootPath).split(path.sep).filter(Boolean);
|
|
1532
|
+
const relativePath = path.relative(rootPath, candidatePath);
|
|
1533
|
+
const relativeSegments = relativePath.split(path.sep).filter(Boolean);
|
|
1534
|
+
return [...rootSegments, ...relativeSegments];
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
function assertNoSensitiveLocalPathSegments(candidatePath, rootPath, label) {
|
|
1538
|
+
const segments = getLocalPathSegments(candidatePath, rootPath);
|
|
1539
|
+
for (const segment of segments) {
|
|
1540
|
+
const normalizedSegment = segment.toLowerCase();
|
|
1541
|
+
if (normalizedSegment.startsWith('.') || SENSITIVE_LOCAL_PATH_SEGMENTS.has(normalizedSegment)) {
|
|
1542
|
+
throw new Error(`${label} cannot include hidden or sensitive path segment: ${segment}`);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
const fileName = path.basename(candidatePath).toLowerCase();
|
|
1547
|
+
if (SENSITIVE_LOCAL_FILE_NAMES.has(fileName)) {
|
|
1548
|
+
throw new Error(
|
|
1549
|
+
`${label} cannot reference sensitive file name: ${path.basename(candidatePath)}`
|
|
1550
|
+
);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1441
1554
|
function ensureWritableDirectory(downloadPath) {
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1555
|
+
const resolvedPath = path.resolve(downloadPath);
|
|
1556
|
+
const candidatePath = resolvePathWithRealAncestor(resolvedPath);
|
|
1557
|
+
const safeRoots = getDownloadSafeRoots().map(resolveExistingRoot);
|
|
1558
|
+
const containingRoot = findContainingRoot(candidatePath, safeRoots);
|
|
1559
|
+
if (!containingRoot) {
|
|
1560
|
+
throw new Error(
|
|
1561
|
+
'downloadPath must be inside the browser session download directory or a CCS_BROWSER_DOWNLOAD_ROOTS entry'
|
|
1562
|
+
);
|
|
1563
|
+
}
|
|
1564
|
+
assertNoSensitiveLocalPathSegments(candidatePath, containingRoot, 'downloadPath');
|
|
1565
|
+
|
|
1566
|
+
fs.mkdirSync(resolvedPath, { recursive: true });
|
|
1567
|
+
const realDownloadPath = fs.realpathSync(resolvedPath);
|
|
1568
|
+
if (!isPathInsideRoot(realDownloadPath, containingRoot)) {
|
|
1569
|
+
throw new Error('downloadPath cannot traverse outside the allowed download root');
|
|
1570
|
+
}
|
|
1571
|
+
fs.accessSync(realDownloadPath, fs.constants.W_OK);
|
|
1572
|
+
return realDownloadPath;
|
|
1445
1573
|
}
|
|
1446
1574
|
|
|
1447
1575
|
function pushRecentDownload(entry) {
|
|
@@ -2418,16 +2546,35 @@ function buildFileInputHandleExpression(selector, nth, frameSelector, pierceShad
|
|
|
2418
2546
|
}
|
|
2419
2547
|
|
|
2420
2548
|
function validateLocalFiles(files) {
|
|
2549
|
+
if (files.length > MAX_LOCAL_TRANSFER_FILES) {
|
|
2550
|
+
throw new Error(`files exceeds maximum of ${MAX_LOCAL_TRANSFER_FILES}`);
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
const safeRoots = getUploadSafeRoots().map(resolveExistingRoot);
|
|
2421
2554
|
return files.map((filePath) => {
|
|
2422
2555
|
const resolvedPath = path.resolve(filePath);
|
|
2423
2556
|
if (!fs.existsSync(resolvedPath)) {
|
|
2424
2557
|
throw new Error(`file does not exist: ${resolvedPath}`);
|
|
2425
2558
|
}
|
|
2426
|
-
const
|
|
2559
|
+
const realFilePath = fs.realpathSync(resolvedPath);
|
|
2560
|
+
const containingRoot = findContainingRoot(realFilePath, safeRoots);
|
|
2561
|
+
if (!containingRoot) {
|
|
2562
|
+
throw new Error(
|
|
2563
|
+
'file must be inside the browser session download directory or a CCS_BROWSER_UPLOAD_ROOTS entry'
|
|
2564
|
+
);
|
|
2565
|
+
}
|
|
2566
|
+
assertNoSensitiveLocalPathSegments(realFilePath, containingRoot, 'file');
|
|
2567
|
+
|
|
2568
|
+
const stat = fs.statSync(realFilePath);
|
|
2427
2569
|
if (!stat.isFile()) {
|
|
2428
|
-
throw new Error(`file is not a regular file: ${
|
|
2570
|
+
throw new Error(`file is not a regular file: ${realFilePath}`);
|
|
2571
|
+
}
|
|
2572
|
+
if (stat.size > MAX_LOCAL_TRANSFER_FILE_BYTES) {
|
|
2573
|
+
throw new Error(
|
|
2574
|
+
`file exceeds maximum size of ${MAX_LOCAL_TRANSFER_FILE_BYTES} bytes: ${realFilePath}`
|
|
2575
|
+
);
|
|
2429
2576
|
}
|
|
2430
|
-
return
|
|
2577
|
+
return realFilePath;
|
|
2431
2578
|
});
|
|
2432
2579
|
}
|
|
2433
2580
|
|