@betterportal/tunnels 1.0.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.
Files changed (116) hide show
  1. package/README.md +76 -0
  2. package/SPEC.md +524 -0
  3. package/lib/.bsb/clients/service-tunnel-client-api.d.ts +133 -0
  4. package/lib/.bsb/clients/service-tunnel-client-api.d.ts.map +1 -0
  5. package/lib/.bsb/clients/service-tunnel-client-api.js +102 -0
  6. package/lib/.bsb/clients/service-tunnel-client-api.js.map +1 -0
  7. package/lib/.bsb/clients/service-tunnel-web.d.ts +43 -0
  8. package/lib/.bsb/clients/service-tunnel-web.d.ts.map +1 -0
  9. package/lib/.bsb/clients/service-tunnel-web.js +47 -0
  10. package/lib/.bsb/clients/service-tunnel-web.js.map +1 -0
  11. package/lib/auth.d.ts +12 -0
  12. package/lib/auth.d.ts.map +1 -0
  13. package/lib/auth.js +59 -0
  14. package/lib/auth.js.map +1 -0
  15. package/lib/cli.d.ts +2 -0
  16. package/lib/cli.d.ts.map +1 -0
  17. package/lib/cli.js +295 -0
  18. package/lib/cli.js.map +1 -0
  19. package/lib/plugins/service-betterportal/.bp-generated/registry.d.ts +3 -0
  20. package/lib/plugins/service-betterportal/.bp-generated/registry.d.ts.map +1 -0
  21. package/lib/plugins/service-betterportal/.bp-generated/registry.js +127 -0
  22. package/lib/plugins/service-betterportal/.bp-generated/registry.js.map +1 -0
  23. package/lib/plugins/service-betterportal/assets/brand/bettertunnels-horizontal-light.svg +18 -0
  24. package/lib/plugins/service-betterportal/assets/brand/bettertunnels-square-dark-1024x1024.png +0 -0
  25. package/lib/plugins/service-betterportal/assets/brand/favicon.svg +12 -0
  26. package/lib/plugins/service-betterportal/betterportal-logo.png +0 -0
  27. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/_theme.bootstrap1/index.d.ts +5 -0
  28. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/_theme.bootstrap1/index.d.ts.map +1 -0
  29. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/_theme.bootstrap1/index.js +6 -0
  30. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/_theme.bootstrap1/index.js.map +1 -0
  31. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/index.d.ts +25 -0
  32. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/index.d.ts.map +1 -0
  33. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/index.js +59 -0
  34. package/lib/plugins/service-betterportal/bp-routes/cli-auth/verify/index.js.map +1 -0
  35. package/lib/plugins/service-betterportal/bp-routes/dashboard/_theme.bootstrap1/index.d.ts +5 -0
  36. package/lib/plugins/service-betterportal/bp-routes/dashboard/_theme.bootstrap1/index.d.ts.map +1 -0
  37. package/lib/plugins/service-betterportal/bp-routes/dashboard/_theme.bootstrap1/index.js +22 -0
  38. package/lib/plugins/service-betterportal/bp-routes/dashboard/_theme.bootstrap1/index.js.map +1 -0
  39. package/lib/plugins/service-betterportal/bp-routes/dashboard/index.d.ts +40 -0
  40. package/lib/plugins/service-betterportal/bp-routes/dashboard/index.d.ts.map +1 -0
  41. package/lib/plugins/service-betterportal/bp-routes/dashboard/index.js +57 -0
  42. package/lib/plugins/service-betterportal/bp-routes/dashboard/index.js.map +1 -0
  43. package/lib/plugins/service-betterportal/bp-routes/downloads/_theme.bootstrap1/index.d.ts +5 -0
  44. package/lib/plugins/service-betterportal/bp-routes/downloads/_theme.bootstrap1/index.d.ts.map +1 -0
  45. package/lib/plugins/service-betterportal/bp-routes/downloads/_theme.bootstrap1/index.js +5 -0
  46. package/lib/plugins/service-betterportal/bp-routes/downloads/_theme.bootstrap1/index.js.map +1 -0
  47. package/lib/plugins/service-betterportal/bp-routes/downloads/index.d.ts +30 -0
  48. package/lib/plugins/service-betterportal/bp-routes/downloads/index.d.ts.map +1 -0
  49. package/lib/plugins/service-betterportal/bp-routes/downloads/index.js +45 -0
  50. package/lib/plugins/service-betterportal/bp-routes/downloads/index.js.map +1 -0
  51. package/lib/plugins/service-betterportal/bp-routes/landing/_theme.bootstrap1/index.d.ts +5 -0
  52. package/lib/plugins/service-betterportal/bp-routes/landing/_theme.bootstrap1/index.d.ts.map +1 -0
  53. package/lib/plugins/service-betterportal/bp-routes/landing/_theme.bootstrap1/index.js +5 -0
  54. package/lib/plugins/service-betterportal/bp-routes/landing/_theme.bootstrap1/index.js.map +1 -0
  55. package/lib/plugins/service-betterportal/bp-routes/landing/index.d.ts +40 -0
  56. package/lib/plugins/service-betterportal/bp-routes/landing/index.d.ts.map +1 -0
  57. package/lib/plugins/service-betterportal/bp-routes/landing/index.js +63 -0
  58. package/lib/plugins/service-betterportal/bp-routes/landing/index.js.map +1 -0
  59. package/lib/plugins/service-betterportal/bp-routes/tunnels/_theme.bootstrap1/index.d.ts +5 -0
  60. package/lib/plugins/service-betterportal/bp-routes/tunnels/_theme.bootstrap1/index.d.ts.map +1 -0
  61. package/lib/plugins/service-betterportal/bp-routes/tunnels/_theme.bootstrap1/index.js +5 -0
  62. package/lib/plugins/service-betterportal/bp-routes/tunnels/_theme.bootstrap1/index.js.map +1 -0
  63. package/lib/plugins/service-betterportal/bp-routes/tunnels/index.d.ts +44 -0
  64. package/lib/plugins/service-betterportal/bp-routes/tunnels/index.d.ts.map +1 -0
  65. package/lib/plugins/service-betterportal/bp-routes/tunnels/index.js +59 -0
  66. package/lib/plugins/service-betterportal/bp-routes/tunnels/index.js.map +1 -0
  67. package/lib/plugins/service-betterportal/brand-assets.d.ts +7 -0
  68. package/lib/plugins/service-betterportal/brand-assets.d.ts.map +1 -0
  69. package/lib/plugins/service-betterportal/brand-assets.js +24 -0
  70. package/lib/plugins/service-betterportal/brand-assets.js.map +1 -0
  71. package/lib/plugins/service-betterportal/index.d.ts +57 -0
  72. package/lib/plugins/service-betterportal/index.d.ts.map +1 -0
  73. package/lib/plugins/service-betterportal/index.js +108 -0
  74. package/lib/plugins/service-betterportal/index.js.map +1 -0
  75. package/lib/plugins/service-tunnel-client-api/ids.d.ts +6 -0
  76. package/lib/plugins/service-tunnel-client-api/ids.d.ts.map +1 -0
  77. package/lib/plugins/service-tunnel-client-api/ids.js +17 -0
  78. package/lib/plugins/service-tunnel-client-api/ids.js.map +1 -0
  79. package/lib/plugins/service-tunnel-client-api/index.d.ts +158 -0
  80. package/lib/plugins/service-tunnel-client-api/index.d.ts.map +1 -0
  81. package/lib/plugins/service-tunnel-client-api/index.js +591 -0
  82. package/lib/plugins/service-tunnel-client-api/index.js.map +1 -0
  83. package/lib/plugins/service-tunnel-client-api/registry.d.ts +36 -0
  84. package/lib/plugins/service-tunnel-client-api/registry.d.ts.map +1 -0
  85. package/lib/plugins/service-tunnel-client-api/registry.js +14 -0
  86. package/lib/plugins/service-tunnel-client-api/registry.js.map +1 -0
  87. package/lib/plugins/service-tunnel-client-api/schemas.d.ts +66 -0
  88. package/lib/plugins/service-tunnel-client-api/schemas.d.ts.map +1 -0
  89. package/lib/plugins/service-tunnel-client-api/schemas.js +56 -0
  90. package/lib/plugins/service-tunnel-client-api/schemas.js.map +1 -0
  91. package/lib/plugins/service-tunnel-web/http.d.ts +4 -0
  92. package/lib/plugins/service-tunnel-web/http.d.ts.map +1 -0
  93. package/lib/plugins/service-tunnel-web/http.js +119 -0
  94. package/lib/plugins/service-tunnel-web/http.js.map +1 -0
  95. package/lib/plugins/service-tunnel-web/index.d.ts +79 -0
  96. package/lib/plugins/service-tunnel-web/index.d.ts.map +1 -0
  97. package/lib/plugins/service-tunnel-web/index.js +278 -0
  98. package/lib/plugins/service-tunnel-web/index.js.map +1 -0
  99. package/lib/plugins/service-tunnel-web/verification.d.ts +27 -0
  100. package/lib/plugins/service-tunnel-web/verification.d.ts.map +1 -0
  101. package/lib/plugins/service-tunnel-web/verification.js +209 -0
  102. package/lib/plugins/service-tunnel-web/verification.js.map +1 -0
  103. package/lib/prisma.d.ts +6 -0
  104. package/lib/prisma.d.ts.map +1 -0
  105. package/lib/prisma.js +10 -0
  106. package/lib/prisma.js.map +1 -0
  107. package/lib/schemas/service-betterportal.json +109 -0
  108. package/lib/schemas/service-tunnel-client-api.json +300 -0
  109. package/lib/schemas/service-tunnel-web.json +140 -0
  110. package/package.json +60 -0
  111. package/prisma/migrations/0001_init/migration.sql +63 -0
  112. package/prisma/migrations/0002_account_plan/migration.sql +6 -0
  113. package/prisma/migrations/0003_tunnel_owner_server/migration.sql +1 -0
  114. package/prisma/migrations/20260701000000_add_client_auth/migration.sql +46 -0
  115. package/prisma/migrations/migration_lock.toml +3 -0
  116. package/prisma/schema.prisma +141 -0
