@spinabot/brigade 1.12.0 → 1.14.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/README.md +20 -0
- package/convex/logs.d.ts +3 -3
- package/convex/memory.d.ts +21 -21
- package/convex/schema.d.ts +9 -9
- package/convex/skills.d.ts +3 -3
- package/dist/buildstamp.json +1 -1
- package/dist/cli/commands/config-cmd.d.ts +12 -19
- package/dist/cli/commands/config-cmd.d.ts.map +1 -1
- package/dist/cli/commands/config-cmd.js +14 -197
- package/dist/cli/commands/config-cmd.js.map +1 -1
- package/dist/cli/commands/connect.d.ts +6 -0
- package/dist/cli/commands/connect.d.ts.map +1 -1
- package/dist/cli/commands/connect.js +7 -0
- package/dist/cli/commands/connect.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +2 -1
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/expose.d.ts.map +1 -1
- package/dist/cli/commands/expose.js +22 -3
- package/dist/cli/commands/expose.js.map +1 -1
- package/dist/cli/commands/gateway.d.ts +12 -0
- package/dist/cli/commands/gateway.d.ts.map +1 -1
- package/dist/cli/commands/gateway.js +114 -2
- package/dist/cli/commands/gateway.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +2 -1
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/program/build-program.d.ts.map +1 -1
- package/dist/cli/program/build-program.js +36 -0
- package/dist/cli/program/build-program.js.map +1 -1
- package/dist/config/io.d.ts +13 -0
- package/dist/config/io.d.ts.map +1 -1
- package/dist/config/io.js.map +1 -1
- package/dist/core/agents-crud-ops.d.ts +15 -0
- package/dist/core/agents-crud-ops.d.ts.map +1 -0
- package/dist/core/agents-crud-ops.js +27 -0
- package/dist/core/agents-crud-ops.js.map +1 -0
- package/dist/core/agents-ops.d.ts +43 -0
- package/dist/core/agents-ops.d.ts.map +1 -0
- package/dist/core/agents-ops.js +117 -0
- package/dist/core/agents-ops.js.map +1 -0
- package/dist/core/channels-ops.d.ts +30 -0
- package/dist/core/channels-ops.d.ts.map +1 -0
- package/dist/core/channels-ops.js +52 -0
- package/dist/core/channels-ops.js.map +1 -0
- package/dist/core/config-ops.d.ts +77 -0
- package/dist/core/config-ops.d.ts.map +1 -0
- package/dist/core/config-ops.js +241 -0
- package/dist/core/config-ops.js.map +1 -0
- package/dist/core/exec-ops.d.ts +48 -0
- package/dist/core/exec-ops.d.ts.map +1 -0
- package/dist/core/exec-ops.js +101 -0
- package/dist/core/exec-ops.js.map +1 -0
- package/dist/core/gateway-auth.d.ts +86 -0
- package/dist/core/gateway-auth.d.ts.map +1 -0
- package/dist/core/gateway-auth.js +156 -0
- package/dist/core/gateway-auth.js.map +1 -0
- package/dist/core/gateway-probe.d.ts +5 -0
- package/dist/core/gateway-probe.d.ts.map +1 -1
- package/dist/core/gateway-probe.js +2 -1
- package/dist/core/gateway-probe.js.map +1 -1
- package/dist/core/gateway-spawn.d.ts.map +1 -1
- package/dist/core/gateway-spawn.js +5 -2
- package/dist/core/gateway-spawn.js.map +1 -1
- package/dist/core/integrations-ops.d.ts +25 -0
- package/dist/core/integrations-ops.d.ts.map +1 -0
- package/dist/core/integrations-ops.js +40 -0
- package/dist/core/integrations-ops.js.map +1 -0
- package/dist/core/memory-ops.d.ts +20 -0
- package/dist/core/memory-ops.d.ts.map +1 -0
- package/dist/core/memory-ops.js +40 -0
- package/dist/core/memory-ops.js.map +1 -0
- package/dist/core/pairing-ops.d.ts +33 -0
- package/dist/core/pairing-ops.d.ts.map +1 -0
- package/dist/core/pairing-ops.js +78 -0
- package/dist/core/pairing-ops.js.map +1 -0
- package/dist/core/provider-ops.d.ts +17 -0
- package/dist/core/provider-ops.d.ts.map +1 -0
- package/dist/core/provider-ops.js +29 -0
- package/dist/core/provider-ops.js.map +1 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +112 -1
- package/dist/core/server.js.map +1 -1
- package/dist/core/sessions-ops.d.ts +25 -0
- package/dist/core/sessions-ops.d.ts.map +1 -0
- package/dist/core/sessions-ops.js +77 -0
- package/dist/core/sessions-ops.js.map +1 -0
- package/dist/core/skills-ops.d.ts +14 -0
- package/dist/core/skills-ops.d.ts.map +1 -0
- package/dist/core/skills-ops.js +28 -0
- package/dist/core/skills-ops.js.map +1 -0
- package/dist/core/tunnel/auth-proxy.d.ts +3 -2
- package/dist/core/tunnel/auth-proxy.d.ts.map +1 -1
- package/dist/core/tunnel/auth-proxy.js +8 -34
- package/dist/core/tunnel/auth-proxy.js.map +1 -1
- package/dist/core/tunnel/manager.d.ts +4 -2
- package/dist/core/tunnel/manager.d.ts.map +1 -1
- package/dist/core/tunnel/manager.js +3 -2
- package/dist/core/tunnel/manager.js.map +1 -1
- package/dist/protocol/methods.d.ts +478 -0
- package/dist/protocol/methods.d.ts.map +1 -1
- package/dist/tui/client.d.ts +8 -0
- package/dist/tui/client.d.ts.map +1 -1
- package/dist/tui/client.js +5 -1
- package/dist/tui/client.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-transcript hygiene behind the `sessions.cleanup` gateway RPC — the
|
|
3
|
+
* `brigade sessions cleanup --older-than <duration>` surface, reachable from a
|
|
4
|
+
* remote client.
|
|
5
|
+
*
|
|
6
|
+
* OPERATOR-SCOPED maintenance: deletes an agent's OWN idle transcript files
|
|
7
|
+
* (`~/.brigade/agents/<id>/sessions/<sid>.jsonl`). It does NOT read or disclose
|
|
8
|
+
* another agent's session CONTENT (unlike sessions.list/history/send, which are
|
|
9
|
+
* guarded) — it only removes stale files the gateway regenerates on next
|
|
10
|
+
* access. So no per-session access guard (allowlisted by name in the
|
|
11
|
+
* guard-sweep).
|
|
12
|
+
*/
|
|
13
|
+
/** Parse a duration like "30d" / "12h" / "2w" into milliseconds. */
|
|
14
|
+
export declare function parseDuration(s: string): number | null;
|
|
15
|
+
export interface SessionsCleanupResult {
|
|
16
|
+
ok: boolean;
|
|
17
|
+
agentId: string;
|
|
18
|
+
candidates: number;
|
|
19
|
+
deleted: number;
|
|
20
|
+
dryRun: boolean;
|
|
21
|
+
wouldDelete?: string[];
|
|
22
|
+
reason?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function handleSessionsCleanup(params: unknown): SessionsCleanupResult;
|
|
25
|
+
//# sourceMappingURL=sessions-ops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions-ops.d.ts","sourceRoot":"","sources":["../../src/core/sessions-ops.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA6BH,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOtD;AAED,MAAM,WAAW,qBAAqB;IACrC,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,qBAAqB,CA+B5E"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-transcript hygiene behind the `sessions.cleanup` gateway RPC — the
|
|
3
|
+
* `brigade sessions cleanup --older-than <duration>` surface, reachable from a
|
|
4
|
+
* remote client.
|
|
5
|
+
*
|
|
6
|
+
* OPERATOR-SCOPED maintenance: deletes an agent's OWN idle transcript files
|
|
7
|
+
* (`~/.brigade/agents/<id>/sessions/<sid>.jsonl`). It does NOT read or disclose
|
|
8
|
+
* another agent's session CONTENT (unlike sessions.list/history/send, which are
|
|
9
|
+
* guarded) — it only removes stale files the gateway regenerates on next
|
|
10
|
+
* access. So no per-session access guard (allowlisted by name in the
|
|
11
|
+
* guard-sweep).
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
14
|
+
import path from "node:path";
|
|
15
|
+
import { DEFAULT_AGENT_ID, resolveSessionsDir } from "../config/paths.js";
|
|
16
|
+
function listSessionFiles(agentId) {
|
|
17
|
+
const dir = resolveSessionsDir(agentId);
|
|
18
|
+
if (!existsSync(dir))
|
|
19
|
+
return [];
|
|
20
|
+
const rows = [];
|
|
21
|
+
for (const name of readdirSync(dir)) {
|
|
22
|
+
if (!name.endsWith(".jsonl"))
|
|
23
|
+
continue;
|
|
24
|
+
try {
|
|
25
|
+
const st = statSync(path.join(dir, name));
|
|
26
|
+
rows.push({ sessionId: name.replace(/\.jsonl$/, ""), bytes: st.size, mtimeMs: st.mtimeMs });
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
/* ignore unreadable entries */
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return rows;
|
|
33
|
+
}
|
|
34
|
+
/** Parse a duration like "30d" / "12h" / "2w" into milliseconds. */
|
|
35
|
+
export function parseDuration(s) {
|
|
36
|
+
const m = s.match(/^(\d+)\s*(s|m|h|d|w)$/i);
|
|
37
|
+
if (!m)
|
|
38
|
+
return null;
|
|
39
|
+
const n = Number(m[1]);
|
|
40
|
+
const u = m[2]?.toLowerCase() ?? "d";
|
|
41
|
+
const mul = { s: 1_000, m: 60_000, h: 3_600_000, d: 86_400_000, w: 604_800_000 }[u] ?? 0;
|
|
42
|
+
return n * mul;
|
|
43
|
+
}
|
|
44
|
+
export function handleSessionsCleanup(params) {
|
|
45
|
+
const p = (params ?? {});
|
|
46
|
+
const agentId = (p.agentId ?? "").trim() || DEFAULT_AGENT_ID;
|
|
47
|
+
const dryRun = !!p.dryRun;
|
|
48
|
+
const ms = parseDuration((p.olderThan ?? "").trim());
|
|
49
|
+
if (ms == null) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
agentId,
|
|
53
|
+
candidates: 0,
|
|
54
|
+
deleted: 0,
|
|
55
|
+
dryRun,
|
|
56
|
+
reason: `'olderThan' must look like "30d" / "12h" / "2w"`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const cutoff = Date.now() - ms;
|
|
60
|
+
const stale = listSessionFiles(agentId).filter((r) => r.mtimeMs < cutoff);
|
|
61
|
+
if (dryRun) {
|
|
62
|
+
return { ok: true, agentId, candidates: stale.length, deleted: 0, dryRun: true, wouldDelete: stale.map((r) => r.sessionId) };
|
|
63
|
+
}
|
|
64
|
+
const dir = resolveSessionsDir(agentId);
|
|
65
|
+
let deleted = 0;
|
|
66
|
+
for (const r of stale) {
|
|
67
|
+
try {
|
|
68
|
+
rmSync(path.join(dir, `${r.sessionId}.jsonl`), { force: true });
|
|
69
|
+
deleted++;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
/* best-effort — skip individual delete failures */
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { ok: true, agentId, candidates: stale.length, deleted, dryRun: false };
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=sessions-ops.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions-ops.js","sourceRoot":"","sources":["../../src/core/sessions-ops.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill authoring behind the `skills.create` / `skills.delete` /
|
|
3
|
+
* `skills.write-file` gateway RPCs — reachable from a remote client.
|
|
4
|
+
*
|
|
5
|
+
* Skills are SKILL.md files on disk (NOT config), so `config.set` can't author
|
|
6
|
+
* them; `skills.status`/`skills.install`/`skills.update` already cover read /
|
|
7
|
+
* install / enable. These close create/delete/support-file. Reuses the
|
|
8
|
+
* `manage_skill` tool (ctx-free execute, owner-gated via wrapper). Operator-
|
|
9
|
+
* scoped (no per-session guard — allowlisted in the guard-sweep).
|
|
10
|
+
*/
|
|
11
|
+
export declare function handleSkillsCreate(params: unknown): Promise<unknown>;
|
|
12
|
+
export declare function handleSkillsDelete(params: unknown): Promise<unknown>;
|
|
13
|
+
export declare function handleSkillsWriteFile(params: unknown): Promise<unknown>;
|
|
14
|
+
//# sourceMappingURL=skills-ops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-ops.d.ts","sourceRoot":"","sources":["../../src/core/skills-ops.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAaH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAE1E;AACD,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAE1E;AACD,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAE7E"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill authoring behind the `skills.create` / `skills.delete` /
|
|
3
|
+
* `skills.write-file` gateway RPCs — reachable from a remote client.
|
|
4
|
+
*
|
|
5
|
+
* Skills are SKILL.md files on disk (NOT config), so `config.set` can't author
|
|
6
|
+
* them; `skills.status`/`skills.install`/`skills.update` already cover read /
|
|
7
|
+
* install / enable. These close create/delete/support-file. Reuses the
|
|
8
|
+
* `manage_skill` tool (ctx-free execute, owner-gated via wrapper). Operator-
|
|
9
|
+
* scoped (no per-session guard — allowlisted in the guard-sweep).
|
|
10
|
+
*/
|
|
11
|
+
import { DEFAULT_AGENT_ID } from "../agents/routing/session-key.js";
|
|
12
|
+
import { makeManageSkillTool } from "../agents/tools/manage-skill-tool.js";
|
|
13
|
+
async function runManageSkill(args) {
|
|
14
|
+
const requesterAgentId = typeof args.agentId === "string" && args.agentId.trim().length > 0 ? args.agentId : DEFAULT_AGENT_ID;
|
|
15
|
+
const tool = makeManageSkillTool({ requesterAgentId });
|
|
16
|
+
const res = await tool.execute("gateway", args);
|
|
17
|
+
return res.details;
|
|
18
|
+
}
|
|
19
|
+
export async function handleSkillsCreate(params) {
|
|
20
|
+
return runManageSkill({ ...(params ?? {}), action: "create" });
|
|
21
|
+
}
|
|
22
|
+
export async function handleSkillsDelete(params) {
|
|
23
|
+
return runManageSkill({ ...(params ?? {}), action: "delete" });
|
|
24
|
+
}
|
|
25
|
+
export async function handleSkillsWriteFile(params) {
|
|
26
|
+
return runManageSkill({ ...(params ?? {}), action: "write_file" });
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=skills-ops.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-ops.js","sourceRoot":"","sources":["../../src/core/skills-ops.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,KAAK,UAAU,cAAc,CAAC,IAA6B;IAC1D,MAAM,gBAAgB,GACrB,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC;IACtG,MAAM,IAAI,GAAG,mBAAmB,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACvD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAa,CAAC,CAAC;IACzD,OAAO,GAAG,CAAC,OAAO,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAe;IACvD,OAAO,cAAc,CAAC,EAAE,GAAI,CAAC,MAAM,IAAI,EAAE,CAA6B,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC7F,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAe;IACvD,OAAO,cAAc,CAAC,EAAE,GAAI,CAAC,MAAM,IAAI,EAAE,CAA6B,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC7F,CAAC;AACD,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAe;IAC1D,OAAO,cAAc,CAAC,EAAE,GAAI,CAAC,MAAM,IAAI,EAAE,CAA6B,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;AACjG,CAAC"}
|
|
@@ -33,8 +33,9 @@ export interface AuthProxyOptions {
|
|
|
33
33
|
gatewayHost: string;
|
|
34
34
|
/** Gateway port to forward to. */
|
|
35
35
|
gatewayPort: number;
|
|
36
|
-
/**
|
|
37
|
-
|
|
36
|
+
/** Valid tokens — a client presenting ANY one is allowed through. Empty/omit
|
|
37
|
+
* → pass-through (insecure). Supersedes the former single `token`. */
|
|
38
|
+
tokens?: readonly string[];
|
|
38
39
|
/** Sink for proxy diagnostics. */
|
|
39
40
|
onLog?: (line: string) => void;
|
|
40
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-proxy.d.ts","sourceRoot":"","sources":["../../../src/core/tunnel/auth-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAOH,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB
|
|
1
|
+
{"version":3,"file":"auth-proxy.d.ts","sourceRoot":"","sources":["../../../src/core/tunnel/auth-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAOH,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB;2EACuE;IACvE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,kCAAkC;IAClC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,qEAAqE;IACrE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAMD;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA8GrF"}
|
|
@@ -30,50 +30,24 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import * as http from "node:http";
|
|
32
32
|
import * as net from "node:net";
|
|
33
|
-
import {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return false;
|
|
38
|
-
const a = Buffer.from(expected, "utf8");
|
|
39
|
-
const b = Buffer.from(provided, "utf8");
|
|
40
|
-
if (a.length !== b.length)
|
|
41
|
-
return false;
|
|
42
|
-
return timingSafeEqual(a, b);
|
|
43
|
-
}
|
|
44
|
-
/** Pull a candidate token from headers or the request URL. */
|
|
45
|
-
function extractToken(reqUrl, headers) {
|
|
46
|
-
const auth = headers["authorization"];
|
|
47
|
-
if (typeof auth === "string" && auth.toLowerCase().startsWith("bearer ")) {
|
|
48
|
-
return auth.slice(7).trim();
|
|
49
|
-
}
|
|
50
|
-
const hdr = headers["x-brigade-token"];
|
|
51
|
-
if (typeof hdr === "string" && hdr.length > 0)
|
|
52
|
-
return hdr;
|
|
53
|
-
if (reqUrl) {
|
|
54
|
-
const qIdx = reqUrl.indexOf("?");
|
|
55
|
-
if (qIdx >= 0) {
|
|
56
|
-
const params = new URLSearchParams(reqUrl.slice(qIdx + 1));
|
|
57
|
-
const t = params.get("token");
|
|
58
|
-
if (t)
|
|
59
|
-
return t;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return undefined;
|
|
63
|
-
}
|
|
33
|
+
import { extractToken, matchesAnyToken } from "../gateway-auth.js";
|
|
34
|
+
// Token extraction + constant-time matching live in `core/gateway-auth.ts` so
|
|
35
|
+
// the expose proxy and the gateway's own connection gate share ONE
|
|
36
|
+
// implementation and can never drift.
|
|
64
37
|
/**
|
|
65
38
|
* Start the auth-proxy. Resolves once it is listening; the returned handle
|
|
66
39
|
* carries the chosen port. The proxy lives until `stop()` (or the process
|
|
67
40
|
* exits).
|
|
68
41
|
*/
|
|
69
42
|
export async function startAuthProxy(opts) {
|
|
70
|
-
const { gatewayHost, gatewayPort,
|
|
71
|
-
const
|
|
43
|
+
const { gatewayHost, gatewayPort, tokens, onLog } = opts;
|
|
44
|
+
const tokenList = tokens ?? [];
|
|
45
|
+
const secured = tokenList.length > 0;
|
|
72
46
|
const sockets = new Set();
|
|
73
47
|
const authorize = (reqUrl, headers) => {
|
|
74
48
|
if (!secured)
|
|
75
49
|
return true;
|
|
76
|
-
return
|
|
50
|
+
return matchesAnyToken(tokenList, extractToken(reqUrl, headers));
|
|
77
51
|
};
|
|
78
52
|
const server = http.createServer((req, res) => {
|
|
79
53
|
// Plain HTTP request path. The gateway is WS-first, but a few HTTP routes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-proxy.js","sourceRoot":"","sources":["../../../src/core/tunnel/auth-proxy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"auth-proxy.js","sourceRoot":"","sources":["../../../src/core/tunnel/auth-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,8 +16,10 @@ export interface StartTunnelOptions {
|
|
|
16
16
|
/** Gateway host/port the auth-proxy forwards to. */
|
|
17
17
|
gatewayHost: string;
|
|
18
18
|
gatewayPort: number;
|
|
19
|
-
/**
|
|
20
|
-
|
|
19
|
+
/** Tokens gating the public URL — a client presenting ANY one is allowed.
|
|
20
|
+
* The first is appended to the shared URL (`?token=`). Empty/omit → insecure
|
|
21
|
+
* pass-through. */
|
|
22
|
+
tokens?: readonly string[];
|
|
21
23
|
/** Self-hosted relay (`bore` / `custom`). */
|
|
22
24
|
relay?: string;
|
|
23
25
|
/** `custom` provider command template. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/core/tunnel/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/core/tunnel/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB;;wBAEoB;IACpB,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAQD,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC,CAyElF"}
|
|
@@ -38,7 +38,7 @@ export async function startTunnel(opts) {
|
|
|
38
38
|
proxy = await startAuthProxy({
|
|
39
39
|
gatewayHost: opts.gatewayHost,
|
|
40
40
|
gatewayPort: opts.gatewayPort,
|
|
41
|
-
|
|
41
|
+
tokens: opts.tokens,
|
|
42
42
|
onLog: opts.onLog,
|
|
43
43
|
});
|
|
44
44
|
handle = await provider.start({
|
|
@@ -50,7 +50,8 @@ export async function startTunnel(opts) {
|
|
|
50
50
|
});
|
|
51
51
|
const secured = proxy.secured;
|
|
52
52
|
const url = handle.url;
|
|
53
|
-
const
|
|
53
|
+
const shareToken = opts.tokens?.[0];
|
|
54
|
+
const urlWithToken = secured && shareToken ? withToken(url, shareToken) : url;
|
|
54
55
|
await writeTunnelState({
|
|
55
56
|
url,
|
|
56
57
|
urlWithToken,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/core/tunnel/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,cAAc,EAAwB,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/core/tunnel/manager.ts"],"names":[],"mappings":"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"}
|