@wopr-network/defcon 1.2.1 → 1.3.0
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/src/api/server.d.ts
CHANGED
package/dist/src/api/server.js
CHANGED
|
@@ -282,8 +282,8 @@ export function createHttpServer(deps) {
|
|
|
282
282
|
const isLoopbackOrigin = /^https?:\/\/localhost(:\d+)?$/.test(origin) ||
|
|
283
283
|
/^https?:\/\/127\.0\.0\.1(:\d+)?$/.test(origin) ||
|
|
284
284
|
/^https?:\/\/\[::1\](:\d+)?$/.test(origin);
|
|
285
|
-
const corsAllowed = deps.
|
|
286
|
-
?
|
|
285
|
+
const corsAllowed = deps.corsOrigins
|
|
286
|
+
? deps.corsOrigins.includes(origin) // explicit origins: set membership check
|
|
287
287
|
: isLoopbackOrigin; // loopback mode: only reflect loopback origins
|
|
288
288
|
if (corsAllowed) {
|
|
289
289
|
res.setHeader("Vary", "Origin");
|
package/dist/src/cors.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export interface CorsOriginResult {
|
|
2
|
-
/** Explicit allowed
|
|
3
|
-
|
|
2
|
+
/** Explicit allowed origins, or null meaning "loopback-only default pattern" */
|
|
3
|
+
origins: string[] | null;
|
|
4
4
|
}
|
|
5
5
|
export declare function resolveCorsOrigin(opts: {
|
|
6
6
|
host: string;
|
package/dist/src/cors.js
CHANGED
|
@@ -2,20 +2,27 @@ const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1"]);
|
|
|
2
2
|
export function resolveCorsOrigin(opts) {
|
|
3
3
|
const corsValue = opts.corsEnv?.trim() || undefined;
|
|
4
4
|
const isLoopback = LOOPBACK_HOSTS.has(opts.host);
|
|
5
|
-
// If explicit
|
|
5
|
+
// If explicit origins provided, validate each and use them
|
|
6
6
|
if (corsValue) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const entries = corsValue
|
|
8
|
+
.split(",")
|
|
9
|
+
.map((s) => s.trim())
|
|
10
|
+
.filter(Boolean);
|
|
11
|
+
for (const entry of entries) {
|
|
12
|
+
if (!/^https?:\/\/[^/]+$/.test(entry)) {
|
|
13
|
+
throw new Error(`DEFCON_CORS_ORIGIN must be bare origins like https://app.example.com (comma-separated for multiple), not ${entry}. ` +
|
|
14
|
+
"Remove any path component or trailing slash.");
|
|
15
|
+
}
|
|
10
16
|
}
|
|
11
|
-
return {
|
|
17
|
+
return { origins: entries };
|
|
12
18
|
}
|
|
13
19
|
// Non-loopback without explicit origin — refuse to start
|
|
14
20
|
if (!isLoopback) {
|
|
15
21
|
throw new Error(`DEFCON_CORS_ORIGIN must be set when binding to non-loopback address "${opts.host}". ` +
|
|
16
22
|
"Without an explicit CORS origin, any website on the network can make cross-origin requests to this server. " +
|
|
17
|
-
'Set DEFCON_CORS_ORIGIN to the allowed origin (e.g. "https://my-app.example.com") or use a loopback address.'
|
|
23
|
+
'Set DEFCON_CORS_ORIGIN to the allowed origin (e.g. "https://my-app.example.com") or use a loopback address. ' +
|
|
24
|
+
"Multiple origins can be separated by commas.");
|
|
18
25
|
}
|
|
19
26
|
// Loopback without explicit origin — use default pattern
|
|
20
|
-
return {
|
|
27
|
+
return { origins: null };
|
|
21
28
|
}
|
|
@@ -243,7 +243,7 @@ program
|
|
|
243
243
|
mcpDeps: deps,
|
|
244
244
|
adminToken,
|
|
245
245
|
workerToken,
|
|
246
|
-
|
|
246
|
+
corsOrigins: restCorsResult.origins ?? undefined,
|
|
247
247
|
});
|
|
248
248
|
if (adminToken) {
|
|
249
249
|
const wsBroadcaster = new WebSocketBroadcaster({
|
|
@@ -278,16 +278,13 @@ program
|
|
|
278
278
|
sqlite.close();
|
|
279
279
|
process.exit(1);
|
|
280
280
|
}
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
: /^https?:\/\/(localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/; // loopback default
|
|
281
|
+
const allowedOriginSet = corsResult.origins ? new Set(corsResult.origins) : null;
|
|
282
|
+
const loopbackPattern = /^https?:\/\/(localhost|127\.0\.0\.1|\[::1\])(:\d+)?$/;
|
|
284
283
|
const httpServer = http.createServer(async (req, res) => {
|
|
285
284
|
// CORS: restrict to localhost origins when bound to loopback; require DEFCON_CORS_ORIGIN when bound to non-loopback
|
|
286
285
|
const origin = req.headers.origin;
|
|
287
286
|
if (origin) {
|
|
288
|
-
const originAllowed =
|
|
289
|
-
? origin === allowedOriginPattern
|
|
290
|
-
: allowedOriginPattern.test(origin);
|
|
287
|
+
const originAllowed = allowedOriginSet ? allowedOriginSet.has(origin) : loopbackPattern.test(origin);
|
|
291
288
|
if (originAllowed) {
|
|
292
289
|
res.setHeader("Vary", "Origin");
|
|
293
290
|
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
@@ -777,7 +777,7 @@ async function handleAdminFlowPause(deps, args) {
|
|
|
777
777
|
return jsonResult({ paused: true, flow: v.data.flow_name });
|
|
778
778
|
}
|
|
779
779
|
async function handleAdminFlowResume(deps, args) {
|
|
780
|
-
const v = validateInput(
|
|
780
|
+
const v = validateInput(AdminFlowRestoreSchema, args);
|
|
781
781
|
if (!v.ok)
|
|
782
782
|
return v.result;
|
|
783
783
|
const flow = await deps.flows.getByName(v.data.flow_name);
|