@@ -0,0 +1,591 @@
1
+ import { BSBService, bsb, optional, createConfigSchema, createEventSchemas, createFireAndForgetEvent, createReturnableEvent } from "@bsb/base";
2
+ import * as av from "anyvali";
3
+ import { createServer } from "node:http";
4
+ import { H3, toNodeHandler } from "h3";
5
+ import { WebSocketServer } from "ws";
6
+ import { TunnelCreateSchema, ClientFrameSchema, AuthStartRequestSchema, AuthStartResponseSchema, AuthStatusResponseSchema } from "./schemas.js";
7
+ import { buildTunnelSubdomain, hashValue, randomPrefix } from "./ids.js";
8
+ import { prisma } from "../../prisma.js";
9
+ import { AUTH_SESSION_TTL_MS, DEVICE_TOKEN_TTL_MS, bearerToken, hashSecret, normalizeIpRange, randomToken, shortBrowserKey, verifySecret } from "../../auth.js";
10
+ import { TunnelRegistry } from "./registry.js";
11
+ import TunnelWebClient from "../../.bsb/clients/service-tunnel-web.js";
12
+ export const Config = createConfigSchema({
13
+ name: "service-tunnel-client-api",
14
+ description: "Client websocket/API service",
15
+ tags: ["service", "websocket", "tunnel"]
16
+ }, av.object({
17
+ port: av.number().default(8081).describe("Client API listener port"),
18
+ domain: av.string().default("tunnels.betterportal.dev").describe("Default public tunnel domain"),
19
+ publicUrl: av.string().default("https://tunnels.betterportal.dev").describe("Public base URL"),
20
+ authAppBaseUrl: av.string().default("https://betterportal.cloud").describe("BetterPortal app URL used for CLI auth"),
21
+ authVerifyPath: av.string().default("/cli-auth/verify").describe("BetterPortal CLI auth verify route")
22
+ }).describe("service-tunnel-client-api config"));
23
+ export const EventSchemas = createEventSchemas({
24
+ emitEvents: {},
25
+ onEvents: {
26
+ "ws.toOrigin": createFireAndForgetEvent(bsb.object({
27
+ publicServerId: bsb.string({ description: "Web service instance that owns the public websocket" }),
28
+ publicSocketId: bsb.string({ description: "Web service local websocket id" }),
29
+ hostname: bsb.string({ description: "Public tunnel hostname" }),
30
+ path: bsb.string({ description: "Websocket path and query" }),
31
+ frameType: bsb.string({ description: "msg, ack, or event" }),
32
+ event: optional(bsb.string({ description: "open or close" })),
33
+ body: optional(bsb.string({ description: "Base64 websocket payload" }))
34
+ }, "Public websocket frame to origin"), "Relay a public websocket frame to the connected tunnel client"),
35
+ "proxy.metrics": createFireAndForgetEvent(bsb.object({
36
+ hostname: bsb.string({ description: "Public tunnel hostname" }),
37
+ requestId: bsb.string({ description: "Request id" }),
38
+ totalMs: bsb.number({ description: "Public request total duration" }),
39
+ clientApiRoundtripMs: optional(bsb.number({ description: "Client API to CLI roundtrip duration" })),
40
+ cliOverheadMs: optional(bsb.number({ description: "CLI work outside origin read duration" })),
41
+ originMs: optional(bsb.number({ description: "CLI to origin/read duration" })),
42
+ internalServerMs: optional(bsb.number({ description: "Remaining server-side duration" }))
43
+ }, "Proxy request metrics"), "Send final proxy request timings to the connected tunnel client")
44
+ },
45
+ emitReturnableEvents: {},
46
+ onReturnableEvents: {
47
+ "proxy.request": createReturnableEvent(bsb.object({
48
+ hostname: bsb.string({ description: "Public request hostname" }),
49
+ method: bsb.string({ description: "HTTP method" }),
50
+ path: bsb.string({ description: "Path and query" }),
51
+ headers: bsb.record(bsb.string({ description: "Header name" }), bsb.string({ description: "Header value" }), "Headers"),
52
+ body: optional(bsb.string({ description: "Base64 encoded request body" })),
53
+ webStartedAt: bsb.number({ description: "Web service request start timestamp" })
54
+ }, "Proxy request"), bsb.object({
55
+ requestId: bsb.string({ description: "Request id" }),
56
+ ownerServerId: bsb.string({ description: "Client API server id" }),
57
+ status: bsb.number({ description: "HTTP status" }),
58
+ headers: bsb.record(bsb.string({ description: "Header name" }), bsb.string({ description: "Header value" }), "Headers"),
59
+ body: bsb.string({ description: "Base64 encoded response body" }),
60
+ webStartedAt: bsb.number({ description: "Web service request start timestamp" }),
61
+ clientApiRoundtripMs: bsb.number({ description: "Client API to CLI roundtrip duration" }),
62
+ cliOverheadMs: optional(bsb.number({ description: "CLI work outside origin read duration" })),
63
+ originMs: optional(bsb.number({ description: "Origin/read duration" }))
64
+ }, "Proxy response"), "Proxy an HTTP request through a connected tunnel client", 60)
65
+ },
66
+ emitBroadcast: {},
67
+ onBroadcast: {}
68
+ });
69
+ export class Plugin extends BSBService {
70
+ static Config = Config;
71
+ static EventSchemas = EventSchemas;
72
+ initBeforePlugins = [];
73
+ initAfterPlugins = [];
74
+ runBeforePlugins = [];
75
+ runAfterPlugins = [];
76
+ registry = new TunnelRegistry();
77
+ app;
78
+ server;
79
+ wss;
80
+ web;
81
+ constructor(cfg) {
82
+ super(cfg);
83
+ this.app = new H3();
84
+ this.server = createServer(toNodeHandler(this.app));
85
+ this.wss = new WebSocketServer({ noServer: true });
86
+ this.web = new TunnelWebClient(this);
87
+ }
88
+ async init(obs) {
89
+ obs.log.info("init {plugin}", { plugin: this.pluginName });
90
+ await this.events.onReturnableEvent("proxy.request", obs, async (_handlerObs, input) => {
91
+ _handlerObs.log.info("CLIENT API proxy.request {method} {hostname}{path}", {
92
+ method: input.method,
93
+ hostname: input.hostname,
94
+ path: input.path
95
+ });
96
+ const tunnel = this.registry.get(input.hostname);
97
+ const unavailable = {
98
+ requestId: crypto.randomUUID(),
99
+ ownerServerId: this.appId,
100
+ status: 503,
101
+ headers: {},
102
+ body: Buffer.from("Tunnel unavailable").toString("base64"),
103
+ webStartedAt: input.webStartedAt,
104
+ clientApiRoundtripMs: 0
105
+ };
106
+ if (!tunnel)
107
+ return unavailable;
108
+ if (tunnel.ws.readyState !== tunnel.ws.OPEN)
109
+ return unavailable;
110
+ return this.proxyRequest(tunnel, input.method, input.path, input.headers, input.body ?? "", input.webStartedAt);
111
+ });
112
+ await this.events.onEventSpecific("proxy.metrics", this.appId, obs, async (_handlerObs, input) => {
113
+ const tunnel = this.registry.get(input.hostname);
114
+ if (!tunnel || tunnel.ws.readyState !== tunnel.ws.OPEN)
115
+ return;
116
+ tunnel.ws.send(JSON.stringify({
117
+ type: "request.metrics",
118
+ requestId: input.requestId,
119
+ totalMs: input.totalMs,
120
+ clientApiRoundtripMs: input.clientApiRoundtripMs,
121
+ cliOverheadMs: input.cliOverheadMs,
122
+ originMs: input.originMs,
123
+ internalServerMs: input.internalServerMs
124
+ }));
125
+ });
126
+ await this.events.onEventSpecific("ws.toOrigin", this.appId, obs, async (_handlerObs, input) => {
127
+ const tunnel = this.registry.get(input.hostname);
128
+ if (!tunnel || tunnel.ws.readyState !== tunnel.ws.OPEN) {
129
+ await this.web.wsFromOriginSpecific(input.publicServerId, _handlerObs, {
130
+ publicSocketId: input.publicSocketId,
131
+ frameType: "event",
132
+ event: "close"
133
+ });
134
+ return;
135
+ }
136
+ tunnel.ws.send(JSON.stringify({
137
+ type: "ws.toOrigin",
138
+ publicServerId: input.publicServerId,
139
+ publicSocketId: input.publicSocketId,
140
+ path: input.path,
141
+ frameType: input.frameType,
142
+ message: input.event,
143
+ body: input.body
144
+ }));
145
+ });
146
+ const domain = this.config.domain;
147
+ const publicUrl = this.config.publicUrl;
148
+ this.app.get("/health", () => new Response("ok\n", {
149
+ headers: { "content-type": "text/plain; charset=utf-8" }
150
+ }));
151
+ this.app.post("/api/client/auth/start", async (event) => {
152
+ const body = AuthStartRequestSchema.parse(await safeJson(event.req));
153
+ const browserKey = shortBrowserKey();
154
+ const pollSecret = randomToken();
155
+ const expiresAt = new Date(Date.now() + AUTH_SESSION_TTL_MS);
156
+ const authBase = body.authAppBaseUrl ?? this.config.authAppBaseUrl;
157
+ const browserUrl = buildAuthUrl(authBase, this.config.authVerifyPath, browserKey);
158
+ const clientIp = proxyClientIpFromHeaders(event.req.headers);
159
+ const session = await prisma.clientAuthSession.create({
160
+ data: {
161
+ browserKeyHash: hashSecret(browserKey),
162
+ pollSecretHash: hashSecret(pollSecret),
163
+ clientIpHash: hashSecret(clientIp),
164
+ userAgentHash: hashSecret(event.req.headers.get("user-agent") ?? ""),
165
+ expiresAt
166
+ }
167
+ });
168
+ const url = new URL(browserUrl);
169
+ url.searchParams.set("session", session.id);
170
+ url.searchParams.set("key", browserKey);
171
+ return json(AuthStartResponseSchema.parse({
172
+ sessionId: session.id,
173
+ pollSecret,
174
+ browserUrl: url.toString(),
175
+ expiresAt: expiresAt.toISOString()
176
+ }));
177
+ });
178
+ this.app.get("/api/client/auth/status", async (event) => {
179
+ const url = new URL(event.req.url);
180
+ const sessionId = url.searchParams.get("sessionId") ?? "";
181
+ const pollSecret = bearerToken(event.req.headers) ?? "";
182
+ if (!sessionId || !pollSecret) {
183
+ return json(AuthStatusResponseSchema.parse({ status: "invalid", message: "Missing auth session credentials." }), 401);
184
+ }
185
+ const session = await prisma.clientAuthSession.findUnique({ where: { id: sessionId } });
186
+ if (!session || !verifySecret(pollSecret, session.pollSecretHash)) {
187
+ return json(AuthStatusResponseSchema.parse({ status: "invalid", message: "Invalid auth session." }), 401);
188
+ }
189
+ if (session.expiresAt <= new Date() && session.status === "pending") {
190
+ await prisma.clientAuthSession.update({ where: { id: session.id }, data: { status: "expired" } });
191
+ return json(AuthStatusResponseSchema.parse({ status: "expired", message: "Authentication session expired." }), 410);
192
+ }
193
+ if (session.status === "pending") {
194
+ return json(AuthStatusResponseSchema.parse({ status: "pending" }));
195
+ }
196
+ if (session.status !== "approved" || !session.tenantId || !session.bpUserSubject) {
197
+ return json(AuthStatusResponseSchema.parse({ status: session.status, message: "Authentication session is not approved." }), 409);
198
+ }
199
+ const clientIp = proxyClientIpFromHeaders(event.req.headers);
200
+ const ipRange = normalizeIpRange(clientIp);
201
+ if (!ipRange) {
202
+ return json(AuthStatusResponseSchema.parse({ status: "invalid", message: "Unable to bind token to public IP range." }), 400);
203
+ }
204
+ const deviceToken = `bt_${randomToken(32)}`;
205
+ const tokenExpiresAt = new Date(Date.now() + DEVICE_TOKEN_TTL_MS);
206
+ await prisma.$transaction([
207
+ prisma.clientDeviceToken.create({
208
+ data: {
209
+ tenantId: session.tenantId,
210
+ bpUserSubject: session.bpUserSubject,
211
+ tokenHash: hashSecret(deviceToken),
212
+ name: "BetterTunnels CLI",
213
+ ipRangeHash: hashSecret(ipRange.cidr),
214
+ ipFamily: ipRange.family,
215
+ userAgentHash: hashSecret(event.req.headers.get("user-agent") ?? ""),
216
+ expiresAt: tokenExpiresAt
217
+ }
218
+ }),
219
+ prisma.clientAuthSession.update({
220
+ where: { id: session.id },
221
+ data: { status: "consumed", consumedAt: new Date() }
222
+ })
223
+ ]);
224
+ return json(AuthStatusResponseSchema.parse({
225
+ status: "approved",
226
+ token: deviceToken,
227
+ expiresAt: tokenExpiresAt.toISOString(),
228
+ tenantId: session.tenantId,
229
+ bpUserSubject: session.bpUserSubject
230
+ }));
231
+ });
232
+ this.server.on("upgrade", (request, socket, head) => {
233
+ const url = new URL(request.url ?? "/", `http://${request.headers.host ?? "localhost"}`);
234
+ if (url.pathname !== "/api/client/ws") {
235
+ socket.destroy();
236
+ return;
237
+ }
238
+ this.wss.handleUpgrade(request, socket, head, (ws) => {
239
+ obs.log.info("CLIENT WS upgrade {path}", { path: url.pathname });
240
+ void this.handleTunnelSocket(ws, url, request.headers["user-agent"] ?? "", proxyClientIp(request.headers), domain, publicUrl, obs);
241
+ });
242
+ });
243
+ }
244
+ async run(obs) {
245
+ const port = this.config.port;
246
+ await new Promise((resolve) => {
247
+ this.server.listen(port, "0.0.0.0", () => resolve());
248
+ });
249
+ obs.log.info(`client-api listening on port ${port}`);
250
+ }
251
+ async dispose() {
252
+ this.wss.close();
253
+ await new Promise((resolve, reject) => {
254
+ this.server.close((error) => error ? reject(error) : resolve());
255
+ });
256
+ }
257
+ async handleTunnelSocket(ws, url, userAgent, clientIp, domain, publicUrl, obs) {
258
+ const input = TunnelCreateSchema.parse({
259
+ sessionId: url.searchParams.get("sessionId") ?? "",
260
+ targetHost: url.searchParams.get("targetHost") ?? "127.0.0.1",
261
+ targetPort: Number(url.searchParams.get("targetPort") ?? "0"),
262
+ authenticated: url.searchParams.get("authenticated") === "true",
263
+ prefix: url.searchParams.get("prefix") ?? undefined,
264
+ token: url.searchParams.get("token") ?? undefined
265
+ });
266
+ const authContext = input.authenticated
267
+ ? await validateDeviceToken(input.token, clientIp, Array.isArray(userAgent) ? userAgent.join(" ") : userAgent)
268
+ : undefined;
269
+ if (input.authenticated && !authContext) {
270
+ ws.close(1008, "reauth required");
271
+ obs.log.warn("CLIENT SESSION rejected authenticated tunnel from {clientIp}", { clientIp });
272
+ return;
273
+ }
274
+ const authenticated = !!authContext;
275
+ const prefix = authenticated && input.prefix ? input.prefix : randomPrefix();
276
+ const subdomain = buildTunnelSubdomain(prefix, input.targetPort, clientIp);
277
+ const expiresAt = new Date(Date.now() + (authenticated ? 24 * 60 * 60 * 1000 : 6 * 60 * 60 * 1000));
278
+ const sessionObs = this.createTrace("bt.client.session", {
279
+ "bt.client.session_id": input.sessionId,
280
+ "bt.tunnel.subdomain": subdomain,
281
+ "bt.tunnel.authenticated": authenticated,
282
+ "client.address": clientIp
283
+ });
284
+ sessionObs.log.info("CLIENT SESSION connect {subdomain} from {clientIp}", {
285
+ subdomain,
286
+ clientIp
287
+ });
288
+ const session = await prisma.clientSession.upsert({
289
+ where: { id: input.sessionId },
290
+ create: {
291
+ id: input.sessionId,
292
+ accountId: authContext?.accountId,
293
+ userAgent: Array.isArray(userAgent) ? userAgent.join(" ") : userAgent,
294
+ ipHash: hashValue(clientIp),
295
+ expiresAt
296
+ },
297
+ update: { expiresAt }
298
+ });
299
+ const tunnelRow = await prisma.tunnel.upsert({
300
+ where: { subdomain },
301
+ create: {
302
+ sessionId: session.id,
303
+ subdomain,
304
+ ownerServerId: this.appId,
305
+ targetHost: input.targetHost,
306
+ targetPort: input.targetPort,
307
+ authenticated,
308
+ accountId: authContext?.accountId,
309
+ status: "active",
310
+ expiresAt
311
+ },
312
+ update: {
313
+ sessionId: session.id,
314
+ ownerServerId: this.appId,
315
+ targetHost: input.targetHost,
316
+ targetPort: input.targetPort,
317
+ authenticated,
318
+ accountId: authContext?.accountId,
319
+ status: "active",
320
+ expiresAt
321
+ }
322
+ });
323
+ const tunnel = {
324
+ id: tunnelRow.id,
325
+ subdomain,
326
+ targetHost: input.targetHost,
327
+ targetPort: input.targetPort,
328
+ authenticated,
329
+ expiresAt,
330
+ ws,
331
+ pending: new Map(),
332
+ sessionObs
333
+ };
334
+ this.registry.set(tunnel);
335
+ sessionObs.log.info("CLIENT TUNNEL active {subdomain} -> {host}:{port}", {
336
+ subdomain,
337
+ host: input.targetHost,
338
+ port: input.targetPort
339
+ });
340
+ ws.send(JSON.stringify({
341
+ type: "tunnel.ready",
342
+ publicUrl: publicUrl.replace(/\/$/, "").replace(`://${domain}`, `://${subdomain}.${domain}`),
343
+ subdomain,
344
+ expiresAt: expiresAt.toISOString()
345
+ }));
346
+ ws.on("message", (raw) => this.handleClientFrame(tunnel, raw.toString()));
347
+ ws.on("close", (code, reason) => {
348
+ sessionObs.log.warn("CLIENT TUNNEL disconnected {subdomain}", { subdomain });
349
+ for (const [requestId, pending] of tunnel.pending.entries()) {
350
+ this.failPending(tunnel, requestId, pending, new Error("Tunnel client disconnected."));
351
+ }
352
+ this.registry.delete(subdomain);
353
+ void prisma.tunnel.update({ where: { id: tunnel.id }, data: { status: "disconnected" } }).catch(() => undefined);
354
+ sessionObs.end({ "bt.client.disconnect": true });
355
+ sessionObs.log.warn("CLIENT TUNNEL socket closed {subdomain} code={code} reason={reason}", {
356
+ subdomain,
357
+ code,
358
+ reason: reason.toString()
359
+ });
360
+ });
361
+ ws.on("error", (error) => {
362
+ sessionObs.log.error("CLIENT TUNNEL socket error {subdomain}: {message}", {
363
+ subdomain,
364
+ message: error.message
365
+ });
366
+ });
367
+ }
368
+ async proxyRequest(tunnel, method, path, headers, body, webStartedAt) {
369
+ const requestId = crypto.randomUUID();
370
+ const clientApiSentAt = Date.now();
371
+ const timeoutMs = tunnel.authenticated ? 5 * 60 * 1000 : 60 * 1000;
372
+ const idleTimeoutMs = tunnel.authenticated ? 60 * 1000 : 30 * 1000;
373
+ const requestObs = tunnel.sessionObs.startSpan("bt.client.proxy", {
374
+ "bt.tunnel.id": tunnel.id,
375
+ "bt.tunnel.subdomain": tunnel.subdomain,
376
+ "http.request.method": method,
377
+ "url.path": path
378
+ });
379
+ requestObs.log.info("CLIENT PROXY start {method} {path} via {subdomain}", {
380
+ method,
381
+ path,
382
+ subdomain: tunnel.subdomain
383
+ });
384
+ const responsePromise = new Promise((resolve, reject) => {
385
+ const pending = {
386
+ resolve: (response) => {
387
+ void response.arrayBuffer().then((arrayBuffer) => {
388
+ const responseHeaders = {};
389
+ response.headers.forEach((value, key) => {
390
+ responseHeaders[key] = value;
391
+ });
392
+ const output = {
393
+ requestId,
394
+ ownerServerId: this.appId,
395
+ status: response.status,
396
+ headers: responseHeaders,
397
+ body: Buffer.from(arrayBuffer).toString("base64"),
398
+ webStartedAt: pending.webStartedAt,
399
+ clientApiRoundtripMs: pending.clientApiRoundtripMs ?? Date.now() - pending.clientApiSentAt,
400
+ cliOverheadMs: pending.cliOverheadMs,
401
+ originMs: pending.originMs
402
+ };
403
+ requestObs.log.info("CLIENT PROXY complete {method} {path} -> {status}", {
404
+ method,
405
+ path,
406
+ status: response.status
407
+ });
408
+ requestObs.end({ "http.response.status_code": response.status });
409
+ resolve(output);
410
+ }).catch(reject);
411
+ },
412
+ reject: (error) => {
413
+ requestObs.error(error);
414
+ requestObs.end({ "status": "failed" });
415
+ reject(error);
416
+ },
417
+ chunks: [],
418
+ webStartedAt,
419
+ clientApiSentAt,
420
+ totalTimer: setTimeout(() => this.failPending(tunnel, requestId, pending, new Error("Local app timed out.")), timeoutMs),
421
+ firstByteTimer: setTimeout(() => this.failPending(tunnel, requestId, pending, new Error("Local app did not acknowledge request within 5s.")), 5 * 1000),
422
+ idleTimeoutMs
423
+ };
424
+ tunnel.pending.set(requestId, pending);
425
+ });
426
+ tunnel.ws.send(JSON.stringify({
427
+ type: "request.start",
428
+ requestId,
429
+ method,
430
+ path,
431
+ headers,
432
+ body,
433
+ webStartedAt,
434
+ clientApiSentAt
435
+ }));
436
+ return responsePromise;
437
+ }
438
+ handleClientFrame(tunnel, raw) {
439
+ let frame;
440
+ try {
441
+ frame = ClientFrameSchema.parse(JSON.parse(raw));
442
+ }
443
+ catch (error) {
444
+ tunnel.sessionObs.error(error instanceof Error ? error : new Error(String(error)));
445
+ tunnel.ws.close(1002, "invalid frame");
446
+ return;
447
+ }
448
+ if (frame.type === "ws.fromOrigin" && frame.publicServerId && frame.publicSocketId && frame.frameType) {
449
+ void this.web.wsFromOriginSpecific(frame.publicServerId, tunnel.sessionObs, {
450
+ publicSocketId: frame.publicSocketId,
451
+ frameType: frame.frameType,
452
+ event: frame.message,
453
+ body: frame.body
454
+ });
455
+ return;
456
+ }
457
+ if (!frame.requestId)
458
+ return;
459
+ const pending = tunnel.pending.get(frame.requestId);
460
+ if (!pending)
461
+ return;
462
+ if (frame.type === "response.start") {
463
+ clearTimeout(pending.firstByteTimer);
464
+ this.resetIdleTimer(tunnel, frame.requestId, pending);
465
+ pending.status = frame.status ?? 200;
466
+ pending.headers = frame.headers ?? {};
467
+ return;
468
+ }
469
+ if (frame.type === "response.body" && frame.body) {
470
+ this.resetIdleTimer(tunnel, frame.requestId, pending);
471
+ pending.chunks.push(frame.body);
472
+ return;
473
+ }
474
+ if (frame.type === "response.end") {
475
+ pending.clientApiRoundtripMs = Date.now() - pending.clientApiSentAt;
476
+ pending.cliOverheadMs = frame.cliOverheadMs;
477
+ pending.originMs = frame.originMs;
478
+ this.clearPendingTimers(pending);
479
+ tunnel.pending.delete(frame.requestId);
480
+ const buffer = Buffer.concat(pending.chunks.map((chunk) => Buffer.from(chunk, "base64")));
481
+ pending.resolve(new Response(buffer, {
482
+ status: pending.status ?? 200,
483
+ headers: stripResponseHeaders(pending.headers ?? {})
484
+ }));
485
+ return;
486
+ }
487
+ if (frame.type === "error") {
488
+ this.failPending(tunnel, frame.requestId, pending, new Error(frame.message ?? "Tunnel client error."));
489
+ }
490
+ }
491
+ resetIdleTimer(tunnel, requestId, pending) {
492
+ if (pending.idleTimer)
493
+ clearTimeout(pending.idleTimer);
494
+ pending.idleTimer = setTimeout(() => {
495
+ this.failPending(tunnel, requestId, pending, new Error("Local app response stalled."));
496
+ }, pending.idleTimeoutMs);
497
+ }
498
+ failPending(tunnel, requestId, pending, error) {
499
+ if (!tunnel.pending.has(requestId))
500
+ return;
501
+ this.clearPendingTimers(pending);
502
+ tunnel.pending.delete(requestId);
503
+ pending.reject(error);
504
+ }
505
+ clearPendingTimers(pending) {
506
+ clearTimeout(pending.totalTimer);
507
+ clearTimeout(pending.firstByteTimer);
508
+ if (pending.idleTimer)
509
+ clearTimeout(pending.idleTimer);
510
+ }
511
+ }
512
+ async function safeJson(request) {
513
+ try {
514
+ return await request.json();
515
+ }
516
+ catch {
517
+ return {};
518
+ }
519
+ }
520
+ function json(value, status = 200) {
521
+ return new Response(JSON.stringify(value), {
522
+ status,
523
+ headers: { "content-type": "application/json; charset=utf-8" }
524
+ });
525
+ }
526
+ function buildAuthUrl(base, path, browserKey) {
527
+ const url = new URL(path.startsWith("/") ? path : `/${path}`, base);
528
+ url.searchParams.set("key", browserKey);
529
+ return url.toString();
530
+ }
531
+ async function validateDeviceToken(token, clientIp, userAgent) {
532
+ if (!token)
533
+ return undefined;
534
+ const ipRange = normalizeIpRange(clientIp);
535
+ if (!ipRange)
536
+ return undefined;
537
+ const row = await prisma.clientDeviceToken.findUnique({
538
+ where: { tokenHash: hashSecret(token) }
539
+ });
540
+ if (!row || row.revokedAt || row.expiresAt <= new Date())
541
+ return undefined;
542
+ if (row.ipFamily !== ipRange.family || row.ipRangeHash !== hashSecret(ipRange.cidr))
543
+ return undefined;
544
+ if (row.userAgentHash && row.userAgentHash !== hashSecret(userAgent))
545
+ return undefined;
546
+ await prisma.clientDeviceToken.update({
547
+ where: { id: row.id },
548
+ data: { lastUsedAt: new Date() }
549
+ });
550
+ return { accountId: row.accountId ?? undefined };
551
+ }
552
+ function proxyClientIp(headers) {
553
+ const forwardedFor = firstPublicForwardedIp(firstHeader(headers["x-forwarded-for"]));
554
+ if (forwardedFor)
555
+ return forwardedFor;
556
+ return firstHeader(headers["x-real-ip"])?.trim() || "unknown";
557
+ }
558
+ function proxyClientIpFromHeaders(headers) {
559
+ const forwardedFor = firstPublicForwardedIp(headers.get("x-forwarded-for") ?? undefined);
560
+ if (forwardedFor)
561
+ return forwardedFor;
562
+ return headers.get("x-real-ip")?.trim() || "unknown";
563
+ }
564
+ function firstHeader(value) {
565
+ return Array.isArray(value) ? value[0] : value;
566
+ }
567
+ function firstPublicForwardedIp(value) {
568
+ return value?.split(",").map((ip) => ip.trim()).find((ip) => ip && !isPrivateIp(ip));
569
+ }
570
+ function isPrivateIp(ip) {
571
+ return ip === "unknown"
572
+ || ip.startsWith("10.")
573
+ || ip.startsWith("192.168.")
574
+ || /^172\.(1[6-9]|2\d|3[0-1])\./.test(ip)
575
+ || ip.startsWith("127.")
576
+ || ip.startsWith("::1")
577
+ || ip.startsWith("fc")
578
+ || ip.startsWith("fd")
579
+ || ip.startsWith("fe80:");
580
+ }
581
+ function stripResponseHeaders(headers) {
582
+ const out = new Headers();
583
+ for (const [name, value] of Object.entries(headers)) {
584
+ const key = name.toLowerCase();
585
+ if (key === "set-cookie" || key === "connection" || key === "transfer-encoding")
586
+ continue;
587
+ out.set(name, value);
588
+ }
589
+ return out;
590
+ }
591
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/service-tunnel-client-api/index.ts"],"names":[],"mappings":"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"}