@ai-ecoverse/slicc-kernel 1.180.0 → 1.182.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 +32 -6
- package/dist/driver-worker.js +15 -1
- package/dist/driver-worker.js.map +2 -2
- package/dist/index.js +26 -1
- package/dist/index.js.map +3 -3
- package/dist/kernel-worker.js +373 -96
- package/dist/kernel-worker.js.map +3 -3
- package/dist/node-driver-worker.js +15 -1
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +389 -95
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +1 -1
- package/dist/types/cdp/types.d.ts +2 -0
- package/dist/types/client/attach.d.ts +12 -0
- package/dist/types/client/protocol.d.ts +9 -0
- package/dist/types/index.d.ts +5 -3
- package/dist/types/kernel/children.d.ts +2 -1
- package/dist/types/kernel/socket.d.ts +2 -0
- package/dist/types/launcher.d.ts +22 -0
- package/dist/types/node.d.ts +5 -3
- package/dist/types/serve.d.ts +11 -1
- package/dist/types/sudo.d.ts +15 -1
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -2454,6 +2454,7 @@ var LoopbackNet = class {
|
|
|
2454
2454
|
reserved = /* @__PURE__ */ new Set();
|
|
2455
2455
|
facades = /* @__PURE__ */ new Map();
|
|
2456
2456
|
proxyStamped;
|
|
2457
|
+
stamped = /* @__PURE__ */ new Set();
|
|
2457
2458
|
nextEphemeral = EPHEMERAL_FIRST;
|
|
2458
2459
|
route;
|
|
2459
2460
|
origins;
|
|
@@ -2528,6 +2529,9 @@ var LoopbackNet = class {
|
|
|
2528
2529
|
this.kernelOnly(port, true);
|
|
2529
2530
|
this.facades.set(port, name2);
|
|
2530
2531
|
}
|
|
2532
|
+
stampPeers(port) {
|
|
2533
|
+
this.stamped.add(port);
|
|
2534
|
+
}
|
|
2531
2535
|
stampProxy(port) {
|
|
2532
2536
|
this.proxyStamped = port;
|
|
2533
2537
|
}
|
|
@@ -2536,7 +2540,7 @@ var LoopbackNet = class {
|
|
|
2536
2540
|
}
|
|
2537
2541
|
stampsPeers(addr) {
|
|
2538
2542
|
if (addr.family !== "inet" || !isLoopback(canonicalHost(addr.host))) return false;
|
|
2539
|
-
return this.facades.has(addr.port) || this.proxyStamped === addr.port;
|
|
2543
|
+
return this.facades.has(addr.port) || this.stamped.has(addr.port) || this.proxyStamped === addr.port;
|
|
2540
2544
|
}
|
|
2541
2545
|
activate(addr, start2) {
|
|
2542
2546
|
this.activators.set(keyOf(addr), start2);
|
|
@@ -3444,10 +3448,10 @@ var CdpFacade = class {
|
|
|
3444
3448
|
);
|
|
3445
3449
|
return;
|
|
3446
3450
|
}
|
|
3447
|
-
await this.write(conn, json(await this.list(runtime)));
|
|
3451
|
+
await this.write(conn, json(await this.list(runtime, conn.peerStamp)));
|
|
3448
3452
|
}
|
|
3449
|
-
async list(runtime) {
|
|
3450
|
-
const conn = await this.host(runtime);
|
|
3453
|
+
async list(runtime, stamp) {
|
|
3454
|
+
const conn = await this.host(runtime, stamp);
|
|
3451
3455
|
try {
|
|
3452
3456
|
const reply = await new Promise(
|
|
3453
3457
|
(resolve2, reject) => {
|
|
@@ -3482,12 +3486,15 @@ var CdpFacade = class {
|
|
|
3482
3486
|
conn.close();
|
|
3483
3487
|
}
|
|
3484
3488
|
}
|
|
3485
|
-
host(runtime) {
|
|
3486
|
-
return this.options.hosts.connect(
|
|
3489
|
+
host(runtime, stamp) {
|
|
3490
|
+
return this.options.hosts.connect({
|
|
3491
|
+
...runtime ? { runtime } : {},
|
|
3492
|
+
...stamp ? { stamp } : {}
|
|
3493
|
+
});
|
|
3487
3494
|
}
|
|
3488
3495
|
async upgrade(conn, incoming, req, runtime) {
|
|
3489
3496
|
const accept2 = await acceptKey(req.headers);
|
|
3490
|
-
const host = await this.host(runtime);
|
|
3497
|
+
const host = await this.host(runtime, conn.peerStamp);
|
|
3491
3498
|
const limits = {
|
|
3492
3499
|
max: this.options.maxMessage ?? MAX_MESSAGE,
|
|
3493
3500
|
closeWaitMs: this.options.closeWaitMs ?? CLOSE_WAIT_MS
|
|
@@ -3567,6 +3574,7 @@ function enableCdp(net, hosts) {
|
|
|
3567
3574
|
let facade;
|
|
3568
3575
|
net.kernelOnly(CDP_PORT, true);
|
|
3569
3576
|
net.reserve(CDP_PORT);
|
|
3577
|
+
net.stampPeers(CDP_PORT);
|
|
3570
3578
|
net.activate({ family: "inet", host: "127.0.0.1", port: CDP_PORT }, () => {
|
|
3571
3579
|
const started = new CdpFacade({ net, hosts });
|
|
3572
3580
|
facade = started;
|
|
@@ -3609,7 +3617,7 @@ var CdpHosts = class {
|
|
|
3609
3617
|
if (!entry) throw new HttpError(503, NO_CDP_HOST);
|
|
3610
3618
|
let conn;
|
|
3611
3619
|
try {
|
|
3612
|
-
conn = await entry.hook(request
|
|
3620
|
+
conn = await entry.hook(hookRequest(request));
|
|
3613
3621
|
} catch (e) {
|
|
3614
3622
|
throw new HttpError(502, `CDP host: ${e instanceof Error ? e.message : String(e)}`);
|
|
3615
3623
|
}
|
|
@@ -3629,6 +3637,12 @@ var CdpHosts = class {
|
|
|
3629
3637
|
for (const entry of [this.embedder, ...this.clients]) if (entry) closeAll(entry);
|
|
3630
3638
|
}
|
|
3631
3639
|
};
|
|
3640
|
+
function hookRequest({ runtime, stamp }) {
|
|
3641
|
+
return {
|
|
3642
|
+
...runtime ? { runtime } : {},
|
|
3643
|
+
...stamp ? { stamp: structuredClone(stamp) } : {}
|
|
3644
|
+
};
|
|
3645
|
+
}
|
|
3632
3646
|
function closeAll(entry) {
|
|
3633
3647
|
for (const conn of [...entry.open]) {
|
|
3634
3648
|
conn.close();
|
|
@@ -3787,7 +3801,7 @@ function satisfies(version, range2) {
|
|
|
3787
3801
|
}
|
|
3788
3802
|
|
|
3789
3803
|
// src/version.ts
|
|
3790
|
-
var KERNEL_VERSION = true ? "1.
|
|
3804
|
+
var KERNEL_VERSION = true ? "1.182.0" : "0.0.0-dev";
|
|
3791
3805
|
var OS_RELEASE = "6.0.0-slicc";
|
|
3792
3806
|
function procVersion() {
|
|
3793
3807
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -4652,27 +4666,27 @@ function hashId(text) {
|
|
|
4652
4666
|
return hex4(a) + hex4(b);
|
|
4653
4667
|
}
|
|
4654
4668
|
function split(text, count2) {
|
|
4655
|
-
const
|
|
4669
|
+
const words3 = [];
|
|
4656
4670
|
let rest2 = text;
|
|
4657
4671
|
for (let i = 0; i < count2; i++) {
|
|
4658
4672
|
const match = /^(\S+)\s+/.exec(rest2);
|
|
4659
4673
|
if (!match) return void 0;
|
|
4660
|
-
|
|
4674
|
+
words3.push(match[1]);
|
|
4661
4675
|
rest2 = rest2.slice(match[0].length);
|
|
4662
4676
|
}
|
|
4663
|
-
return [
|
|
4677
|
+
return [words3, rest2.trim()];
|
|
4664
4678
|
}
|
|
4665
4679
|
function jobOf(content, pending, ctx, env) {
|
|
4666
4680
|
const fields = content.startsWith("@") ? 1 : 5;
|
|
4667
4681
|
const parts2 = split(content, fields + (ctx.system ? 1 : 0));
|
|
4668
4682
|
if (!parts2 || parts2[1] === "") throw new Error("no command");
|
|
4669
|
-
const [
|
|
4670
|
-
const schedule =
|
|
4683
|
+
const [words3, command] = parts2;
|
|
4684
|
+
const schedule = words3.slice(0, fields).join(" ");
|
|
4671
4685
|
const when = parseWhen(schedule);
|
|
4672
4686
|
const zone = env.CRON_TZ;
|
|
4673
4687
|
if (zone && !when.reboot && canonicalZone(zone) === void 0)
|
|
4674
4688
|
throw new Error(`CRON_TZ: unknown time zone "${zone}"`);
|
|
4675
|
-
const user = ctx.system ?
|
|
4689
|
+
const user = ctx.system ? words3[fields] : void 0;
|
|
4676
4690
|
if (user !== void 0 && !USER_NAME.test(user)) throw new Error(`bad user name ${user}`);
|
|
4677
4691
|
if (pending !== void 0 && !JOB_NAME.test(pending))
|
|
4678
4692
|
throw new Error(`bad job name "${pending}"`);
|
|
@@ -8374,9 +8388,11 @@ var SpawnError = class extends Error {
|
|
|
8374
8388
|
};
|
|
8375
8389
|
var ChangedError = class extends SpawnError {
|
|
8376
8390
|
notice;
|
|
8377
|
-
|
|
8391
|
+
file;
|
|
8392
|
+
constructor(notice, file) {
|
|
8378
8393
|
super("EPERM");
|
|
8379
8394
|
this.notice = notice;
|
|
8395
|
+
this.file = file;
|
|
8380
8396
|
}
|
|
8381
8397
|
};
|
|
8382
8398
|
function interrupted(signal) {
|
|
@@ -15453,21 +15469,21 @@ function unescaped(double) {
|
|
|
15453
15469
|
}
|
|
15454
15470
|
function splitWords(text) {
|
|
15455
15471
|
const piece = /'([^']*)'|"((?:[^"\\]|\\[\s\S])*)"|\\([\s\S])|([^\s'"\\]+)|(\s+)/y;
|
|
15456
|
-
const
|
|
15472
|
+
const words3 = [];
|
|
15457
15473
|
let word;
|
|
15458
15474
|
while (piece.lastIndex < text.length) {
|
|
15459
15475
|
const m = piece.exec(text);
|
|
15460
15476
|
if (!m) return void 0;
|
|
15461
15477
|
const [, single, double, escaped, plain3, space] = m;
|
|
15462
15478
|
if (space !== void 0) {
|
|
15463
|
-
if (word !== void 0)
|
|
15479
|
+
if (word !== void 0) words3.push(word);
|
|
15464
15480
|
word = void 0;
|
|
15465
15481
|
continue;
|
|
15466
15482
|
}
|
|
15467
15483
|
word = (word ?? "") + (single ?? (double !== void 0 ? unescaped(double) : escaped ?? plain3));
|
|
15468
15484
|
}
|
|
15469
|
-
if (word !== void 0)
|
|
15470
|
-
return
|
|
15485
|
+
if (word !== void 0) words3.push(word);
|
|
15486
|
+
return words3;
|
|
15471
15487
|
}
|
|
15472
15488
|
function quoteWord(word) {
|
|
15473
15489
|
const text = hasControl(word) ? withoutControl(word) : word;
|
|
@@ -15488,14 +15504,14 @@ function addPlain(word, plain3) {
|
|
|
15488
15504
|
}
|
|
15489
15505
|
function splitPatterns(text) {
|
|
15490
15506
|
const piece = /'([^']*)'|"((?:[^"\\]|\\[\s\S])*)"|\\([\s\S])|([^\s'"\\]+)|(\s+)/y;
|
|
15491
|
-
const
|
|
15507
|
+
const words3 = [];
|
|
15492
15508
|
let word;
|
|
15493
15509
|
while (piece.lastIndex < text.length) {
|
|
15494
15510
|
const m = piece.exec(text);
|
|
15495
15511
|
if (!m) return void 0;
|
|
15496
15512
|
const [, single, double, escaped, plain3, space] = m;
|
|
15497
15513
|
if (space !== void 0) {
|
|
15498
|
-
if (word !== void 0)
|
|
15514
|
+
if (word !== void 0) words3.push(word);
|
|
15499
15515
|
word = void 0;
|
|
15500
15516
|
continue;
|
|
15501
15517
|
}
|
|
@@ -15503,8 +15519,8 @@ function splitPatterns(text) {
|
|
|
15503
15519
|
if (plain3 !== void 0) addPlain(word, plain3);
|
|
15504
15520
|
else addPart(word, single ?? (double !== void 0 ? unescaped(double) : escaped));
|
|
15505
15521
|
}
|
|
15506
|
-
if (word !== void 0)
|
|
15507
|
-
return
|
|
15522
|
+
if (word !== void 0) words3.push(word);
|
|
15523
|
+
return words3;
|
|
15508
15524
|
}
|
|
15509
15525
|
var literal = (pattern) => pattern.map((p) => p ?? "*").join("");
|
|
15510
15526
|
var isAny = (pattern) => pattern?.length === 1 && pattern[0] === null;
|
|
@@ -15577,14 +15593,14 @@ function whoError(who) {
|
|
|
15577
15593
|
return `expected a user name, %group or ALL first, not ${shown(who)}`;
|
|
15578
15594
|
}
|
|
15579
15595
|
function cwdOf(word) {
|
|
15580
|
-
const
|
|
15581
|
-
const path =
|
|
15596
|
+
const words3 = splitWords(word);
|
|
15597
|
+
const path = words3?.length === 1 ? words3[0] : "";
|
|
15582
15598
|
return path.startsWith("/") ? normalizePath(path) : "";
|
|
15583
15599
|
}
|
|
15584
15600
|
function commandOf2(text, after) {
|
|
15585
|
-
const
|
|
15586
|
-
if (
|
|
15587
|
-
const [first, ...args] =
|
|
15601
|
+
const words3 = splitPatterns(text);
|
|
15602
|
+
if (words3 === void 0) return "a quote in the command is not closed, or it ends in a \\";
|
|
15603
|
+
const [first, ...args] = words3;
|
|
15588
15604
|
const path = first ? literal(first) : "";
|
|
15589
15605
|
if (path === "") return `expected a command after ${after}`;
|
|
15590
15606
|
if (!path.startsWith("/")) return `expected an absolute command path, not ${shown(path)}`;
|
|
@@ -16274,6 +16290,9 @@ function recordable(cwd, argv) {
|
|
|
16274
16290
|
function changedText(file) {
|
|
16275
16291
|
return `sudo: ${file} changed since it was approved`;
|
|
16276
16292
|
}
|
|
16293
|
+
function requestedText(file) {
|
|
16294
|
+
return `sudo: ${file} changed since it was requested`;
|
|
16295
|
+
}
|
|
16277
16296
|
function changedFile(approved, now) {
|
|
16278
16297
|
const files = /* @__PURE__ */ new Set([...Object.keys(approved), ...Object.keys(now)]);
|
|
16279
16298
|
return [...files].find((file) => approved[file] !== now[file]);
|
|
@@ -16281,6 +16300,67 @@ function changedFile(approved, now) {
|
|
|
16281
16300
|
function pinned(rule, bound3) {
|
|
16282
16301
|
return rule.sha256 === void 0 || changedFile(rule.sha256, bound3) === void 0;
|
|
16283
16302
|
}
|
|
16303
|
+
var REPLAY_ID = /^[!-~]{1,256}$/;
|
|
16304
|
+
var REPLAY_TAGS_MAX = 64;
|
|
16305
|
+
var REPLAY_ARGV_MAX = 4096;
|
|
16306
|
+
var REPLAY_BYTES_MAX = 1024 * 1024;
|
|
16307
|
+
var NOT_A_REQUEST = "sudo: that isn't a sudo request this kernel can run";
|
|
16308
|
+
function strings(value2, max) {
|
|
16309
|
+
return Array.isArray(value2) && value2.length <= max && value2.every((s) => typeof s === "string");
|
|
16310
|
+
}
|
|
16311
|
+
function words(value2) {
|
|
16312
|
+
if (!strings(value2, REPLAY_ARGV_MAX) || value2.length === 0) return false;
|
|
16313
|
+
const bytes = value2.reduce((n, s) => n + s.length + 1, 0);
|
|
16314
|
+
return bytes <= REPLAY_BYTES_MAX && !value2.some((s) => s.includes("\0"));
|
|
16315
|
+
}
|
|
16316
|
+
function filesOf(value2) {
|
|
16317
|
+
if (value2 === void 0) return {};
|
|
16318
|
+
if (!Array.isArray(value2) || value2.length > OPERANDS_MAX) return void 0;
|
|
16319
|
+
const files = {};
|
|
16320
|
+
for (const file of value2) {
|
|
16321
|
+
const { path, sha256: hex4 } = file ?? {};
|
|
16322
|
+
if (typeof path !== "string" || typeof hex4 !== "string") return void 0;
|
|
16323
|
+
files[path] = hex4;
|
|
16324
|
+
}
|
|
16325
|
+
return files;
|
|
16326
|
+
}
|
|
16327
|
+
function flagsOf(value2) {
|
|
16328
|
+
if (typeof value2 !== "object" || value2 === null || Array.isArray(value2)) return void 0;
|
|
16329
|
+
const entries = Object.entries(value2);
|
|
16330
|
+
if (entries.length > ROOT_ONLY_MAX || entries.some(([, v]) => typeof v !== "boolean")) {
|
|
16331
|
+
return void 0;
|
|
16332
|
+
}
|
|
16333
|
+
return Object.fromEntries(entries);
|
|
16334
|
+
}
|
|
16335
|
+
function replayOf(value2) {
|
|
16336
|
+
if (typeof value2 !== "object" || value2 === null) return failed2("EINVAL", NOT_A_REQUEST);
|
|
16337
|
+
const r = value2;
|
|
16338
|
+
if (r.validate === true) return failed2("EINVAL", "sudo: a sudo -v request runs no command");
|
|
16339
|
+
if (r.stdin === "pipe" || r.stdin === "file") {
|
|
16340
|
+
return failed2("EINVAL", `sudo: the request read a ${r.stdin}, and that input is gone`);
|
|
16341
|
+
}
|
|
16342
|
+
const { id: id2, user, uid, target, argv, path, cwd, stdin, tag, tags } = r;
|
|
16343
|
+
const rootOnly2 = flagsOf(r.rootOnly);
|
|
16344
|
+
const bound3 = filesOf(r.userWritable);
|
|
16345
|
+
const named = (s) => typeof s === "string" && s !== "";
|
|
16346
|
+
const absolute2 = (s) => typeof s === "string" && s.startsWith("/") && s.length <= PATH_MAX && !s.includes("\0");
|
|
16347
|
+
const valid2 = typeof id2 === "string" && REPLAY_ID.test(id2) && named(user) && named(target) && Number.isInteger(uid) && uid >= 0 && words(argv) && absolute2(path) && absolute2(cwd) && (stdin === "tty" || stdin === "none") && (tag === void 0 || typeof tag === "string") && (tags === void 0 || strings(tags, REPLAY_TAGS_MAX)) && rootOnly2 !== void 0 && bound3 !== void 0;
|
|
16348
|
+
if (!valid2) return failed2("EINVAL", NOT_A_REQUEST);
|
|
16349
|
+
const all = tags ?? (tag === void 0 ? [] : [tag]);
|
|
16350
|
+
return {
|
|
16351
|
+
id: id2,
|
|
16352
|
+
user,
|
|
16353
|
+
uid,
|
|
16354
|
+
target,
|
|
16355
|
+
argv,
|
|
16356
|
+
path,
|
|
16357
|
+
cwd,
|
|
16358
|
+
stdin,
|
|
16359
|
+
rootOnly: rootOnly2,
|
|
16360
|
+
bound: bound3,
|
|
16361
|
+
tags: [...new Set(all)]
|
|
16362
|
+
};
|
|
16363
|
+
}
|
|
16284
16364
|
var VISUDO_FILES_MAX = 64;
|
|
16285
16365
|
var VISUDO_TEXT_MAX = 1024 * 1024;
|
|
16286
16366
|
function visudoCall(req) {
|
|
@@ -16682,6 +16762,61 @@ var Sudo = class {
|
|
|
16682
16762
|
if (parsed2.validate) return this.validate(session, root, mine, call.cwd);
|
|
16683
16763
|
return this.command(session, root, mine, call);
|
|
16684
16764
|
}
|
|
16765
|
+
async replay(value2) {
|
|
16766
|
+
const r = replayOf(value2);
|
|
16767
|
+
if ("error" in r) return r;
|
|
16768
|
+
if (this.o.mode !== "enforce") {
|
|
16769
|
+
return failed2("EINVAL", `sudo: users are '${this.o.mode}', so no request needed approval`);
|
|
16770
|
+
}
|
|
16771
|
+
const self = await this.o.users.lookup(r.user);
|
|
16772
|
+
if (!self) return failed2("ENOENT", `sudo: unknown user ${r.user}`);
|
|
16773
|
+
if (self.uid !== r.uid) return failed2("EPERM", `sudo: ${self.name} is no longer uid ${r.uid}`);
|
|
16774
|
+
const target = await this.lookup(r.target);
|
|
16775
|
+
if (!target) return failed2("ENOENT", `sudo: unknown user ${r.target}`);
|
|
16776
|
+
const cred = credOf(self);
|
|
16777
|
+
const [word = "", ...args] = r.argv;
|
|
16778
|
+
const argv = [r.path, ...args];
|
|
16779
|
+
if (!await this.mayAsk(self, target, r, argv)) {
|
|
16780
|
+
const quoted = argv.map(quoteWord).join(" ");
|
|
16781
|
+
return failed2(
|
|
16782
|
+
"EACCES",
|
|
16783
|
+
`sudo: ${self.name} may no longer ask to run ${quoted} as ${target.name}`
|
|
16784
|
+
);
|
|
16785
|
+
}
|
|
16786
|
+
if (await this.canonical(r.cwd) !== r.cwd) {
|
|
16787
|
+
return failed2("EACCES", `sudo: ${r.cwd} changed since it was requested`);
|
|
16788
|
+
}
|
|
16789
|
+
if (!await this.reachable(cred, r.cwd)) {
|
|
16790
|
+
return failed2(
|
|
16791
|
+
"EACCES",
|
|
16792
|
+
`sudo: cannot run in ${r.cwd}: it isn't a directory ${self.name} can enter`
|
|
16793
|
+
);
|
|
16794
|
+
}
|
|
16795
|
+
const path = await this.locate(word, r.cwd);
|
|
16796
|
+
if (!path) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
16797
|
+
if (path !== r.path) return failed2("EPERM", `sudo: ${word} now runs ${path}, not ${r.path}`);
|
|
16798
|
+
const bound3 = await this.bound(path, r.cwd);
|
|
16799
|
+
if (!bound3) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
16800
|
+
const changed = changedFile(r.bound, bound3);
|
|
16801
|
+
if (changed !== void 0) return failed2("EPERM", requestedText(changed));
|
|
16802
|
+
const now = await this.rootOnly(r.cwd, args);
|
|
16803
|
+
const flipped = Object.keys(r.rootOnly).find((at) => r.rootOnly[at] && now[at] !== true);
|
|
16804
|
+
if (flipped !== void 0) return failed2("EPERM", `sudo: ${flipped} is no longer root-only`);
|
|
16805
|
+
const { grant } = this.grant(self, target, cred, r.argv, path, r.cwd, void 0, bound3);
|
|
16806
|
+
(this.o.warn ?? console.warn)(
|
|
16807
|
+
`sudo: ${self.name} : TTY=unknown ; PWD=${quoteWord(r.cwd)} ; USER=${target.name} ; REPLAY=${r.id} ; COMMAND=${argv.map(quoteWord).join(" ")}`
|
|
16808
|
+
);
|
|
16809
|
+
return { grant, caller: self, target, tags: r.tags };
|
|
16810
|
+
}
|
|
16811
|
+
async mayAsk(self, target, r, argv) {
|
|
16812
|
+
if (self.uid === 0) return true;
|
|
16813
|
+
const cred = credOf(self);
|
|
16814
|
+
const { rules } = await this.policyRules({ cred, pid: 0, stdin: r.stdin });
|
|
16815
|
+
const applies = await this.applies(self, cred);
|
|
16816
|
+
return rules.some(
|
|
16817
|
+
(rule) => applies(rule.who) && (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === r.cwd) && stdinMatches(rule, r.stdin) && commandMatches(rule.cmnd, argv) && pinned(rule, r.bound)
|
|
16818
|
+
);
|
|
16819
|
+
}
|
|
16685
16820
|
async command(s, root, mine, call) {
|
|
16686
16821
|
const { caller, self, target, parsed: parsed2 } = s;
|
|
16687
16822
|
const { cred } = caller;
|
|
@@ -16861,8 +16996,8 @@ ${lines2}
|
|
|
16861
16996
|
const st = await fs.lstat(path).catch(() => void 0);
|
|
16862
16997
|
if (st && !await this.trusted(path)) return false;
|
|
16863
16998
|
const old = st ? await fs.readFile(path) : "";
|
|
16864
|
-
const
|
|
16865
|
-
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none ${sha256Text(bound3)}Cmnd ${
|
|
16999
|
+
const words3 = recordedCommand(argv);
|
|
17000
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none ${sha256Text(bound3)}Cmnd ${words3}
|
|
16866
17001
|
`;
|
|
16867
17002
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
16868
17003
|
${line}`;
|
|
@@ -18167,8 +18302,8 @@ function ipv6(host) {
|
|
|
18167
18302
|
const head = groups(halves[0]);
|
|
18168
18303
|
const back = halves.length === 2 ? groups(halves[1]) : [];
|
|
18169
18304
|
if (![...head, ...back].every((g) => /^[0-9A-Fa-f]{1,4}$/.test(g))) return void 0;
|
|
18170
|
-
const
|
|
18171
|
-
const missing6 = 8 -
|
|
18305
|
+
const words3 = [...head, ...back].map((g) => Number.parseInt(g, 16));
|
|
18306
|
+
const missing6 = 8 - words3.length - tail2.length;
|
|
18172
18307
|
if (halves.length === 2 ? missing6 < 1 : missing6 !== 0) return void 0;
|
|
18173
18308
|
const all = [
|
|
18174
18309
|
...head.map((g) => Number.parseInt(g, 16)),
|
|
@@ -21652,7 +21787,7 @@ function selectFlag(req) {
|
|
|
21652
21787
|
throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS: alpn with select");
|
|
21653
21788
|
return TLS_SERVER_SELECT;
|
|
21654
21789
|
}
|
|
21655
|
-
function
|
|
21790
|
+
function flagsOf2(req) {
|
|
21656
21791
|
return certFlags(req) | selectFlag(req) | (req.keylog ? TLS_KEYLOG : 0);
|
|
21657
21792
|
}
|
|
21658
21793
|
async function engineOf(proc, { select, keylog }) {
|
|
@@ -21703,7 +21838,7 @@ async function serverOf(proc, req) {
|
|
|
21703
21838
|
let mine;
|
|
21704
21839
|
try {
|
|
21705
21840
|
mine = req.ca && req.ca.length > 0 ? storeOf(engine, req.ca) : void 0;
|
|
21706
|
-
const flags2 =
|
|
21841
|
+
const flags2 = flagsOf2(req);
|
|
21707
21842
|
const store = mine ?? (flags2 & CERT_FLAGS ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
|
|
21708
21843
|
return {
|
|
21709
21844
|
engine,
|
|
@@ -23592,7 +23727,7 @@ var WRITE_ACCESS = 3;
|
|
|
23592
23727
|
var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
|
|
23593
23728
|
var STUCK_ESCAPES = /* @__PURE__ */ new Set([SIG.INT, SIG.TERM, SIG.QUIT, SIG.HUP]);
|
|
23594
23729
|
var DEFAULT_UMASK2 = 18;
|
|
23595
|
-
function
|
|
23730
|
+
function words2(value2) {
|
|
23596
23731
|
if (!Array.isArray(value2) || !value2.every((w) => typeof w === "string")) {
|
|
23597
23732
|
throw new KernelError("EINVAL");
|
|
23598
23733
|
}
|
|
@@ -25045,7 +25180,7 @@ var WasmProcess = class {
|
|
|
25045
25180
|
if (!sudo) throw new KernelError("ENOSYS");
|
|
25046
25181
|
const call = {
|
|
25047
25182
|
op: "proc-sudo",
|
|
25048
|
-
args:
|
|
25183
|
+
args: words2(req.args),
|
|
25049
25184
|
cwd: typeof req.cwd === "string" && req.cwd.startsWith("/") ? req.cwd : "/",
|
|
25050
25185
|
...typeof req.term === "string" ? { term: req.term } : {}
|
|
25051
25186
|
};
|
|
@@ -28334,8 +28469,8 @@ function serveFilesystem(port, handlers, capabilities = {}, options = {}) {
|
|
|
28334
28469
|
function noticeOf(data) {
|
|
28335
28470
|
if (Array.isArray(data)) return { paths: data.filter((p) => typeof p === "string"), trees: [] };
|
|
28336
28471
|
const notice = data ?? {};
|
|
28337
|
-
const
|
|
28338
|
-
return { paths:
|
|
28472
|
+
const strings2 = (list) => Array.isArray(list) ? list.filter((p) => typeof p === "string") : [];
|
|
28473
|
+
return { paths: strings2(notice.paths), trees: strings2(notice.trees), outside: true };
|
|
28339
28474
|
}
|
|
28340
28475
|
|
|
28341
28476
|
// src/fs/opfs.ts
|
|
@@ -32648,7 +32783,40 @@ function describe(req, tty) {
|
|
|
32648
32783
|
}
|
|
32649
32784
|
function refuseChanged(approved, now) {
|
|
32650
32785
|
const changed = changedFile(approved, now);
|
|
32651
|
-
if (changed !== void 0) throw new ChangedError(changedText(changed));
|
|
32786
|
+
if (changed !== void 0) throw new ChangedError(changedText(changed), changed);
|
|
32787
|
+
}
|
|
32788
|
+
var O_WRONLY2 = 1;
|
|
32789
|
+
var OUTPUT_MODE = 384;
|
|
32790
|
+
var ERRNO_TEXT = {
|
|
32791
|
+
EACCES: "Permission denied",
|
|
32792
|
+
EISDIR: "Is a directory",
|
|
32793
|
+
ENOENT: "No such file or directory",
|
|
32794
|
+
ENOTDIR: "Not a directory",
|
|
32795
|
+
EROFS: "Read-only file system"
|
|
32796
|
+
};
|
|
32797
|
+
function sudoFailure(errno3, message3) {
|
|
32798
|
+
return Object.assign(new Error(message3), { code: errno3 });
|
|
32799
|
+
}
|
|
32800
|
+
function sudoCause(err) {
|
|
32801
|
+
const code = codeOf8(err);
|
|
32802
|
+
if (typeof code !== "string") throw err;
|
|
32803
|
+
return code;
|
|
32804
|
+
}
|
|
32805
|
+
function requested(err) {
|
|
32806
|
+
if (err instanceof ChangedError) throw sudoFailure(err.code, requestedText(err.file));
|
|
32807
|
+
throw err;
|
|
32808
|
+
}
|
|
32809
|
+
var MAX_SPAWN_TAGS = 8;
|
|
32810
|
+
function tagList(value2) {
|
|
32811
|
+
if (!Array.isArray(value2)) {
|
|
32812
|
+
tagOption(value2);
|
|
32813
|
+
return value2 === void 0 ? [] : [value2];
|
|
32814
|
+
}
|
|
32815
|
+
if (value2.length > MAX_SPAWN_TAGS) {
|
|
32816
|
+
throw new TypeError(`a spawn adds at most ${MAX_SPAWN_TAGS} tags`);
|
|
32817
|
+
}
|
|
32818
|
+
for (const each of value2) tagOption(each ?? 0);
|
|
32819
|
+
return value2;
|
|
32652
32820
|
}
|
|
32653
32821
|
function linksOf2(req) {
|
|
32654
32822
|
return req.links === void 0 ? {} : { links: req.links };
|
|
@@ -32774,27 +32942,27 @@ function appendedRoots(given) {
|
|
|
32774
32942
|
}
|
|
32775
32943
|
return [...roots];
|
|
32776
32944
|
}
|
|
32777
|
-
function plainEnv(
|
|
32778
|
-
const next3 =
|
|
32779
|
-
if (baseName2(
|
|
32945
|
+
function plainEnv(words3) {
|
|
32946
|
+
const next3 = words3[1];
|
|
32947
|
+
if (baseName2(words3[0] ?? "") !== "env" || next3 === void 0) return false;
|
|
32780
32948
|
return next3 === "-S" || !next3.startsWith("-") && !next3.includes("=");
|
|
32781
32949
|
}
|
|
32782
|
-
function shebangCommand(
|
|
32783
|
-
if (!plainEnv(
|
|
32784
|
-
const arg2 =
|
|
32785
|
-
return { interp:
|
|
32950
|
+
function shebangCommand(words3) {
|
|
32951
|
+
if (!plainEnv(words3)) {
|
|
32952
|
+
const arg2 = words3.slice(1).join(" ");
|
|
32953
|
+
return { interp: words3[0], args: arg2 ? [arg2] : [] };
|
|
32786
32954
|
}
|
|
32787
|
-
const split3 =
|
|
32788
|
-
const [interp, ...rest2] =
|
|
32955
|
+
const split3 = words3[1] === "-S";
|
|
32956
|
+
const [interp, ...rest2] = words3.slice(split3 ? 2 : 1);
|
|
32789
32957
|
const arg = rest2.join(" ");
|
|
32790
32958
|
return { interp, args: split3 ? rest2 : arg ? [arg] : [] };
|
|
32791
32959
|
}
|
|
32792
32960
|
function interpreter(head) {
|
|
32793
|
-
const
|
|
32794
|
-
if (!
|
|
32795
|
-
if (baseName2(
|
|
32796
|
-
if (
|
|
32797
|
-
return baseName2(
|
|
32961
|
+
const words3 = shebang(head);
|
|
32962
|
+
if (!words3) return "node";
|
|
32963
|
+
if (baseName2(words3[0]) === "env") words3.shift();
|
|
32964
|
+
if (words3[0] === "-S") words3.shift();
|
|
32965
|
+
return baseName2(words3[0] ?? "");
|
|
32798
32966
|
}
|
|
32799
32967
|
function expandDefaults(defaults2, env) {
|
|
32800
32968
|
const out = {};
|
|
@@ -33569,9 +33737,9 @@ var Launcher = class {
|
|
|
33569
33737
|
const head = await this.head(script);
|
|
33570
33738
|
if (!head) return void 0;
|
|
33571
33739
|
const binfmt = isWasm(head) ? void 0 : binfmtOf(await this.interpreters(scope), script);
|
|
33572
|
-
const
|
|
33573
|
-
if (!
|
|
33574
|
-
const { interp, args } = shebangCommand(
|
|
33740
|
+
const words3 = shebang(head) ?? (binfmt ? [binfmt] : void 0);
|
|
33741
|
+
if (!words3) return void 0;
|
|
33742
|
+
const { interp, args } = shebangCommand(words3);
|
|
33575
33743
|
const passed = [...args, command ? script : file, ...argv.slice(1)];
|
|
33576
33744
|
if (!interp) return void 0;
|
|
33577
33745
|
const found = await this.resolve(interp, interp, cwd, scope);
|
|
@@ -33802,7 +33970,7 @@ var Launcher = class {
|
|
|
33802
33970
|
const hex4 = pinned2[real];
|
|
33803
33971
|
if (hex4 !== void 0) return { [real]: hex4 };
|
|
33804
33972
|
if (await this.sudoer.trusted(real)) return {};
|
|
33805
|
-
throw new ChangedError(changedText(real));
|
|
33973
|
+
throw new ChangedError(changedText(real), real);
|
|
33806
33974
|
}
|
|
33807
33975
|
async pinnedBytes(pin, bytes) {
|
|
33808
33976
|
const [real = ""] = Object.keys(pin);
|
|
@@ -34081,6 +34249,10 @@ var Launcher = class {
|
|
|
34081
34249
|
}
|
|
34082
34250
|
async launch(asked, req) {
|
|
34083
34251
|
const cwd = await physicalPathAsync(this.base, req.cwd);
|
|
34252
|
+
if (req.exactCwd && cwd !== req.cwd) {
|
|
34253
|
+
await req.fds.closeAll();
|
|
34254
|
+
throw sudoFailure("EACCES", `sudo: ${req.cwd} changed since it was requested`);
|
|
34255
|
+
}
|
|
34084
34256
|
const seen = { ...req.env, HOSTNAME: this.hostname, cwd };
|
|
34085
34257
|
await this.pnpmReady();
|
|
34086
34258
|
let loaded;
|
|
@@ -35776,6 +35948,96 @@ var Launcher = class {
|
|
|
35776
35948
|
const signal = handle.termsig();
|
|
35777
35949
|
return { status, ...signal ? { signal } : {}, stdout: concat7(out), stderr: concat7(err) };
|
|
35778
35950
|
}
|
|
35951
|
+
async sudoRun(replay, options = {}) {
|
|
35952
|
+
const added = tagList(options.tag);
|
|
35953
|
+
const replayed = await this.sudoer.replay(replay);
|
|
35954
|
+
if ("error" in replayed) throw sudoFailure(replayed.errno, replayed.error);
|
|
35955
|
+
const { grant, caller, target } = replayed;
|
|
35956
|
+
let tags = withTag(void 0, options.base);
|
|
35957
|
+
for (const tag of [...replayed.tags, ...added]) tags = withTag(tags, tag);
|
|
35958
|
+
const tagged = { tags, tagBase: options.base === void 0 ? 0 : 1 };
|
|
35959
|
+
await this.swaps.settled();
|
|
35960
|
+
this.resetCatalogs();
|
|
35961
|
+
const req = { file: grant.file, argv: grant.argv, env: grant.env, cwd: grant.cwd };
|
|
35962
|
+
const ctx = { ppid: 0, cred: grant.cred, scope: "" };
|
|
35963
|
+
const planned = await this.planOne(req, ctx).catch((err2) => {
|
|
35964
|
+
const code = sudoCause(err2);
|
|
35965
|
+
const word = grant.argv[0] ?? grant.file;
|
|
35966
|
+
if (code === "ENOENT") throw sudoFailure(code, `sudo: ${word}: command not found`);
|
|
35967
|
+
throw sudoFailure(code, `sudo: ${grant.file}: ${ERRNO_TEXT[code] ?? code}`);
|
|
35968
|
+
});
|
|
35969
|
+
const pin = await this.unchanged(planned, grant.file, grant.cwd, grant).catch(requested);
|
|
35970
|
+
const fds = await this.sudoOutputs(options, caller, this.stackFor(tags, tagged.tagBase));
|
|
35971
|
+
const err = fds.get(2).file;
|
|
35972
|
+
const report = (message3) => void Promise.resolve(err.write?.(encoder10.encode(`${message3}
|
|
35973
|
+
`))).catch(() => void 0);
|
|
35974
|
+
const replan = () => this.planOne(req, ctx);
|
|
35975
|
+
if (!await this.grantedCwd(grant.caller, grant.cwd)) {
|
|
35976
|
+
await fds.closeAll();
|
|
35977
|
+
throw sudoFailure("EACCES", `sudo: ${grant.cwd} changed since it was requested`);
|
|
35978
|
+
}
|
|
35979
|
+
const handle = await this.launch(
|
|
35980
|
+
{ ...planned, replan },
|
|
35981
|
+
{
|
|
35982
|
+
...pin,
|
|
35983
|
+
env: grant.env,
|
|
35984
|
+
cwd: grant.cwd,
|
|
35985
|
+
fds,
|
|
35986
|
+
report,
|
|
35987
|
+
...this.identity(target, tagged, options.session),
|
|
35988
|
+
...caller.umask !== void 0 ? { umask: caller.umask } : {},
|
|
35989
|
+
links: grant.cred.euid,
|
|
35990
|
+
exactCwd: true
|
|
35991
|
+
}
|
|
35992
|
+
).catch(requested);
|
|
35993
|
+
const ended = handle.exited.then((status) => {
|
|
35994
|
+
const signal = handle.termsig();
|
|
35995
|
+
return { status, ...signal ? { signal } : {} };
|
|
35996
|
+
});
|
|
35997
|
+
return { pid: handle.pid, ended };
|
|
35998
|
+
}
|
|
35999
|
+
async sudoOutputs(options, caller, stack) {
|
|
36000
|
+
const fds = new FdTable();
|
|
36001
|
+
const opened2 = /* @__PURE__ */ new Map();
|
|
36002
|
+
fds.installAt(0, deviceFile("null"));
|
|
36003
|
+
try {
|
|
36004
|
+
fds.installAt(1, await this.sudoOutput(options.stdout, caller, stack, opened2));
|
|
36005
|
+
fds.installAt(2, await this.sudoOutput(options.stderr, caller, stack, opened2));
|
|
36006
|
+
} catch (err) {
|
|
36007
|
+
await fds.closeAll();
|
|
36008
|
+
throw err;
|
|
36009
|
+
}
|
|
36010
|
+
return fds;
|
|
36011
|
+
}
|
|
36012
|
+
async sudoOutput(path, caller, stack, opened2) {
|
|
36013
|
+
if (path === void 0) return deviceFile("null");
|
|
36014
|
+
if (typeof path !== "string" || !path.startsWith("/")) {
|
|
36015
|
+
throw sudoFailure("EINVAL", `sudo: ${String(path)} is not an absolute path`);
|
|
36016
|
+
}
|
|
36017
|
+
const cred = credOf(caller);
|
|
36018
|
+
const walked = await walk(this.fs, cred, normalizePath(path), true, caller.uid);
|
|
36019
|
+
const real = walked.path;
|
|
36020
|
+
const same2 = opened2.get(real);
|
|
36021
|
+
if (same2) return same2.retain();
|
|
36022
|
+
try {
|
|
36023
|
+
if (walked.denied !== void 0) throw fsError("EACCES", path);
|
|
36024
|
+
await writable({ ...this.execGuard(cred, 0), links: caller.uid }, "open", real);
|
|
36025
|
+
const owner = { uid: caller.uid, gid: caller.gid, mode: OUTPUT_MODE };
|
|
36026
|
+
await stack.noLinks.writeFile(real, new Uint8Array(0), owner);
|
|
36027
|
+
} catch (err) {
|
|
36028
|
+
const code = sudoCause(err);
|
|
36029
|
+
throw sudoFailure(code, `sudo: ${path}: ${ERRNO_TEXT[code] ?? code}`);
|
|
36030
|
+
}
|
|
36031
|
+
const file = vfsFile(stack.fs, { path: real, flags: O_WRONLY2, position: 0 }, stack.nodes);
|
|
36032
|
+
const again = await walk(this.fs, cred, real, true, caller.uid);
|
|
36033
|
+
const st = await stack.noLinks.lstat(real).catch(() => void 0);
|
|
36034
|
+
if (again.path !== real || again.denied !== void 0 || !st?.isFile) {
|
|
36035
|
+
await file.release();
|
|
36036
|
+
throw sudoFailure("EACCES", `sudo: ${path} changed while it was opened`);
|
|
36037
|
+
}
|
|
36038
|
+
opened2.set(real, file);
|
|
36039
|
+
return file;
|
|
36040
|
+
}
|
|
35779
36041
|
};
|
|
35780
36042
|
function cronLocks() {
|
|
35781
36043
|
return globalThis.navigator?.locks;
|
|
@@ -36260,7 +36522,7 @@ function serveTransport(peer, transport, {
|
|
|
36260
36522
|
}
|
|
36261
36523
|
|
|
36262
36524
|
// src/client/protocol.ts
|
|
36263
|
-
var PROTOCOL = [1,
|
|
36525
|
+
var PROTOCOL = [1, 17];
|
|
36264
36526
|
var FS_METHODS = [
|
|
36265
36527
|
"readFile",
|
|
36266
36528
|
"writeFile",
|
|
@@ -36416,9 +36678,9 @@ async function accountOf(l, user) {
|
|
|
36416
36678
|
if (!found) throw fsError("ENOENT", `no user ${String(user)}`);
|
|
36417
36679
|
return found;
|
|
36418
36680
|
}
|
|
36419
|
-
async function runAs(l, self,
|
|
36420
|
-
if (
|
|
36421
|
-
const target = await accountOf(l,
|
|
36681
|
+
async function runAs(l, self, requested2) {
|
|
36682
|
+
if (requested2 === void 0) return self;
|
|
36683
|
+
const target = await accountOf(l, requested2);
|
|
36422
36684
|
if (self.uid !== 0 && target.uid !== self.uid) {
|
|
36423
36685
|
throw fsError("EPERM", `${self.name} may not run as ${target.name}`);
|
|
36424
36686
|
}
|
|
@@ -36427,21 +36689,9 @@ async function runAs(l, self, requested) {
|
|
|
36427
36689
|
function clientCred(self) {
|
|
36428
36690
|
return self ? credOf(self) : copyCred(ROOT);
|
|
36429
36691
|
}
|
|
36430
|
-
var MAX_SPAWN_TAGS = 8;
|
|
36431
|
-
function spawnTags(value2) {
|
|
36432
|
-
if (!Array.isArray(value2)) {
|
|
36433
|
-
tagOption(value2);
|
|
36434
|
-
return value2 === void 0 ? [] : [value2];
|
|
36435
|
-
}
|
|
36436
|
-
if (value2.length > MAX_SPAWN_TAGS) {
|
|
36437
|
-
throw new TypeError(`a spawn adds at most ${MAX_SPAWN_TAGS} tags`);
|
|
36438
|
-
}
|
|
36439
|
-
for (const each of value2) tagOption(each ?? 0);
|
|
36440
|
-
return value2;
|
|
36441
|
-
}
|
|
36442
36692
|
async function runTagged(l, self, options, tag, session = -1) {
|
|
36443
36693
|
let tags = withTag(void 0, tag);
|
|
36444
|
-
for (const added of
|
|
36694
|
+
for (const added of tagList(options.tag)) tags = withTag(tags, added);
|
|
36445
36695
|
return {
|
|
36446
36696
|
user: await runAs(l, self, options.user),
|
|
36447
36697
|
tag,
|
|
@@ -36626,6 +36876,20 @@ function requestBinding(send2, port) {
|
|
|
36626
36876
|
close: () => unbind?.()
|
|
36627
36877
|
};
|
|
36628
36878
|
}
|
|
36879
|
+
async function sudoRunAs(l, self, host, req, reply) {
|
|
36880
|
+
if (self.uid !== 0) throw sudoFailure("EPERM", "sudo: only a root client may run a sudo request");
|
|
36881
|
+
const { stdout, stderr, tag } = req.options;
|
|
36882
|
+
const running = await l.sudoRun(req.replay, {
|
|
36883
|
+
stdout,
|
|
36884
|
+
stderr,
|
|
36885
|
+
tag,
|
|
36886
|
+
base: host.tag,
|
|
36887
|
+
session: host.session
|
|
36888
|
+
});
|
|
36889
|
+
reply(req.id, { started: running.pid });
|
|
36890
|
+
const { status, signal } = await running.ended;
|
|
36891
|
+
return { result: status, ...signalField(signal) };
|
|
36892
|
+
}
|
|
36629
36893
|
function answered(pending, req, reply, detach) {
|
|
36630
36894
|
pending.then(
|
|
36631
36895
|
({ result, signal, transfer }) => {
|
|
@@ -36775,6 +37039,8 @@ function serveClient(port, host) {
|
|
|
36775
37039
|
case "trace":
|
|
36776
37040
|
case "untrace":
|
|
36777
37041
|
return traces.answer(l, self, req);
|
|
37042
|
+
case "sudo-run":
|
|
37043
|
+
return sudoRunAs(l, self, host, req, reply);
|
|
36778
37044
|
case "detach":
|
|
36779
37045
|
return { result: true };
|
|
36780
37046
|
default:
|
|
@@ -36880,16 +37146,16 @@ function placeOf(address) {
|
|
|
36880
37146
|
const kind = isIP3(plain3);
|
|
36881
37147
|
if (kind === 4) return ipv4Place(plain3);
|
|
36882
37148
|
if (kind !== 6) return void 0;
|
|
36883
|
-
const
|
|
36884
|
-
const embedded2 =
|
|
36885
|
-
if (embedded2 && (
|
|
36886
|
-
if (
|
|
36887
|
-
if (((
|
|
36888
|
-
if (
|
|
37149
|
+
const words3 = hextets2(plain3);
|
|
37150
|
+
const embedded2 = words3.slice(0, 5).every((w) => w === 0) && (words3[5] === 65535 || words3[5] === 0);
|
|
37151
|
+
if (embedded2 && (words3[5] === 65535 || words3[6] !== 0)) return ipv4Place(ipv4Of(words3));
|
|
37152
|
+
if (words3.slice(0, 7).every((w) => w === 0) && (words3[7] ?? 0) <= 1) return "loopback";
|
|
37153
|
+
if (((words3[0] ?? 0) & 65472) === 65152) return "link-local";
|
|
37154
|
+
if (words3.join(":") === METADATA_V6) return "link-local";
|
|
36889
37155
|
return void 0;
|
|
36890
37156
|
}
|
|
36891
|
-
function ipv4Of(
|
|
36892
|
-
const [high = 0, low = 0] =
|
|
37157
|
+
function ipv4Of(words3) {
|
|
37158
|
+
const [high = 0, low = 0] = words3.slice(6);
|
|
36893
37159
|
return [high >> 8, high & 255, low >> 8, low & 255].join(".");
|
|
36894
37160
|
}
|
|
36895
37161
|
function hextets2(address) {
|
|
@@ -37970,6 +38236,19 @@ async function spawnOn(channel, argv, opts) {
|
|
|
37970
38236
|
signal: async (name2 = "SIGTERM") => void await channel.call({ op: "kill", pid: -pgid, signal: name2 })
|
|
37971
38237
|
};
|
|
37972
38238
|
}
|
|
38239
|
+
async function sudoRunOn(channel, replay, { stdout, stderr, tag }) {
|
|
38240
|
+
await since(channel, 16, "sudoRun", async () => {
|
|
38241
|
+
});
|
|
38242
|
+
const started = Promise.withResolvers();
|
|
38243
|
+
let endedBy;
|
|
38244
|
+
const { done: done4 } = channel.request(
|
|
38245
|
+
{ op: "sudo-run", replay, options: { stdout, stderr, tag } },
|
|
38246
|
+
{ started: started.resolve, ended: (signal) => endedBy = signal }
|
|
38247
|
+
);
|
|
38248
|
+
done4.catch(started.reject);
|
|
38249
|
+
const pid = await started.promise;
|
|
38250
|
+
return { pid, pgid: pid, ended: endedOf(done4, () => endedBy) };
|
|
38251
|
+
}
|
|
37973
38252
|
function endedOf(done4, signal) {
|
|
37974
38253
|
return quiet(
|
|
37975
38254
|
done4.then((status) => {
|
|
@@ -38171,6 +38450,7 @@ async function attachKernel(port, options = {}) {
|
|
|
38171
38450
|
return () => channel.traitsListeners.delete(listener);
|
|
38172
38451
|
},
|
|
38173
38452
|
trace: (tag, onEvents, options2 = {}) => traceOn(channel, tag, onEvents, options2),
|
|
38453
|
+
sudoRun: (replay, options2 = {}) => sudoRunOn(channel, replay, options2),
|
|
38174
38454
|
async close(o = {}) {
|
|
38175
38455
|
if (channel.failure) return;
|
|
38176
38456
|
await channel.call({ op: "detach", ...o.kill ? { kill: true } : {} }).catch(() => void 0);
|
|
@@ -38485,6 +38765,30 @@ function checkedRequests(hook) {
|
|
|
38485
38765
|
const kinds = kindsOf(hook);
|
|
38486
38766
|
return { kinds, handle: (request) => hook.handle(request) };
|
|
38487
38767
|
}
|
|
38768
|
+
function nodeAccounts(launcher, guard2) {
|
|
38769
|
+
return {
|
|
38770
|
+
users: {
|
|
38771
|
+
mode: launcher.usersMode,
|
|
38772
|
+
add: (user) => guard2(() => launcher.users.add(user)),
|
|
38773
|
+
remove: (name2, options) => guard2(() => launcher.users.remove(name2, options)),
|
|
38774
|
+
list: () => guard2(() => launcher.users.list())
|
|
38775
|
+
},
|
|
38776
|
+
groups: {
|
|
38777
|
+
list: () => guard2(() => launcher.users.groups()),
|
|
38778
|
+
add: (name2, options) => guard2(() => launcher.users.addGroup(name2, options?.gid)),
|
|
38779
|
+
addMember: (group, user) => guard2(() => launcher.users.addMember(group, user)),
|
|
38780
|
+
removeMember: (group, user) => guard2(() => launcher.users.removeMember(group, user))
|
|
38781
|
+
}
|
|
38782
|
+
};
|
|
38783
|
+
}
|
|
38784
|
+
async function nodeSudoRun(launcher, guard2, replay, options) {
|
|
38785
|
+
const running = await guard2(() => launcher.sudoRun(replay, options));
|
|
38786
|
+
const ended = guard2(async () => {
|
|
38787
|
+
const { status, signal } = await running.ended;
|
|
38788
|
+
return { status, ...signalField(signal) };
|
|
38789
|
+
});
|
|
38790
|
+
return { pid: running.pid, pgid: running.pid, ended: quiet(ended) };
|
|
38791
|
+
}
|
|
38488
38792
|
async function createNodeKernel(options = {}) {
|
|
38489
38793
|
const hooks = sealedHooks(options.sealed);
|
|
38490
38794
|
const timeZone = systemTimeZone(options.timeZone, clockZone(options.cron?.clock));
|
|
@@ -38613,18 +38917,8 @@ async function createNodeKernel(options = {}) {
|
|
|
38613
38917
|
mounts: async () => launcher.mounts.listed(),
|
|
38614
38918
|
setRoutes: (routes) => guard2(async () => launcher.setRoutes(routes)),
|
|
38615
38919
|
updateTransportTraits: () => guard2(async () => launcher.updateTransportTraits()),
|
|
38616
|
-
|
|
38617
|
-
|
|
38618
|
-
add: (user) => guard2(() => launcher.users.add(user)),
|
|
38619
|
-
remove: (name2, options2) => guard2(() => launcher.users.remove(name2, options2)),
|
|
38620
|
-
list: () => guard2(() => launcher.users.list())
|
|
38621
|
-
},
|
|
38622
|
-
groups: {
|
|
38623
|
-
list: () => guard2(() => launcher.users.groups()),
|
|
38624
|
-
add: (name2, options2) => guard2(() => launcher.users.addGroup(name2, options2?.gid)),
|
|
38625
|
-
addMember: (group, user) => guard2(() => launcher.users.addMember(group, user)),
|
|
38626
|
-
removeMember: (group, user) => guard2(() => launcher.users.removeMember(group, user))
|
|
38627
|
-
},
|
|
38920
|
+
...nodeAccounts(launcher, guard2),
|
|
38921
|
+
sudoRun: (replay, sudoOptions = {}) => nodeSudoRun(launcher, guard2, replay, sudoOptions),
|
|
38628
38922
|
async connect(connectOptions = {}) {
|
|
38629
38923
|
if (terminated) throw new Error(TERMINATED);
|
|
38630
38924
|
const { user } = connectOptions;
|