@kortix/agent-tunnel 0.13.56 → 0.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/dist/agent-cli.js +71 -66
- package/package.json +4 -3
- package/src/agent/cli.ts +3 -2
- package/src/server/routes.ts +9 -9
- package/src/server/server.test.ts +17 -0
- package/src/shared/types.ts +1 -1
package/dist/agent-cli.js
CHANGED
|
@@ -19,13 +19,15 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
19
19
|
return cached;
|
|
20
20
|
}
|
|
21
21
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
const to = isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
+
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
24
|
+
for (let key of __getOwnPropNames(mod))
|
|
25
|
+
if (!__hasOwnProp.call(to, key))
|
|
26
|
+
__defProp(to, key, {
|
|
27
|
+
get: __accessProp.bind(mod, key),
|
|
28
|
+
enumerable: true
|
|
29
|
+
});
|
|
30
|
+
}
|
|
29
31
|
if (canCache)
|
|
30
32
|
cache.set(mod, to);
|
|
31
33
|
return to;
|
|
@@ -44,11 +46,21 @@ var __export = (target, all) => {
|
|
|
44
46
|
set: __exportSetter.bind(all, name)
|
|
45
47
|
});
|
|
46
48
|
};
|
|
47
|
-
var __esm = (fn, res) => () =>
|
|
49
|
+
var __esm = (fn, res, err) => () => {
|
|
50
|
+
if (fn)
|
|
51
|
+
try {
|
|
52
|
+
res = fn(fn = 0);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
err = [e];
|
|
55
|
+
}
|
|
56
|
+
if (err)
|
|
57
|
+
throw err[0];
|
|
58
|
+
return res;
|
|
59
|
+
};
|
|
48
60
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
49
61
|
|
|
50
62
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/constants.js
|
|
51
|
-
var require_constants = __commonJS((exports, module)
|
|
63
|
+
var require_constants = __commonJS(function(exports, module) {
|
|
52
64
|
var BINARY_TYPES = ["nodebuffer", "arraybuffer", "fragments"];
|
|
53
65
|
var hasBlob = typeof Blob !== "undefined";
|
|
54
66
|
if (hasBlob)
|
|
@@ -68,7 +80,7 @@ var require_constants = __commonJS((exports, module) => {
|
|
|
68
80
|
});
|
|
69
81
|
|
|
70
82
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/buffer-util.js
|
|
71
|
-
var require_buffer_util = __commonJS((exports, module)
|
|
83
|
+
var require_buffer_util = __commonJS(function(exports, module) {
|
|
72
84
|
var { EMPTY_BUFFER } = require_constants();
|
|
73
85
|
var FastBuffer = Buffer[Symbol.species];
|
|
74
86
|
function concat(list, totalLength) {
|
|
@@ -129,11 +141,11 @@ var require_buffer_util = __commonJS((exports, module) => {
|
|
|
129
141
|
if (!process.env.WS_NO_BUFFER_UTIL) {
|
|
130
142
|
try {
|
|
131
143
|
const bufferUtil = (()=>{throw new Error("Cannot require module "+"bufferutil");})();
|
|
132
|
-
module.exports.mask = function(source,
|
|
144
|
+
module.exports.mask = function(source, mask2, output, offset, length) {
|
|
133
145
|
if (length < 48)
|
|
134
|
-
_mask(source,
|
|
146
|
+
_mask(source, mask2, output, offset, length);
|
|
135
147
|
else
|
|
136
|
-
bufferUtil.mask(source,
|
|
148
|
+
bufferUtil.mask(source, mask2, output, offset, length);
|
|
137
149
|
};
|
|
138
150
|
module.exports.unmask = function(buffer, mask) {
|
|
139
151
|
if (buffer.length < 32)
|
|
@@ -146,7 +158,7 @@ var require_buffer_util = __commonJS((exports, module) => {
|
|
|
146
158
|
});
|
|
147
159
|
|
|
148
160
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/limiter.js
|
|
149
|
-
var require_limiter = __commonJS((exports, module)
|
|
161
|
+
var require_limiter = __commonJS(function(exports, module) {
|
|
150
162
|
var kDone = Symbol("kDone");
|
|
151
163
|
var kRun = Symbol("kRun");
|
|
152
164
|
|
|
@@ -178,7 +190,7 @@ var require_limiter = __commonJS((exports, module) => {
|
|
|
178
190
|
});
|
|
179
191
|
|
|
180
192
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/permessage-deflate.js
|
|
181
|
-
var require_permessage_deflate = __commonJS((exports, module)
|
|
193
|
+
var require_permessage_deflate = __commonJS(function(exports, module) {
|
|
182
194
|
var zlib = __require("zlib");
|
|
183
195
|
var bufferUtil = require_buffer_util();
|
|
184
196
|
var Limiter = require_limiter();
|
|
@@ -366,7 +378,7 @@ var require_permessage_deflate = __commonJS((exports, module) => {
|
|
|
366
378
|
callback(err);
|
|
367
379
|
return;
|
|
368
380
|
}
|
|
369
|
-
const
|
|
381
|
+
const data = bufferUtil.concat(this._inflate[kBuffers], this._inflate[kTotalLength]);
|
|
370
382
|
if (this._inflate._readableState.endEmitted) {
|
|
371
383
|
this._inflate.close();
|
|
372
384
|
this._inflate = null;
|
|
@@ -377,7 +389,7 @@ var require_permessage_deflate = __commonJS((exports, module) => {
|
|
|
377
389
|
this._inflate.reset();
|
|
378
390
|
}
|
|
379
391
|
}
|
|
380
|
-
callback(null,
|
|
392
|
+
callback(null, data);
|
|
381
393
|
});
|
|
382
394
|
}
|
|
383
395
|
_compress(data, fin, callback) {
|
|
@@ -399,9 +411,9 @@ var require_permessage_deflate = __commonJS((exports, module) => {
|
|
|
399
411
|
if (!this._deflate) {
|
|
400
412
|
return;
|
|
401
413
|
}
|
|
402
|
-
let
|
|
414
|
+
let data = bufferUtil.concat(this._deflate[kBuffers], this._deflate[kTotalLength]);
|
|
403
415
|
if (fin) {
|
|
404
|
-
|
|
416
|
+
data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);
|
|
405
417
|
}
|
|
406
418
|
this._deflate[kCallback] = null;
|
|
407
419
|
this._deflate[kTotalLength] = 0;
|
|
@@ -409,7 +421,7 @@ var require_permessage_deflate = __commonJS((exports, module) => {
|
|
|
409
421
|
if (fin && this.params[`${endpoint}_no_context_takeover`]) {
|
|
410
422
|
this._deflate.reset();
|
|
411
423
|
}
|
|
412
|
-
callback(null,
|
|
424
|
+
callback(null, data);
|
|
413
425
|
});
|
|
414
426
|
}
|
|
415
427
|
}
|
|
@@ -442,7 +454,7 @@ var require_permessage_deflate = __commonJS((exports, module) => {
|
|
|
442
454
|
});
|
|
443
455
|
|
|
444
456
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/validation.js
|
|
445
|
-
var require_validation = __commonJS((exports, module)
|
|
457
|
+
var require_validation = __commonJS(function(exports, module) {
|
|
446
458
|
var { isUtf8 } = __require("buffer");
|
|
447
459
|
var { hasBlob } = require_constants();
|
|
448
460
|
var tokenChars = [
|
|
@@ -629,7 +641,7 @@ var require_validation = __commonJS((exports, module) => {
|
|
|
629
641
|
});
|
|
630
642
|
|
|
631
643
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/receiver.js
|
|
632
|
-
var require_receiver = __commonJS((exports, module)
|
|
644
|
+
var require_receiver = __commonJS(function(exports, module) {
|
|
633
645
|
var { Writable } = __require("stream");
|
|
634
646
|
var PerMessageDeflate = require_permessage_deflate();
|
|
635
647
|
var {
|
|
@@ -1023,7 +1035,7 @@ var require_receiver = __commonJS((exports, module) => {
|
|
|
1023
1035
|
});
|
|
1024
1036
|
|
|
1025
1037
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/sender.js
|
|
1026
|
-
var require_sender = __commonJS((exports, module)
|
|
1038
|
+
var require_sender = __commonJS(function(exports, module) {
|
|
1027
1039
|
var { Duplex } = __require("stream");
|
|
1028
1040
|
var { randomFillSync } = __require("crypto");
|
|
1029
1041
|
var {
|
|
@@ -1382,7 +1394,7 @@ var require_sender = __commonJS((exports, module) => {
|
|
|
1382
1394
|
});
|
|
1383
1395
|
|
|
1384
1396
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/event-target.js
|
|
1385
|
-
var require_event_target = __commonJS((exports, module)
|
|
1397
|
+
var require_event_target = __commonJS(function(exports, module) {
|
|
1386
1398
|
var { kForOnEventAttribute, kListener } = require_constants();
|
|
1387
1399
|
var kCode = Symbol("kCode");
|
|
1388
1400
|
var kData = Symbol("kData");
|
|
@@ -1533,7 +1545,7 @@ var require_event_target = __commonJS((exports, module) => {
|
|
|
1533
1545
|
});
|
|
1534
1546
|
|
|
1535
1547
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/extension.js
|
|
1536
|
-
var require_extension = __commonJS((exports, module)
|
|
1548
|
+
var require_extension = __commonJS(function(exports, module) {
|
|
1537
1549
|
var { tokenChars } = require_validation();
|
|
1538
1550
|
function push(dest, name, elem) {
|
|
1539
1551
|
if (dest[name] === undefined)
|
|
@@ -1698,7 +1710,7 @@ var require_extension = __commonJS((exports, module) => {
|
|
|
1698
1710
|
});
|
|
1699
1711
|
|
|
1700
1712
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/websocket.js
|
|
1701
|
-
var require_websocket = __commonJS((exports, module)
|
|
1713
|
+
var require_websocket = __commonJS(function(exports, module) {
|
|
1702
1714
|
var EventEmitter = __require("events");
|
|
1703
1715
|
var https = __require("https");
|
|
1704
1716
|
var http = __require("http");
|
|
@@ -2121,7 +2133,7 @@ var require_websocket = __commonJS((exports, module) => {
|
|
|
2121
2133
|
}
|
|
2122
2134
|
const defaultPort = isSecure ? 443 : 80;
|
|
2123
2135
|
const key = randomBytes(16).toString("base64");
|
|
2124
|
-
const
|
|
2136
|
+
const request3 = isSecure ? https.request : http.request;
|
|
2125
2137
|
const protocolSet = new Set;
|
|
2126
2138
|
let perMessageDeflate;
|
|
2127
2139
|
opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
|
|
@@ -2180,8 +2192,8 @@ var require_websocket = __commonJS((exports, module) => {
|
|
|
2180
2192
|
const headers = options && options.headers;
|
|
2181
2193
|
options = { ...options, headers: {} };
|
|
2182
2194
|
if (headers) {
|
|
2183
|
-
for (const [
|
|
2184
|
-
options.headers[
|
|
2195
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
2196
|
+
options.headers[key.toLowerCase()] = value;
|
|
2185
2197
|
}
|
|
2186
2198
|
}
|
|
2187
2199
|
} else if (websocket.listenerCount("redirect") === 0) {
|
|
@@ -2197,12 +2209,12 @@ var require_websocket = __commonJS((exports, module) => {
|
|
|
2197
2209
|
if (opts.auth && !options.headers.authorization) {
|
|
2198
2210
|
options.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64");
|
|
2199
2211
|
}
|
|
2200
|
-
req = websocket._req =
|
|
2212
|
+
req = websocket._req = request3(opts);
|
|
2201
2213
|
if (websocket._redirects) {
|
|
2202
2214
|
websocket.emit("redirect", websocket.url, req);
|
|
2203
2215
|
}
|
|
2204
2216
|
} else {
|
|
2205
|
-
req = websocket._req =
|
|
2217
|
+
req = websocket._req = request3(opts);
|
|
2206
2218
|
}
|
|
2207
2219
|
if (opts.timeout) {
|
|
2208
2220
|
req.on("timeout", () => {
|
|
@@ -2470,7 +2482,7 @@ var require_websocket = __commonJS((exports, module) => {
|
|
|
2470
2482
|
});
|
|
2471
2483
|
|
|
2472
2484
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/stream.js
|
|
2473
|
-
var require_stream = __commonJS((exports, module)
|
|
2485
|
+
var require_stream = __commonJS(function(exports, module) {
|
|
2474
2486
|
var WebSocket2 = require_websocket();
|
|
2475
2487
|
var { Duplex } = __require("stream");
|
|
2476
2488
|
function emitClose(stream) {
|
|
@@ -2520,9 +2532,9 @@ var require_stream = __commonJS((exports, module) => {
|
|
|
2520
2532
|
return;
|
|
2521
2533
|
}
|
|
2522
2534
|
let called = false;
|
|
2523
|
-
ws.once("error", function error(
|
|
2535
|
+
ws.once("error", function error(err) {
|
|
2524
2536
|
called = true;
|
|
2525
|
-
callback(
|
|
2537
|
+
callback(err);
|
|
2526
2538
|
});
|
|
2527
2539
|
ws.once("close", function close() {
|
|
2528
2540
|
if (!called)
|
|
@@ -2573,7 +2585,7 @@ var require_stream = __commonJS((exports, module) => {
|
|
|
2573
2585
|
});
|
|
2574
2586
|
|
|
2575
2587
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/subprotocol.js
|
|
2576
|
-
var require_subprotocol = __commonJS((exports, module)
|
|
2588
|
+
var require_subprotocol = __commonJS(function(exports, module) {
|
|
2577
2589
|
var { tokenChars } = require_validation();
|
|
2578
2590
|
function parse(header) {
|
|
2579
2591
|
const protocols = new Set;
|
|
@@ -2594,11 +2606,11 @@ var require_subprotocol = __commonJS((exports, module) => {
|
|
|
2594
2606
|
}
|
|
2595
2607
|
if (end === -1)
|
|
2596
2608
|
end = i;
|
|
2597
|
-
const
|
|
2598
|
-
if (protocols.has(
|
|
2599
|
-
throw new SyntaxError(`The "${
|
|
2609
|
+
const protocol = header.slice(start, end);
|
|
2610
|
+
if (protocols.has(protocol)) {
|
|
2611
|
+
throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
|
|
2600
2612
|
}
|
|
2601
|
-
protocols.add(
|
|
2613
|
+
protocols.add(protocol);
|
|
2602
2614
|
start = end = -1;
|
|
2603
2615
|
} else {
|
|
2604
2616
|
throw new SyntaxError(`Unexpected character at index ${i}`);
|
|
@@ -2618,7 +2630,7 @@ var require_subprotocol = __commonJS((exports, module) => {
|
|
|
2618
2630
|
});
|
|
2619
2631
|
|
|
2620
2632
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/lib/websocket-server.js
|
|
2621
|
-
var require_websocket_server = __commonJS((exports, module)
|
|
2633
|
+
var require_websocket_server = __commonJS(function(exports, module) {
|
|
2622
2634
|
var EventEmitter = __require("events");
|
|
2623
2635
|
var http = __require("http");
|
|
2624
2636
|
var { Duplex } = __require("stream");
|
|
@@ -2930,15 +2942,8 @@ var require_websocket_server = __commonJS((exports, module) => {
|
|
|
2930
2942
|
// ../../node_modules/.pnpm/ws@8.21.3/node_modules/ws/wrapper.mjs
|
|
2931
2943
|
var exports_wrapper = {};
|
|
2932
2944
|
__export(exports_wrapper, {
|
|
2933
|
-
subprotocol: () => import_subprotocol.default,
|
|
2934
|
-
extension: () => import_extension.default,
|
|
2935
|
-
default: () => wrapper_default,
|
|
2936
|
-
createWebSocketStream: () => import_stream.default,
|
|
2937
|
-
WebSocketServer: () => import_websocket_server.default,
|
|
2938
2945
|
WebSocket: () => import_websocket.default,
|
|
2939
|
-
|
|
2940
|
-
Receiver: () => import_receiver.default,
|
|
2941
|
-
PerMessageDeflate: () => import_permessage_deflate.default
|
|
2946
|
+
default: () => wrapper_default
|
|
2942
2947
|
});
|
|
2943
2948
|
var import_stream, import_extension, import_permessage_deflate, import_receiver, import_sender, import_subprotocol, import_websocket, import_websocket_server, wrapper_default;
|
|
2944
2949
|
var init_wrapper = __esm(() => {
|
|
@@ -2957,7 +2962,7 @@ var init_wrapper = __esm(() => {
|
|
|
2957
2962
|
if (typeof globalThis.WebSocket === "undefined") {
|
|
2958
2963
|
try {
|
|
2959
2964
|
const ws = await Promise.resolve().then(() => (init_wrapper(), exports_wrapper));
|
|
2960
|
-
const WebSocketImpl = ws.WebSocket ??
|
|
2965
|
+
const WebSocketImpl = ws.WebSocket ?? wrapper_default;
|
|
2961
2966
|
globalThis.WebSocket = WebSocketImpl;
|
|
2962
2967
|
} catch {
|
|
2963
2968
|
console.error('[agent-tunnel] WebSocket is not available. Install the "ws" package or use Node.js 22+.');
|
|
@@ -3677,10 +3682,10 @@ function wakeDesktopApp(home = agentTunnelHome(), now = Date.now()) {
|
|
|
3677
3682
|
return "no-app";
|
|
3678
3683
|
}
|
|
3679
3684
|
}
|
|
3680
|
-
function keepAwakeCommand(
|
|
3681
|
-
if (
|
|
3685
|
+
function keepAwakeCommand(platform, pid) {
|
|
3686
|
+
if (platform === "darwin")
|
|
3682
3687
|
return { command: "caffeinate", args: ["-s", "-w", String(pid)] };
|
|
3683
|
-
if (
|
|
3688
|
+
if (platform === "linux") {
|
|
3684
3689
|
return {
|
|
3685
3690
|
command: "systemd-inhibit",
|
|
3686
3691
|
args: ["--what=sleep", "--who=Kortix", "--why=Keep this computer reachable", "--mode=block", "tail", `--pid=${pid}`, "-f", "/dev/null"]
|
|
@@ -3947,7 +3952,7 @@ function visibleLength(value) {
|
|
|
3947
3952
|
function clearScreen() {
|
|
3948
3953
|
process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
3949
3954
|
}
|
|
3950
|
-
var sleep = (ms) => new Promise((
|
|
3955
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
3951
3956
|
var glyph = {
|
|
3952
3957
|
on: `${c.green}●${c.reset}`,
|
|
3953
3958
|
off: `${c.gray}○${c.reset}`,
|
|
@@ -4485,7 +4490,7 @@ class TunnelAgent {
|
|
|
4485
4490
|
} catch {}
|
|
4486
4491
|
const deadline = Date.now() + hold;
|
|
4487
4492
|
while (Date.now() < deadline) {
|
|
4488
|
-
await new Promise((
|
|
4493
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(100, hold / 4)));
|
|
4489
4494
|
const decision = decideAccess(readAccess(this.home));
|
|
4490
4495
|
if (decision === "ask")
|
|
4491
4496
|
continue;
|
|
@@ -4527,7 +4532,7 @@ class TunnelAgent {
|
|
|
4527
4532
|
const hold = this.options.accessHoldMs ?? ACCESS_HOLD_MS;
|
|
4528
4533
|
const deadline = Date.now() + hold;
|
|
4529
4534
|
while (Date.now() < deadline) {
|
|
4530
|
-
await new Promise((
|
|
4535
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(100, hold / 4)));
|
|
4531
4536
|
if (!accessWidens(readAccess(this.home), target, this.now())) {
|
|
4532
4537
|
clearAccessRequest(asked.id, this.home);
|
|
4533
4538
|
return accessView(this.home, platform3(), this.now());
|
|
@@ -4853,7 +4858,7 @@ function hostBundleId() {
|
|
|
4853
4858
|
}
|
|
4854
4859
|
}
|
|
4855
4860
|
function execFile(cmd, args, timeoutMs = 30000, env = driverEnvironment()) {
|
|
4856
|
-
return new Promise((
|
|
4861
|
+
return new Promise((resolve, reject) => {
|
|
4857
4862
|
const proc = spawn4(cmd, args, {
|
|
4858
4863
|
stdio: ["ignore", "pipe", "pipe"],
|
|
4859
4864
|
env
|
|
@@ -4898,7 +4903,7 @@ function execFile(cmd, args, timeoutMs = 30000, env = driverEnvironment()) {
|
|
|
4898
4903
|
const detail = stderr.trim() || stdout.trim();
|
|
4899
4904
|
reject(new Error(`${basename2(cmd)} failed (${code})${detail ? `: ${detail}` : ""}`));
|
|
4900
4905
|
} else {
|
|
4901
|
-
|
|
4906
|
+
resolve({ stdout, stderr });
|
|
4902
4907
|
}
|
|
4903
4908
|
});
|
|
4904
4909
|
proc.on("error", (err) => {
|
|
@@ -4920,7 +4925,7 @@ function isDaemonProxyFallback(message) {
|
|
|
4920
4925
|
return message.includes("daemon proxy") && message.includes("Resource temporarily unavailable");
|
|
4921
4926
|
}
|
|
4922
4927
|
async function sleep2(ms) {
|
|
4923
|
-
await new Promise((
|
|
4928
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
4924
4929
|
}
|
|
4925
4930
|
function sanitizeArgs(args) {
|
|
4926
4931
|
const sanitized = {};
|
|
@@ -5546,7 +5551,7 @@ function createShellCapability(config) {
|
|
|
5546
5551
|
safeEnv[key] = process.env[key];
|
|
5547
5552
|
}
|
|
5548
5553
|
}
|
|
5549
|
-
return new Promise((
|
|
5554
|
+
return new Promise((resolve, reject) => {
|
|
5550
5555
|
const proc = spawn5(executable, args, {
|
|
5551
5556
|
cwd,
|
|
5552
5557
|
shell: false,
|
|
@@ -5589,7 +5594,7 @@ function createShellCapability(config) {
|
|
|
5589
5594
|
reject(new Error(`Command failed to start: ${err.message}`));
|
|
5590
5595
|
});
|
|
5591
5596
|
proc.on("close", (code, signal) => {
|
|
5592
|
-
|
|
5597
|
+
resolve({
|
|
5593
5598
|
exitCode: code,
|
|
5594
5599
|
signal,
|
|
5595
5600
|
stdout,
|
|
@@ -5678,17 +5683,17 @@ function clearSavedCredentials() {
|
|
|
5678
5683
|
// src/agent/credential-probe.ts
|
|
5679
5684
|
var DEFAULT_PROBE_TIMEOUT_MS = 1e4;
|
|
5680
5685
|
function probeCredentials(config, options = {}) {
|
|
5681
|
-
return new Promise((
|
|
5686
|
+
return new Promise((resolve) => {
|
|
5682
5687
|
let socket;
|
|
5683
5688
|
try {
|
|
5684
5689
|
socket = openRelaySocket(new URL(buildTunnelWsUrl(config)).href);
|
|
5685
5690
|
} catch {
|
|
5686
|
-
|
|
5691
|
+
resolve("unreachable");
|
|
5687
5692
|
return;
|
|
5688
5693
|
}
|
|
5689
5694
|
const settle = (result) => {
|
|
5690
5695
|
clearTimeout(timer);
|
|
5691
|
-
|
|
5696
|
+
resolve(result);
|
|
5692
5697
|
try {
|
|
5693
5698
|
socket.close(1000, "probe complete");
|
|
5694
5699
|
} catch {}
|
|
@@ -6262,8 +6267,8 @@ import { statSync as statSync3 } from "fs";
|
|
|
6262
6267
|
function runtimeFingerprint(files) {
|
|
6263
6268
|
return files.map((file) => {
|
|
6264
6269
|
try {
|
|
6265
|
-
const
|
|
6266
|
-
return `${
|
|
6270
|
+
const stat = statSync3(file);
|
|
6271
|
+
return `${stat.ino}:${stat.mtimeMs}:${stat.size}`;
|
|
6267
6272
|
} catch {
|
|
6268
6273
|
return "missing";
|
|
6269
6274
|
}
|
|
@@ -6405,7 +6410,6 @@ function startAgent(config, options = {}) {
|
|
|
6405
6410
|
persistent: options.service === true,
|
|
6406
6411
|
reloadConfig: () => loadConfig({ apiUrl: config.apiUrl })
|
|
6407
6412
|
});
|
|
6408
|
-
agent.connect();
|
|
6409
6413
|
const shutdown = () => {
|
|
6410
6414
|
if (!options.service)
|
|
6411
6415
|
console.log(`
|
|
@@ -6415,6 +6419,7 @@ ${c.dim} Shutting down…${c.reset}`);
|
|
|
6415
6419
|
};
|
|
6416
6420
|
process.on("SIGTERM", shutdown);
|
|
6417
6421
|
process.on("SIGINT", shutdown);
|
|
6422
|
+
agent.connect();
|
|
6418
6423
|
}
|
|
6419
6424
|
function chooseBackgroundMode(flags) {
|
|
6420
6425
|
if (anyFlag(flags, BACKGROUND_FLAGS))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kortix/agent-tunnel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/kortix-ai/suna.git",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "bun build src/agent/cli.ts --target=node --outfile=dist/agent-cli.js --banner='#!/usr/bin/env node' && bun build src/client/cli.ts --target=node --outfile=dist/client-cli.js --banner='#!/usr/bin/env node' && node -e \"const fs=require('node:fs'); fs.chmodSync('dist/agent-cli.js', 0o755); fs.chmodSync('dist/client-cli.js', 0o755);\"",
|
|
33
33
|
"prepack": "bun run build",
|
|
34
|
-
"typecheck": "
|
|
35
|
-
"test": "bun test --timeout ${KORTIX_TEST_TIMEOUT_MS:-15000}"
|
|
34
|
+
"typecheck": "tsgo --noEmit --incremental --tsBuildInfoFile node_modules/.cache/tsgo.tsbuildinfo",
|
|
35
|
+
"test": "node ../../scripts/test-guard.mjs \"bun test --timeout ${KORTIX_TEST_TIMEOUT_MS:-15000}\""
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"hono": "^4.13.7",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/bun": "^1.3.9",
|
|
43
43
|
"@types/ws": "^8.5.13",
|
|
44
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
44
45
|
"typescript": "^5.4.0"
|
|
45
46
|
},
|
|
46
47
|
"keywords": [
|
package/src/agent/cli.ts
CHANGED
|
@@ -149,8 +149,8 @@ function startAgent(config: TunnelConfig, options: { service?: boolean } = {}):
|
|
|
149
149
|
reloadConfig: () => loadConfig({ apiUrl: config.apiUrl }),
|
|
150
150
|
},
|
|
151
151
|
);
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
// Before connect(): connect() writes state.json, and a SIGTERM that lands
|
|
153
|
+
// before a handler exists kills the process with the state left `connecting`.
|
|
154
154
|
const shutdown = () => {
|
|
155
155
|
if (!options.service) console.log(`\n${c.dim} Shutting down…${c.reset}`);
|
|
156
156
|
agent?.disconnect();
|
|
@@ -158,6 +158,7 @@ function startAgent(config: TunnelConfig, options: { service?: boolean } = {}):
|
|
|
158
158
|
};
|
|
159
159
|
process.on('SIGTERM', shutdown);
|
|
160
160
|
process.on('SIGINT', shutdown);
|
|
161
|
+
agent.connect();
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
// ── pairing ──────────────────────────────────────────────────────────────────
|
package/src/server/routes.ts
CHANGED
|
@@ -9,15 +9,15 @@ export function createTunnelRouter(
|
|
|
9
9
|
): Hono {
|
|
10
10
|
const router = new Hono();
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
12
|
+
// Fail closed: these routes list agents and relay RPC to them (shell, files,
|
|
13
|
+
// desktop). With no authorizer, nobody is authorized.
|
|
14
|
+
router.use('*', async (c, next) => {
|
|
15
|
+
const authorized = onAuthorizeHTTP ? await onAuthorizeHTTP(c.req.raw) : false;
|
|
16
|
+
if (!authorized) {
|
|
17
|
+
return c.json({ error: 'Unauthorized' }, 403);
|
|
18
|
+
}
|
|
19
|
+
await next();
|
|
20
|
+
});
|
|
21
21
|
|
|
22
22
|
router.get('/connections', (c) => {
|
|
23
23
|
const agents = relay.getConnectedAgents();
|
|
@@ -31,3 +31,20 @@ describe('standalone tunnel WebSocket boundary', () => {
|
|
|
31
31
|
expect(server.relay.getConnectedCount()).toBe(0);
|
|
32
32
|
});
|
|
33
33
|
});
|
|
34
|
+
|
|
35
|
+
describe('standalone tunnel HTTP routes', () => {
|
|
36
|
+
// Pentest: with no onAuthorizeHTTP the routes listed agents and relayed RPC to anyone.
|
|
37
|
+
test('fail closed when no HTTP authorizer is configured', async () => {
|
|
38
|
+
server = startTunnelServer({ port: 0 });
|
|
39
|
+
const base = `http://127.0.0.1:${server.port}`;
|
|
40
|
+
expect((await fetch(`${base}/connections`)).status).toBe(403);
|
|
41
|
+
expect((await fetch(`${base}/rpc/00000000-0000-4000-8000-000000000001`, { method: 'POST', body: '{}' })).status).toBe(403);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('serve a caller the authorizer accepts', async () => {
|
|
45
|
+
server = startTunnelServer({ port: 0, onAuthorizeHTTP: async (req) => req.headers.get('authorization') === 'Bearer ok' });
|
|
46
|
+
const base = `http://127.0.0.1:${server.port}`;
|
|
47
|
+
expect((await fetch(`${base}/connections`, { headers: { authorization: 'Bearer ok' } })).status).toBe(200);
|
|
48
|
+
expect((await fetch(`${base}/connections`)).status).toBe(403);
|
|
49
|
+
});
|
|
50
|
+
});
|
package/src/shared/types.ts
CHANGED
|
@@ -200,7 +200,7 @@ export interface TunnelServerConfig {
|
|
|
200
200
|
) => Promise<boolean>;
|
|
201
201
|
/**
|
|
202
202
|
* Called before handling HTTP requests to relay routes (/connections, /rpc).
|
|
203
|
-
* Return false to deny. If not provided,
|
|
203
|
+
* Return false to deny. If not provided, every request is denied (403).
|
|
204
204
|
*/
|
|
205
205
|
onAuthorizeHTTP?: (req: Request) => Promise<boolean>;
|
|
206
206
|
}
|