@spinabot/brigade 1.7.0 → 1.9.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 +19 -0
- package/dist/agents/agent-loop.d.ts +13 -0
- package/dist/agents/agent-loop.d.ts.map +1 -1
- package/dist/agents/agent-loop.js +5 -0
- package/dist/agents/agent-loop.js.map +1 -1
- package/dist/agents/channels/access-control/group-tool-policy.d.ts +73 -0
- package/dist/agents/channels/access-control/group-tool-policy.d.ts.map +1 -0
- package/dist/agents/channels/access-control/group-tool-policy.js +193 -0
- package/dist/agents/channels/access-control/group-tool-policy.js.map +1 -0
- package/dist/agents/channels/access-control/index.d.ts +1 -0
- package/dist/agents/channels/access-control/index.d.ts.map +1 -1
- package/dist/agents/channels/access-control/index.js +1 -0
- package/dist/agents/channels/access-control/index.js.map +1 -1
- package/dist/agents/channels/bluebubbles/account-config.d.ts +253 -0
- package/dist/agents/channels/bluebubbles/account-config.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/account-config.js +486 -0
- package/dist/agents/channels/bluebubbles/account-config.js.map +1 -0
- package/dist/agents/channels/bluebubbles/account-registry.d.ts +33 -0
- package/dist/agents/channels/bluebubbles/account-registry.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/account-registry.js +46 -0
- package/dist/agents/channels/bluebubbles/account-registry.js.map +1 -0
- package/dist/agents/channels/bluebubbles/adapter.d.ts +45 -0
- package/dist/agents/channels/bluebubbles/adapter.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/adapter.js +366 -0
- package/dist/agents/channels/bluebubbles/adapter.js.map +1 -0
- package/dist/agents/channels/bluebubbles/catchup-cursor.d.ts +52 -0
- package/dist/agents/channels/bluebubbles/catchup-cursor.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/catchup-cursor.js +118 -0
- package/dist/agents/channels/bluebubbles/catchup-cursor.js.map +1 -0
- package/dist/agents/channels/bluebubbles/catchup.d.ts +114 -0
- package/dist/agents/channels/bluebubbles/catchup.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/catchup.js +220 -0
- package/dist/agents/channels/bluebubbles/catchup.js.map +1 -0
- package/dist/agents/channels/bluebubbles/chat.d.ts +75 -0
- package/dist/agents/channels/bluebubbles/chat.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/chat.js +182 -0
- package/dist/agents/channels/bluebubbles/chat.js.map +1 -0
- package/dist/agents/channels/bluebubbles/connection.d.ts +95 -0
- package/dist/agents/channels/bluebubbles/connection.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/connection.js +413 -0
- package/dist/agents/channels/bluebubbles/connection.js.map +1 -0
- package/dist/agents/channels/bluebubbles/contact-names.d.ts +79 -0
- package/dist/agents/channels/bluebubbles/contact-names.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/contact-names.js +188 -0
- package/dist/agents/channels/bluebubbles/contact-names.js.map +1 -0
- package/dist/agents/channels/bluebubbles/debounce.d.ts +78 -0
- package/dist/agents/channels/bluebubbles/debounce.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/debounce.js +173 -0
- package/dist/agents/channels/bluebubbles/debounce.js.map +1 -0
- package/dist/agents/channels/bluebubbles/dedupe.d.ts +25 -0
- package/dist/agents/channels/bluebubbles/dedupe.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/dedupe.js +35 -0
- package/dist/agents/channels/bluebubbles/dedupe.js.map +1 -0
- package/dist/agents/channels/bluebubbles/effects.d.ts +17 -0
- package/dist/agents/channels/bluebubbles/effects.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/effects.js +57 -0
- package/dist/agents/channels/bluebubbles/effects.js.map +1 -0
- package/dist/agents/channels/bluebubbles/history.d.ts +56 -0
- package/dist/agents/channels/bluebubbles/history.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/history.js +140 -0
- package/dist/agents/channels/bluebubbles/history.js.map +1 -0
- package/dist/agents/channels/bluebubbles/index.d.ts +18 -0
- package/dist/agents/channels/bluebubbles/index.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/index.js +18 -0
- package/dist/agents/channels/bluebubbles/index.js.map +1 -0
- package/dist/agents/channels/bluebubbles/media.d.ts +104 -0
- package/dist/agents/channels/bluebubbles/media.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/media.js +222 -0
- package/dist/agents/channels/bluebubbles/media.js.map +1 -0
- package/dist/agents/channels/bluebubbles/messaging.d.ts +13 -0
- package/dist/agents/channels/bluebubbles/messaging.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/messaging.js +36 -0
- package/dist/agents/channels/bluebubbles/messaging.js.map +1 -0
- package/dist/agents/channels/bluebubbles/module.d.ts +24 -0
- package/dist/agents/channels/bluebubbles/module.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/module.js +52 -0
- package/dist/agents/channels/bluebubbles/module.js.map +1 -0
- package/dist/agents/channels/bluebubbles/normalize.d.ts +111 -0
- package/dist/agents/channels/bluebubbles/normalize.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/normalize.js +239 -0
- package/dist/agents/channels/bluebubbles/normalize.js.map +1 -0
- package/dist/agents/channels/bluebubbles/plugin.d.ts +46 -0
- package/dist/agents/channels/bluebubbles/plugin.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/plugin.js +242 -0
- package/dist/agents/channels/bluebubbles/plugin.js.map +1 -0
- package/dist/agents/channels/bluebubbles/probe.d.ts +79 -0
- package/dist/agents/channels/bluebubbles/probe.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/probe.js +138 -0
- package/dist/agents/channels/bluebubbles/probe.js.map +1 -0
- package/dist/agents/channels/bluebubbles/reactions.d.ts +46 -0
- package/dist/agents/channels/bluebubbles/reactions.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/reactions.js +207 -0
- package/dist/agents/channels/bluebubbles/reactions.js.map +1 -0
- package/dist/agents/channels/bluebubbles/send.d.ts +132 -0
- package/dist/agents/channels/bluebubbles/send.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/send.js +327 -0
- package/dist/agents/channels/bluebubbles/send.js.map +1 -0
- package/dist/agents/channels/bluebubbles/status-issues.d.ts +57 -0
- package/dist/agents/channels/bluebubbles/status-issues.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/status-issues.js +93 -0
- package/dist/agents/channels/bluebubbles/status-issues.js.map +1 -0
- package/dist/agents/channels/bluebubbles/types.d.ts +69 -0
- package/dist/agents/channels/bluebubbles/types.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/types.js +118 -0
- package/dist/agents/channels/bluebubbles/types.js.map +1 -0
- package/dist/agents/channels/bluebubbles/webhook.d.ts +97 -0
- package/dist/agents/channels/bluebubbles/webhook.d.ts.map +1 -0
- package/dist/agents/channels/bluebubbles/webhook.js +249 -0
- package/dist/agents/channels/bluebubbles/webhook.js.map +1 -0
- package/dist/agents/channels/bundled-channel-metas.d.ts +13 -0
- package/dist/agents/channels/bundled-channel-metas.d.ts.map +1 -1
- package/dist/agents/channels/bundled-channel-metas.js +33 -0
- package/dist/agents/channels/bundled-channel-metas.js.map +1 -1
- package/dist/agents/channels/imessage/account-config.d.ts +178 -0
- package/dist/agents/channels/imessage/account-config.d.ts.map +1 -0
- package/dist/agents/channels/imessage/account-config.js +371 -0
- package/dist/agents/channels/imessage/account-config.js.map +1 -0
- package/dist/agents/channels/imessage/adapter.d.ts +36 -0
- package/dist/agents/channels/imessage/adapter.d.ts.map +1 -0
- package/dist/agents/channels/imessage/adapter.js +286 -0
- package/dist/agents/channels/imessage/adapter.js.map +1 -0
- package/dist/agents/channels/imessage/client.d.ts +99 -0
- package/dist/agents/channels/imessage/client.d.ts.map +1 -0
- package/dist/agents/channels/imessage/client.js +231 -0
- package/dist/agents/channels/imessage/client.js.map +1 -0
- package/dist/agents/channels/imessage/connection.d.ts +101 -0
- package/dist/agents/channels/imessage/connection.d.ts.map +1 -0
- package/dist/agents/channels/imessage/connection.js +367 -0
- package/dist/agents/channels/imessage/connection.js.map +1 -0
- package/dist/agents/channels/imessage/format.d.ts +45 -0
- package/dist/agents/channels/imessage/format.d.ts.map +1 -0
- package/dist/agents/channels/imessage/format.js +170 -0
- package/dist/agents/channels/imessage/format.js.map +1 -0
- package/dist/agents/channels/imessage/history.d.ts +49 -0
- package/dist/agents/channels/imessage/history.d.ts.map +1 -0
- package/dist/agents/channels/imessage/history.js +74 -0
- package/dist/agents/channels/imessage/history.js.map +1 -0
- package/dist/agents/channels/imessage/index.d.ts +25 -0
- package/dist/agents/channels/imessage/index.d.ts.map +1 -0
- package/dist/agents/channels/imessage/index.js +25 -0
- package/dist/agents/channels/imessage/index.js.map +1 -0
- package/dist/agents/channels/imessage/media.d.ts +92 -0
- package/dist/agents/channels/imessage/media.d.ts.map +1 -0
- package/dist/agents/channels/imessage/media.js +196 -0
- package/dist/agents/channels/imessage/media.js.map +1 -0
- package/dist/agents/channels/imessage/messaging.d.ts +14 -0
- package/dist/agents/channels/imessage/messaging.d.ts.map +1 -0
- package/dist/agents/channels/imessage/messaging.js +37 -0
- package/dist/agents/channels/imessage/messaging.js.map +1 -0
- package/dist/agents/channels/imessage/module.d.ts +16 -0
- package/dist/agents/channels/imessage/module.d.ts.map +1 -0
- package/dist/agents/channels/imessage/module.js +23 -0
- package/dist/agents/channels/imessage/module.js.map +1 -0
- package/dist/agents/channels/imessage/monitor.d.ts +207 -0
- package/dist/agents/channels/imessage/monitor.d.ts.map +1 -0
- package/dist/agents/channels/imessage/monitor.js +504 -0
- package/dist/agents/channels/imessage/monitor.js.map +1 -0
- package/dist/agents/channels/imessage/plugin.d.ts +53 -0
- package/dist/agents/channels/imessage/plugin.d.ts.map +1 -0
- package/dist/agents/channels/imessage/plugin.js +215 -0
- package/dist/agents/channels/imessage/plugin.js.map +1 -0
- package/dist/agents/channels/imessage/probe.d.ts +68 -0
- package/dist/agents/channels/imessage/probe.d.ts.map +1 -0
- package/dist/agents/channels/imessage/probe.js +134 -0
- package/dist/agents/channels/imessage/probe.js.map +1 -0
- package/dist/agents/channels/imessage/remote-attachments.d.ts +61 -0
- package/dist/agents/channels/imessage/remote-attachments.d.ts.map +1 -0
- package/dist/agents/channels/imessage/remote-attachments.js +131 -0
- package/dist/agents/channels/imessage/remote-attachments.js.map +1 -0
- package/dist/agents/channels/imessage/send.d.ts +61 -0
- package/dist/agents/channels/imessage/send.d.ts.map +1 -0
- package/dist/agents/channels/imessage/send.js +108 -0
- package/dist/agents/channels/imessage/send.js.map +1 -0
- package/dist/agents/channels/imessage/targets.d.ts +91 -0
- package/dist/agents/channels/imessage/targets.d.ts.map +1 -0
- package/dist/agents/channels/imessage/targets.js +245 -0
- package/dist/agents/channels/imessage/targets.js.map +1 -0
- package/dist/agents/channels/imessage/watch-error.d.ts +23 -0
- package/dist/agents/channels/imessage/watch-error.d.ts.map +1 -0
- package/dist/agents/channels/imessage/watch-error.js +69 -0
- package/dist/agents/channels/imessage/watch-error.js.map +1 -0
- package/dist/agents/channels/inbound-pipeline.d.ts +11 -0
- package/dist/agents/channels/inbound-pipeline.d.ts.map +1 -1
- package/dist/agents/channels/inbound-pipeline.js +20 -1
- package/dist/agents/channels/inbound-pipeline.js.map +1 -1
- package/dist/agents/channels/manager.d.ts +9 -0
- package/dist/agents/channels/manager.d.ts.map +1 -1
- package/dist/agents/channels/manager.js.map +1 -1
- package/dist/agents/channels/sdk.d.ts +4 -0
- package/dist/agents/channels/sdk.d.ts.map +1 -1
- package/dist/agents/channels/sdk.js +4 -0
- package/dist/agents/channels/sdk.js.map +1 -1
- package/dist/agents/extensions/modules/index.d.ts.map +1 -1
- package/dist/agents/extensions/modules/index.js +12 -0
- package/dist/agents/extensions/modules/index.js.map +1 -1
- package/dist/agents/session-wiring.d.ts +31 -0
- package/dist/agents/session-wiring.d.ts.map +1 -1
- package/dist/agents/session-wiring.js +45 -2
- package/dist/agents/session-wiring.js.map +1 -1
- package/dist/agents/tools/bluebubbles-action-tool.d.ts +66 -0
- package/dist/agents/tools/bluebubbles-action-tool.d.ts.map +1 -0
- package/dist/agents/tools/bluebubbles-action-tool.js +234 -0
- package/dist/agents/tools/bluebubbles-action-tool.js.map +1 -0
- package/dist/agents/tools/registry.d.ts.map +1 -1
- package/dist/agents/tools/registry.js +18 -0
- package/dist/agents/tools/registry.js.map +1 -1
- package/dist/buildstamp.json +1 -1
- package/dist/cli/commands/expose.d.ts +40 -0
- package/dist/cli/commands/expose.d.ts.map +1 -0
- package/dist/cli/commands/expose.js +200 -0
- package/dist/cli/commands/expose.js.map +1 -0
- package/dist/cli/program/build-program.d.ts.map +1 -1
- package/dist/cli/program/build-program.js +61 -0
- package/dist/cli/program/build-program.js.map +1 -1
- package/dist/config/io.d.ts +41 -0
- package/dist/config/io.d.ts.map +1 -1
- package/dist/config/io.js.map +1 -1
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +48 -2
- package/dist/core/server.js.map +1 -1
- package/dist/core/tunnel/auth-proxy.d.ts +55 -0
- package/dist/core/tunnel/auth-proxy.d.ts.map +1 -0
- package/dist/core/tunnel/auth-proxy.js +179 -0
- package/dist/core/tunnel/auth-proxy.js.map +1 -0
- package/dist/core/tunnel/manager.d.ts +42 -0
- package/dist/core/tunnel/manager.d.ts.map +1 -0
- package/dist/core/tunnel/manager.js +102 -0
- package/dist/core/tunnel/manager.js.map +1 -0
- package/dist/core/tunnel/providers/bore.d.ts +18 -0
- package/dist/core/tunnel/providers/bore.d.ts.map +1 -0
- package/dist/core/tunnel/providers/bore.js +117 -0
- package/dist/core/tunnel/providers/bore.js.map +1 -0
- package/dist/core/tunnel/providers/cloudflared.d.ts +24 -0
- package/dist/core/tunnel/providers/cloudflared.d.ts.map +1 -0
- package/dist/core/tunnel/providers/cloudflared.js +179 -0
- package/dist/core/tunnel/providers/cloudflared.js.map +1 -0
- package/dist/core/tunnel/providers/custom.d.ts +21 -0
- package/dist/core/tunnel/providers/custom.d.ts.map +1 -0
- package/dist/core/tunnel/providers/custom.js +124 -0
- package/dist/core/tunnel/providers/custom.js.map +1 -0
- package/dist/core/tunnel/registry.d.ts +15 -0
- package/dist/core/tunnel/registry.d.ts.map +1 -0
- package/dist/core/tunnel/registry.js +26 -0
- package/dist/core/tunnel/registry.js.map +1 -0
- package/dist/core/tunnel/state.d.ts +39 -0
- package/dist/core/tunnel/state.d.ts.map +1 -0
- package/dist/core/tunnel/state.js +57 -0
- package/dist/core/tunnel/state.js.map +1 -0
- package/dist/core/tunnel/types.d.ts +61 -0
- package/dist/core/tunnel/types.d.ts.map +1 -0
- package/dist/core/tunnel/types.js +20 -0
- package/dist/core/tunnel/types.js.map +1 -0
- package/dist/infra/net/fetch-guard.d.ts +24 -2
- package/dist/infra/net/fetch-guard.d.ts.map +1 -1
- package/dist/infra/net/fetch-guard.js +78 -31
- package/dist/infra/net/fetch-guard.js.map +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-checking reverse proxy that fronts the gateway for `brigade expose`.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS — the gateway WebSocket is UNAUTHENTICATED: every connection
|
|
5
|
+
* is granted full `operator.admin` scope (see `core/server.ts` connection
|
|
6
|
+
* handler). The only thing protecting it today is the hard localhost-bind
|
|
7
|
+
* guard in `startServer`. Tunnelling the raw gateway to the internet would
|
|
8
|
+
* therefore publish full agent control to anyone who learns the URL.
|
|
9
|
+
*
|
|
10
|
+
* Rather than bolt auth onto the security-sensitive gateway connection path
|
|
11
|
+
* (and force every local client to start sending a token), `expose` keeps the
|
|
12
|
+
* gateway exactly as-is and publishes THIS proxy instead. The proxy:
|
|
13
|
+
* 1. binds to 127.0.0.1 on an ephemeral port,
|
|
14
|
+
* 2. requires a bearer token on every HTTP request AND every WS upgrade,
|
|
15
|
+
* 3. forwards authed traffic to 127.0.0.1:<gatewayPort>.
|
|
16
|
+
*
|
|
17
|
+
* The tunnel client connects to this proxy; the gateway never sees an
|
|
18
|
+
* unauthenticated remote. This is precisely the "front the gateway with a
|
|
19
|
+
* reverse-proxy that adds your own auth" path the gateway's own guard
|
|
20
|
+
* recommends.
|
|
21
|
+
*
|
|
22
|
+
* Token may arrive three ways (so browsers, CLIs, and WS clients all work):
|
|
23
|
+
* - `Authorization: Bearer <token>`
|
|
24
|
+
* - `x-brigade-token: <token>` header
|
|
25
|
+
* - `?token=<token>` query string (the form the printed public URL uses)
|
|
26
|
+
*
|
|
27
|
+
* When started WITHOUT a token (`brigade expose --insecure`) the proxy is a
|
|
28
|
+
* plain pass-through — every byte reaches the gateway. That mode is gated
|
|
29
|
+
* behind an explicit flag + a loud warning in the CLI.
|
|
30
|
+
*/
|
|
31
|
+
export interface AuthProxyOptions {
|
|
32
|
+
/** Gateway host to forward to (loopback). */
|
|
33
|
+
gatewayHost: string;
|
|
34
|
+
/** Gateway port to forward to. */
|
|
35
|
+
gatewayPort: number;
|
|
36
|
+
/** Required bearer token. `undefined`/empty → pass-through (insecure). */
|
|
37
|
+
token?: string;
|
|
38
|
+
/** Sink for proxy diagnostics. */
|
|
39
|
+
onLog?: (line: string) => void;
|
|
40
|
+
}
|
|
41
|
+
export interface AuthProxyHandle {
|
|
42
|
+
/** Loopback port the proxy is listening on. */
|
|
43
|
+
port: number;
|
|
44
|
+
/** Whether a token gate is active. */
|
|
45
|
+
secured: boolean;
|
|
46
|
+
/** Stop accepting connections and close the listener. Idempotent. */
|
|
47
|
+
stop(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Start the auth-proxy. Resolves once it is listening; the returned handle
|
|
51
|
+
* carries the chosen port. The proxy lives until `stop()` (or the process
|
|
52
|
+
* exits).
|
|
53
|
+
*/
|
|
54
|
+
export declare function startAuthProxy(opts: AuthProxyOptions): Promise<AuthProxyHandle>;
|
|
55
|
+
//# sourceMappingURL=auth-proxy.d.ts.map
|
|
@@ -0,0 +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,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,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;AA8BD;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CA6GrF"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-checking reverse proxy that fronts the gateway for `brigade expose`.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS — the gateway WebSocket is UNAUTHENTICATED: every connection
|
|
5
|
+
* is granted full `operator.admin` scope (see `core/server.ts` connection
|
|
6
|
+
* handler). The only thing protecting it today is the hard localhost-bind
|
|
7
|
+
* guard in `startServer`. Tunnelling the raw gateway to the internet would
|
|
8
|
+
* therefore publish full agent control to anyone who learns the URL.
|
|
9
|
+
*
|
|
10
|
+
* Rather than bolt auth onto the security-sensitive gateway connection path
|
|
11
|
+
* (and force every local client to start sending a token), `expose` keeps the
|
|
12
|
+
* gateway exactly as-is and publishes THIS proxy instead. The proxy:
|
|
13
|
+
* 1. binds to 127.0.0.1 on an ephemeral port,
|
|
14
|
+
* 2. requires a bearer token on every HTTP request AND every WS upgrade,
|
|
15
|
+
* 3. forwards authed traffic to 127.0.0.1:<gatewayPort>.
|
|
16
|
+
*
|
|
17
|
+
* The tunnel client connects to this proxy; the gateway never sees an
|
|
18
|
+
* unauthenticated remote. This is precisely the "front the gateway with a
|
|
19
|
+
* reverse-proxy that adds your own auth" path the gateway's own guard
|
|
20
|
+
* recommends.
|
|
21
|
+
*
|
|
22
|
+
* Token may arrive three ways (so browsers, CLIs, and WS clients all work):
|
|
23
|
+
* - `Authorization: Bearer <token>`
|
|
24
|
+
* - `x-brigade-token: <token>` header
|
|
25
|
+
* - `?token=<token>` query string (the form the printed public URL uses)
|
|
26
|
+
*
|
|
27
|
+
* When started WITHOUT a token (`brigade expose --insecure`) the proxy is a
|
|
28
|
+
* plain pass-through — every byte reaches the gateway. That mode is gated
|
|
29
|
+
* behind an explicit flag + a loud warning in the CLI.
|
|
30
|
+
*/
|
|
31
|
+
import * as http from "node:http";
|
|
32
|
+
import * as net from "node:net";
|
|
33
|
+
import { timingSafeEqual } from "node:crypto";
|
|
34
|
+
/** Constant-time token comparison that never throws on length mismatch. */
|
|
35
|
+
function tokenMatches(expected, provided) {
|
|
36
|
+
if (!provided)
|
|
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
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Start the auth-proxy. Resolves once it is listening; the returned handle
|
|
66
|
+
* carries the chosen port. The proxy lives until `stop()` (or the process
|
|
67
|
+
* exits).
|
|
68
|
+
*/
|
|
69
|
+
export async function startAuthProxy(opts) {
|
|
70
|
+
const { gatewayHost, gatewayPort, token, onLog } = opts;
|
|
71
|
+
const secured = typeof token === "string" && token.length > 0;
|
|
72
|
+
const sockets = new Set();
|
|
73
|
+
const authorize = (reqUrl, headers) => {
|
|
74
|
+
if (!secured)
|
|
75
|
+
return true;
|
|
76
|
+
return tokenMatches(token, extractToken(reqUrl, headers));
|
|
77
|
+
};
|
|
78
|
+
const server = http.createServer((req, res) => {
|
|
79
|
+
// Plain HTTP request path. The gateway is WS-first, but a few HTTP routes
|
|
80
|
+
// exist (plugin httpRoutes, health). Gate then forward verbatim.
|
|
81
|
+
if (!authorize(req.url, req.headers)) {
|
|
82
|
+
res.writeHead(401, { "content-type": "text/plain", "www-authenticate": "Bearer" });
|
|
83
|
+
res.end("401 Unauthorized — append ?token=<token> or send Authorization: Bearer <token>\n");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const upstream = http.request({
|
|
87
|
+
host: gatewayHost,
|
|
88
|
+
port: gatewayPort,
|
|
89
|
+
method: req.method,
|
|
90
|
+
path: req.url,
|
|
91
|
+
headers: req.headers,
|
|
92
|
+
}, (upRes) => {
|
|
93
|
+
res.writeHead(upRes.statusCode ?? 502, upRes.headers);
|
|
94
|
+
upRes.pipe(res);
|
|
95
|
+
});
|
|
96
|
+
upstream.on("error", (err) => {
|
|
97
|
+
onLog?.(`http upstream error: ${err.message}`);
|
|
98
|
+
if (!res.headersSent)
|
|
99
|
+
res.writeHead(502, { "content-type": "text/plain" });
|
|
100
|
+
res.end("502 Bad Gateway\n");
|
|
101
|
+
});
|
|
102
|
+
req.pipe(upstream);
|
|
103
|
+
});
|
|
104
|
+
// WebSocket (and any other Upgrade) path — the primary traffic. We can't use
|
|
105
|
+
// the parsed `req` to forward, so reconstruct the raw HTTP upgrade request
|
|
106
|
+
// from `req.rawHeaders` and pipe both directions at the socket level.
|
|
107
|
+
server.on("upgrade", (req, clientSocket, head) => {
|
|
108
|
+
sockets.add(clientSocket);
|
|
109
|
+
clientSocket.on("close", () => sockets.delete(clientSocket));
|
|
110
|
+
if (!authorize(req.url, req.headers)) {
|
|
111
|
+
clientSocket.write("HTTP/1.1 401 Unauthorized\r\n" +
|
|
112
|
+
"Connection: close\r\n" +
|
|
113
|
+
"WWW-Authenticate: Bearer\r\n" +
|
|
114
|
+
"Content-Length: 0\r\n\r\n");
|
|
115
|
+
clientSocket.destroy();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const upstream = net.connect(gatewayPort, gatewayHost, () => {
|
|
119
|
+
// Replay the upgrade request line + headers, then any buffered head.
|
|
120
|
+
const lines = [`${req.method} ${req.url} HTTP/${req.httpVersion}`];
|
|
121
|
+
for (let i = 0; i < req.rawHeaders.length; i += 2) {
|
|
122
|
+
lines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`);
|
|
123
|
+
}
|
|
124
|
+
upstream.write(lines.join("\r\n") + "\r\n\r\n");
|
|
125
|
+
if (head && head.length > 0)
|
|
126
|
+
upstream.write(head);
|
|
127
|
+
clientSocket.pipe(upstream);
|
|
128
|
+
upstream.pipe(clientSocket);
|
|
129
|
+
});
|
|
130
|
+
const teardown = () => {
|
|
131
|
+
try {
|
|
132
|
+
clientSocket.destroy();
|
|
133
|
+
}
|
|
134
|
+
catch { /* ignore */ }
|
|
135
|
+
try {
|
|
136
|
+
upstream.destroy();
|
|
137
|
+
}
|
|
138
|
+
catch { /* ignore */ }
|
|
139
|
+
};
|
|
140
|
+
upstream.on("error", (err) => {
|
|
141
|
+
onLog?.(`ws upstream error: ${err.message}`);
|
|
142
|
+
teardown();
|
|
143
|
+
});
|
|
144
|
+
clientSocket.on("error", teardown);
|
|
145
|
+
});
|
|
146
|
+
await new Promise((resolve, reject) => {
|
|
147
|
+
const onError = (err) => reject(err);
|
|
148
|
+
server.once("error", onError);
|
|
149
|
+
// Port 0 → OS assigns an ephemeral port. Bound to loopback only.
|
|
150
|
+
server.listen(0, "127.0.0.1", () => {
|
|
151
|
+
server.removeListener("error", onError);
|
|
152
|
+
resolve();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
const address = server.address();
|
|
156
|
+
const port = typeof address === "object" && address ? address.port : 0;
|
|
157
|
+
if (!port)
|
|
158
|
+
throw new Error("auth-proxy failed to acquire a local port");
|
|
159
|
+
onLog?.(`auth-proxy listening on 127.0.0.1:${port} → ${gatewayHost}:${gatewayPort} (${secured ? "token-gated" : "OPEN/insecure"})`);
|
|
160
|
+
let stopped = false;
|
|
161
|
+
return {
|
|
162
|
+
port,
|
|
163
|
+
secured,
|
|
164
|
+
async stop() {
|
|
165
|
+
if (stopped)
|
|
166
|
+
return;
|
|
167
|
+
stopped = true;
|
|
168
|
+
for (const s of sockets) {
|
|
169
|
+
try {
|
|
170
|
+
s.destroy();
|
|
171
|
+
}
|
|
172
|
+
catch { /* ignore */ }
|
|
173
|
+
}
|
|
174
|
+
sockets.clear();
|
|
175
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=auth-proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-proxy.js","sourceRoot":"","sources":["../../../src/core/tunnel/auth-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tunnel manager — wires the auth-proxy + a provider into one running tunnel
|
|
3
|
+
* and records its state.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. start the token-checking auth-proxy in front of the gateway
|
|
7
|
+
* 2. start the chosen provider, pointing it at the auth-proxy's local port
|
|
8
|
+
* 3. compose the public URL (with `?token=` when secured) + persist state
|
|
9
|
+
*
|
|
10
|
+
* `stop()` tears down provider then proxy and clears the state file. The
|
|
11
|
+
* gateway is never touched — it keeps running localhost-only.
|
|
12
|
+
*/
|
|
13
|
+
export interface StartTunnelOptions {
|
|
14
|
+
/** Provider name (resolved through the registry). */
|
|
15
|
+
provider: string;
|
|
16
|
+
/** Gateway host/port the auth-proxy forwards to. */
|
|
17
|
+
gatewayHost: string;
|
|
18
|
+
gatewayPort: number;
|
|
19
|
+
/** Bearer token gating the public URL. `undefined` → insecure pass-through. */
|
|
20
|
+
token?: string;
|
|
21
|
+
/** Self-hosted relay (`bore` / `custom`). */
|
|
22
|
+
relay?: string;
|
|
23
|
+
/** `custom` provider command template. */
|
|
24
|
+
command?: string;
|
|
25
|
+
/** Log sink for proxy + provider diagnostics. */
|
|
26
|
+
onLog?: (line: string) => void;
|
|
27
|
+
}
|
|
28
|
+
export interface RunningTunnel {
|
|
29
|
+
provider: string;
|
|
30
|
+
/** Public URL without the token. */
|
|
31
|
+
url: string;
|
|
32
|
+
/** Public URL with `?token=` appended when secured (else identical to `url`). */
|
|
33
|
+
urlWithToken: string;
|
|
34
|
+
/** Local auth-proxy port. */
|
|
35
|
+
proxyPort: number;
|
|
36
|
+
/** Whether the token gate is active. */
|
|
37
|
+
secured: boolean;
|
|
38
|
+
/** Tear everything down. Idempotent. */
|
|
39
|
+
stop(): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
export declare function startTunnel(opts: StartTunnelOptions): Promise<RunningTunnel>;
|
|
42
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +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,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,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,CAwElF"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tunnel manager — wires the auth-proxy + a provider into one running tunnel
|
|
3
|
+
* and records its state.
|
|
4
|
+
*
|
|
5
|
+
* Flow:
|
|
6
|
+
* 1. start the token-checking auth-proxy in front of the gateway
|
|
7
|
+
* 2. start the chosen provider, pointing it at the auth-proxy's local port
|
|
8
|
+
* 3. compose the public URL (with `?token=` when secured) + persist state
|
|
9
|
+
*
|
|
10
|
+
* `stop()` tears down provider then proxy and clears the state file. The
|
|
11
|
+
* gateway is never touched — it keeps running localhost-only.
|
|
12
|
+
*/
|
|
13
|
+
import { startAuthProxy } from "./auth-proxy.js";
|
|
14
|
+
import { getProvider } from "./registry.js";
|
|
15
|
+
import { clearTunnelState, writeTunnelState } from "./state.js";
|
|
16
|
+
/** Append the token as a query param without clobbering an existing query. */
|
|
17
|
+
function withToken(url, token) {
|
|
18
|
+
const sep = url.includes("?") ? "&" : "?";
|
|
19
|
+
return `${url}${sep}token=${encodeURIComponent(token)}`;
|
|
20
|
+
}
|
|
21
|
+
export async function startTunnel(opts) {
|
|
22
|
+
const provider = getProvider(opts.provider);
|
|
23
|
+
// Fail fast on a provider that can't run (missing binary, missing command)
|
|
24
|
+
// BEFORE we open the proxy.
|
|
25
|
+
const avail = await provider.isAvailable({
|
|
26
|
+
localHost: opts.gatewayHost,
|
|
27
|
+
localPort: opts.gatewayPort,
|
|
28
|
+
relay: opts.relay,
|
|
29
|
+
command: opts.command,
|
|
30
|
+
onLog: opts.onLog,
|
|
31
|
+
});
|
|
32
|
+
if (!avail.ok) {
|
|
33
|
+
throw new Error(`tunnel provider "${opts.provider}" is unavailable: ${avail.reason ?? "unknown reason"}`);
|
|
34
|
+
}
|
|
35
|
+
let proxy;
|
|
36
|
+
let handle;
|
|
37
|
+
try {
|
|
38
|
+
proxy = await startAuthProxy({
|
|
39
|
+
gatewayHost: opts.gatewayHost,
|
|
40
|
+
gatewayPort: opts.gatewayPort,
|
|
41
|
+
token: opts.token,
|
|
42
|
+
onLog: opts.onLog,
|
|
43
|
+
});
|
|
44
|
+
handle = await provider.start({
|
|
45
|
+
localHost: "127.0.0.1",
|
|
46
|
+
localPort: proxy.port,
|
|
47
|
+
relay: opts.relay,
|
|
48
|
+
command: opts.command,
|
|
49
|
+
onLog: opts.onLog,
|
|
50
|
+
});
|
|
51
|
+
const secured = proxy.secured;
|
|
52
|
+
const url = handle.url;
|
|
53
|
+
const urlWithToken = secured && opts.token ? withToken(url, opts.token) : url;
|
|
54
|
+
await writeTunnelState({
|
|
55
|
+
url,
|
|
56
|
+
urlWithToken,
|
|
57
|
+
provider: opts.provider,
|
|
58
|
+
pid: process.pid,
|
|
59
|
+
proxyPort: proxy.port,
|
|
60
|
+
gatewayPort: opts.gatewayPort,
|
|
61
|
+
secured,
|
|
62
|
+
startedAt: Date.now(),
|
|
63
|
+
});
|
|
64
|
+
const proxyRef = proxy;
|
|
65
|
+
const handleRef = handle;
|
|
66
|
+
let stopped = false;
|
|
67
|
+
return {
|
|
68
|
+
provider: opts.provider,
|
|
69
|
+
url,
|
|
70
|
+
urlWithToken,
|
|
71
|
+
proxyPort: proxy.port,
|
|
72
|
+
secured,
|
|
73
|
+
async stop() {
|
|
74
|
+
if (stopped)
|
|
75
|
+
return;
|
|
76
|
+
stopped = true;
|
|
77
|
+
try {
|
|
78
|
+
await handleRef.stop();
|
|
79
|
+
}
|
|
80
|
+
catch { /* ignore */ }
|
|
81
|
+
try {
|
|
82
|
+
await proxyRef.stop();
|
|
83
|
+
}
|
|
84
|
+
catch { /* ignore */ }
|
|
85
|
+
await clearTunnelState().catch(() => { });
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
// Roll back partial startup so we never leak a proxy/provider process.
|
|
91
|
+
try {
|
|
92
|
+
await handle?.stop();
|
|
93
|
+
}
|
|
94
|
+
catch { /* ignore */ }
|
|
95
|
+
try {
|
|
96
|
+
await proxy?.stop();
|
|
97
|
+
}
|
|
98
|
+
catch { /* ignore */ }
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/core/tunnel/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bore provider — the OSS `bore` client (https://github.com/ekzhang/bore, MIT).
|
|
3
|
+
*
|
|
4
|
+
* A tiny TCP tunnel. WebSocket + HTTP pass through transparently because bore
|
|
5
|
+
* forwards raw TCP. The public relay `bore.pub` is anonymous; for a private
|
|
6
|
+
* relay the operator runs `bore server` on their own box and passes
|
|
7
|
+
* `--relay <host>` (or `cfg.gateway.tunnel.relay`) + sets `BORE_SECRET`.
|
|
8
|
+
*
|
|
9
|
+
* Trade-off vs cloudflare: bore gives `host:port` with NO TLS and no
|
|
10
|
+
* subdomain — the public URL is `http://<relay>:<port>` (ws over the same).
|
|
11
|
+
* That's the cost of a fully self-hostable, dependency-light OSS path.
|
|
12
|
+
*
|
|
13
|
+
* The `bore` binary is NOT auto-downloaded (it's a Rust release, and this is
|
|
14
|
+
* the "advanced / self-host" path). Resolve order: `$BRIGADE_BORE_BIN` → PATH.
|
|
15
|
+
*/
|
|
16
|
+
import type { TunnelProvider } from "../types.js";
|
|
17
|
+
export declare const boreProvider: TunnelProvider;
|
|
18
|
+
//# sourceMappingURL=bore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bore.d.ts","sourceRoot":"","sources":["../../../../src/core/tunnel/providers/bore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EAAoC,cAAc,EAAsB,MAAM,aAAa,CAAC;AAuBxG,eAAO,MAAM,YAAY,EAAE,cAsE1B,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bore provider — the OSS `bore` client (https://github.com/ekzhang/bore, MIT).
|
|
3
|
+
*
|
|
4
|
+
* A tiny TCP tunnel. WebSocket + HTTP pass through transparently because bore
|
|
5
|
+
* forwards raw TCP. The public relay `bore.pub` is anonymous; for a private
|
|
6
|
+
* relay the operator runs `bore server` on their own box and passes
|
|
7
|
+
* `--relay <host>` (or `cfg.gateway.tunnel.relay`) + sets `BORE_SECRET`.
|
|
8
|
+
*
|
|
9
|
+
* Trade-off vs cloudflare: bore gives `host:port` with NO TLS and no
|
|
10
|
+
* subdomain — the public URL is `http://<relay>:<port>` (ws over the same).
|
|
11
|
+
* That's the cost of a fully self-hostable, dependency-light OSS path.
|
|
12
|
+
*
|
|
13
|
+
* The `bore` binary is NOT auto-downloaded (it's a Rust release, and this is
|
|
14
|
+
* the "advanced / self-host" path). Resolve order: `$BRIGADE_BORE_BIN` → PATH.
|
|
15
|
+
*/
|
|
16
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
17
|
+
import * as fs from "node:fs";
|
|
18
|
+
const DEFAULT_RELAY = "bore.pub";
|
|
19
|
+
// bore prints e.g. `listening at bore.pub:41734`.
|
|
20
|
+
const BORE_PORT_RE = /listening at\s+([^\s:]+):(\d+)/i;
|
|
21
|
+
const URL_WAIT_MS = 20_000;
|
|
22
|
+
function resolveBoreBin() {
|
|
23
|
+
const envBin = process.env.BRIGADE_BORE_BIN?.trim();
|
|
24
|
+
if (envBin && fs.existsSync(envBin))
|
|
25
|
+
return envBin;
|
|
26
|
+
const probe = process.platform === "win32" ? "where" : "which";
|
|
27
|
+
try {
|
|
28
|
+
const res = spawnSync(probe, ["bore"], { encoding: "utf8" });
|
|
29
|
+
if (res.status === 0) {
|
|
30
|
+
const first = res.stdout.split(/\r?\n/).map((l) => l.trim()).find(Boolean);
|
|
31
|
+
if (first)
|
|
32
|
+
return process.platform === "win32" ? first : "bore";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// probe tool missing
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
export const boreProvider = {
|
|
41
|
+
name: "bore",
|
|
42
|
+
label: "bore (OSS TCP tunnel; self-hostable relay)",
|
|
43
|
+
async isAvailable() {
|
|
44
|
+
if (resolveBoreBin())
|
|
45
|
+
return { ok: true };
|
|
46
|
+
return {
|
|
47
|
+
ok: false,
|
|
48
|
+
reason: "the `bore` binary was not found. Install it (https://github.com/ekzhang/bore — `cargo install bore-cli` " +
|
|
49
|
+
"or download a release) and ensure it's on PATH, or set BRIGADE_BORE_BIN.",
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
async start(opts) {
|
|
53
|
+
const bin = resolveBoreBin();
|
|
54
|
+
if (!bin)
|
|
55
|
+
throw new Error("bore binary not found (set BRIGADE_BORE_BIN or install bore)");
|
|
56
|
+
const relay = opts.relay?.trim() || DEFAULT_RELAY;
|
|
57
|
+
const args = ["local", String(opts.localPort), "--to", relay];
|
|
58
|
+
const child = spawn(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
59
|
+
const url = await new Promise((resolve, reject) => {
|
|
60
|
+
let settled = false;
|
|
61
|
+
const timer = setTimeout(() => {
|
|
62
|
+
if (settled)
|
|
63
|
+
return;
|
|
64
|
+
settled = true;
|
|
65
|
+
try {
|
|
66
|
+
child.kill();
|
|
67
|
+
}
|
|
68
|
+
catch { /* ignore */ }
|
|
69
|
+
reject(new Error(`bore did not report a public port within ${URL_WAIT_MS / 1000}s`));
|
|
70
|
+
}, URL_WAIT_MS);
|
|
71
|
+
const scan = (chunk) => {
|
|
72
|
+
const text = chunk.toString();
|
|
73
|
+
for (const line of text.split(/\r?\n/)) {
|
|
74
|
+
if (line.trim())
|
|
75
|
+
opts.onLog?.(line.trim());
|
|
76
|
+
}
|
|
77
|
+
const m = text.match(BORE_PORT_RE);
|
|
78
|
+
if (m && !settled) {
|
|
79
|
+
settled = true;
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
resolve(`http://${m[1]}:${m[2]}`);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
child.stdout?.on("data", scan);
|
|
85
|
+
child.stderr?.on("data", scan);
|
|
86
|
+
child.on("error", (err) => {
|
|
87
|
+
if (settled)
|
|
88
|
+
return;
|
|
89
|
+
settled = true;
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
reject(err);
|
|
92
|
+
});
|
|
93
|
+
child.on("exit", (code) => {
|
|
94
|
+
if (settled)
|
|
95
|
+
return;
|
|
96
|
+
settled = true;
|
|
97
|
+
clearTimeout(timer);
|
|
98
|
+
reject(new Error(`bore exited (code ${code ?? "?"}) before reporting a port`));
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
let stopped = false;
|
|
102
|
+
return {
|
|
103
|
+
provider: "bore",
|
|
104
|
+
url,
|
|
105
|
+
async stop() {
|
|
106
|
+
if (stopped)
|
|
107
|
+
return;
|
|
108
|
+
stopped = true;
|
|
109
|
+
try {
|
|
110
|
+
child.kill();
|
|
111
|
+
}
|
|
112
|
+
catch { /* ignore */ }
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=bore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bore.js","sourceRoot":"","sources":["../../../../src/core/tunnel/providers/bore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare provider — anonymous TryCloudflare quick tunnel.
|
|
3
|
+
*
|
|
4
|
+
* The default `brigade expose` backend. No account, no signup: cloudflared
|
|
5
|
+
* dials Cloudflare's edge and we get a random `https://<x>.trycloudflare.com`
|
|
6
|
+
* URL that terminates TLS at the edge and proxies straight to our local
|
|
7
|
+
* auth-proxy. WebSockets work by default (the gateway is WS-first).
|
|
8
|
+
*
|
|
9
|
+
* The `cloudflared` binary (Apache-2.0) is NOT a hard npm dependency — that
|
|
10
|
+
* would add a ~30 MB download to every Brigade install. Instead we resolve it
|
|
11
|
+
* lazily at expose time:
|
|
12
|
+
* 1. `$BRIGADE_CLOUDFLARED_BIN`
|
|
13
|
+
* 2. `cloudflared` on PATH (system install)
|
|
14
|
+
* 3. a Brigade-managed copy in the OS cache dir
|
|
15
|
+
* 4. download the official release into the cache dir (once)
|
|
16
|
+
*
|
|
17
|
+
* Caveat (documented in the research): TryCloudflare quick tunnels don't
|
|
18
|
+
* support SSE and cap in-flight requests; that's fine for a personal WS
|
|
19
|
+
* gateway. For a stable URL the operator can point a self-host provider at
|
|
20
|
+
* their own relay instead.
|
|
21
|
+
*/
|
|
22
|
+
import type { TunnelProvider } from "../types.js";
|
|
23
|
+
export declare const cloudflareProvider: TunnelProvider;
|
|
24
|
+
//# sourceMappingURL=cloudflared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflared.d.ts","sourceRoot":"","sources":["../../../../src/core/tunnel/providers/cloudflared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAQH,OAAO,KAAK,EAAoC,cAAc,EAAsB,MAAM,aAAa,CAAC;AAqFxG,eAAO,MAAM,kBAAkB,EAAE,cAkEhC,CAAC"}
|