@ai-ecoverse/slicc-kernel 1.177.0 → 1.178.1
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 +23 -4
- package/dist/driver-worker.js +4 -1
- package/dist/driver-worker.js.map +3 -3
- package/dist/index.js +47 -3
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +200 -74
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +4 -1
- package/dist/node-driver-worker.js.map +3 -3
- package/dist/node-process-worker.cjs +8 -4
- package/dist/node-process-worker.cjs.map +2 -2
- package/dist/node-process-worker.js +8 -4
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +237 -70
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +8 -4
- package/dist/process-worker.js.map +2 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/kernel/net/http-syscalls.d.ts +1 -1
- package/dist/types/kernel/net/remote-transport.d.ts +3 -3
- package/dist/types/kernel/net/transport.d.ts +1 -0
- package/dist/types/kernel/sealed-oauth.d.ts +74 -0
- package/dist/types/kernel/sealed.d.ts +1 -0
- package/dist/types/node.d.ts +1 -0
- package/dist/types/realm/sync-fs-wire.d.ts +1 -1
- package/dist/types/transport.d.ts +2 -1
- package/package.json +2 -2
package/dist/kernel-worker.js
CHANGED
|
@@ -1611,10 +1611,10 @@ var RemoteWatch = class {
|
|
|
1611
1611
|
|
|
1612
1612
|
// src/fs/view.ts
|
|
1613
1613
|
function view(target, overrides) {
|
|
1614
|
-
const
|
|
1614
|
+
const keys2 = new Set(Object.keys(overrides));
|
|
1615
1615
|
return new Proxy(target, {
|
|
1616
1616
|
get(t, prop, receiver) {
|
|
1617
|
-
if (
|
|
1617
|
+
if (keys2.has(prop)) return overrides[prop];
|
|
1618
1618
|
return Reflect.get(t, prop, receiver);
|
|
1619
1619
|
},
|
|
1620
1620
|
set(t, prop, value2) {
|
|
@@ -3599,8 +3599,8 @@ var OpfsFs = class {
|
|
|
3599
3599
|
renamingDirs = /* @__PURE__ */ new Set();
|
|
3600
3600
|
intents = 0;
|
|
3601
3601
|
async intend(rename, at = `${RENAMES2}/${crypto.randomUUID()}`) {
|
|
3602
|
-
const
|
|
3603
|
-
await this.meta.update(at, () => ({ path: at, rename:
|
|
3602
|
+
const record3 = { ...rename, at: Date.now() * 1e3 + this.intents++ % 1e3 };
|
|
3603
|
+
await this.meta.update(at, () => ({ path: at, rename: record3 }));
|
|
3604
3604
|
return at;
|
|
3605
3605
|
}
|
|
3606
3606
|
async rollBack(from, to, intents) {
|
|
@@ -4145,9 +4145,9 @@ async function same(a, b) {
|
|
|
4145
4145
|
return false;
|
|
4146
4146
|
}
|
|
4147
4147
|
}
|
|
4148
|
-
async function matches(
|
|
4149
|
-
if (
|
|
4150
|
-
return "path" in at &&
|
|
4148
|
+
async function matches(record3, root, at) {
|
|
4149
|
+
if (record3.handle) return same(record3.handle, root);
|
|
4150
|
+
return "path" in at && record3.path !== void 0 && samePath(record3.path, at.path);
|
|
4151
4151
|
}
|
|
4152
4152
|
var nameOf = (id2) => `${META_DB}:${id2}`;
|
|
4153
4153
|
function done(tx) {
|
|
@@ -4190,7 +4190,7 @@ async function rootId(factory, root, locks = globalThis.navigator?.locks, top) {
|
|
|
4190
4190
|
const all = await request(
|
|
4191
4191
|
db.transaction(ROOTS_STORE, "readonly").objectStore(ROOTS_STORE).getAll()
|
|
4192
4192
|
);
|
|
4193
|
-
for (const
|
|
4193
|
+
for (const record3 of all) if (await matches(record3, root, at)) return record3.id;
|
|
4194
4194
|
const id2 = crypto.randomUUID();
|
|
4195
4195
|
if (await used(root)) await seed(factory, nameOf(id2));
|
|
4196
4196
|
const tx = db.transaction(ROOTS_STORE, "readwrite");
|
|
@@ -5673,9 +5673,9 @@ function changeCred(cur, change) {
|
|
|
5673
5673
|
}
|
|
5674
5674
|
const privileged = cur.euid === 0;
|
|
5675
5675
|
const next3 = copyCred(cur);
|
|
5676
|
-
for (const
|
|
5677
|
-
const own =
|
|
5678
|
-
for (const key of
|
|
5676
|
+
for (const keys2 of [UIDS, GIDS]) {
|
|
5677
|
+
const own = keys2.map((key) => cur[key]);
|
|
5678
|
+
for (const key of keys2) {
|
|
5679
5679
|
const value2 = id(change[key]);
|
|
5680
5680
|
if (value2 === void 0) continue;
|
|
5681
5681
|
if (!privileged && !own.includes(value2)) throw fsError("EPERM", `${key} ${value2}`);
|
|
@@ -7452,6 +7452,9 @@ var KERNEL_SIGINFO = Object.freeze({
|
|
|
7452
7452
|
// src/body-idle.ts
|
|
7453
7453
|
var BODY_IDLE_MS = 5 * 60 * 1e3;
|
|
7454
7454
|
|
|
7455
|
+
// src/kernel/net/transport.ts
|
|
7456
|
+
var FORBIDDEN_HEADER = "forbidden-header";
|
|
7457
|
+
|
|
7455
7458
|
// src/kernel/net/ws-queue.ts
|
|
7456
7459
|
var INBOUND_LIMIT = 16 * 1024 * 1024;
|
|
7457
7460
|
var MESSAGE_LIMIT = 64 * 1024 * 1024;
|
|
@@ -7586,7 +7589,7 @@ function serveTransport(peer, transport, {
|
|
|
7586
7589
|
message: e instanceof Error ? e.message : String(e),
|
|
7587
7590
|
...typeof status === "number" ? { status } : {},
|
|
7588
7591
|
...typeof code === "string" ? { code } : {},
|
|
7589
|
-
...detail === "transport" ? { detail } : {}
|
|
7592
|
+
...detail === "transport" || detail === FORBIDDEN_HEADER ? { detail } : {}
|
|
7590
7593
|
});
|
|
7591
7594
|
};
|
|
7592
7595
|
const uploads = uploadsFor(peer);
|
|
@@ -8682,12 +8685,12 @@ function next(p) {
|
|
|
8682
8685
|
var ANY = [[">=", [0, 0, 0, []]]];
|
|
8683
8686
|
var NOTHING = [["<", [0, 0, 0, ["0"]]]];
|
|
8684
8687
|
function plain(op, p) {
|
|
8685
|
-
const
|
|
8688
|
+
const exact2 = !p.parts.includes(void 0);
|
|
8686
8689
|
const low = floor(p);
|
|
8687
8690
|
const high = next(p);
|
|
8688
8691
|
if (op === ">=") return [[">=", low]];
|
|
8689
|
-
if (op === "<") return [["<",
|
|
8690
|
-
if (
|
|
8692
|
+
if (op === "<") return [["<", exact2 ? low : [low[0], low[1], low[2], ["0"]]]];
|
|
8693
|
+
if (exact2) return [[op === "" ? "=" : op, low]];
|
|
8691
8694
|
if (op === ">") return high ? [[">=", high]] : NOTHING;
|
|
8692
8695
|
if (op === "<=") return high ? [["<", high]] : ANY;
|
|
8693
8696
|
return high ? [
|
|
@@ -8774,7 +8777,7 @@ function satisfies(version, range2) {
|
|
|
8774
8777
|
}
|
|
8775
8778
|
|
|
8776
8779
|
// src/version.ts
|
|
8777
|
-
var KERNEL_VERSION = true ? "1.
|
|
8780
|
+
var KERNEL_VERSION = true ? "1.178.1" : "0.0.0-dev";
|
|
8778
8781
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8779
8782
|
function procVersion() {
|
|
8780
8783
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9364,7 +9367,7 @@ function intlZone(name2) {
|
|
|
9364
9367
|
minute: "numeric",
|
|
9365
9368
|
second: "numeric"
|
|
9366
9369
|
});
|
|
9367
|
-
const
|
|
9370
|
+
const exact2 = (at) => {
|
|
9368
9371
|
const parts2 = {};
|
|
9369
9372
|
for (const part of format.formatToParts(at)) parts2[part.type] = Number(part.value);
|
|
9370
9373
|
const wall = Date.UTC(
|
|
@@ -9384,12 +9387,12 @@ function intlZone(name2) {
|
|
|
9384
9387
|
const bucket = Math.floor(at / BUCKET_MS);
|
|
9385
9388
|
let known = buckets.get(bucket);
|
|
9386
9389
|
if (known === void 0) {
|
|
9387
|
-
const start2 =
|
|
9388
|
-
known = start2 ===
|
|
9390
|
+
const start2 = exact2(bucket * BUCKET_MS);
|
|
9391
|
+
known = start2 === exact2(bucket * BUCKET_MS + BUCKET_MS - MINUTE_MS) ? start2 : null;
|
|
9389
9392
|
if (buckets.size >= CACHE_MAX) buckets.clear();
|
|
9390
9393
|
buckets.set(bucket, known);
|
|
9391
9394
|
}
|
|
9392
|
-
return known ??
|
|
9395
|
+
return known ?? exact2(at);
|
|
9393
9396
|
}
|
|
9394
9397
|
};
|
|
9395
9398
|
}
|
|
@@ -10619,11 +10622,11 @@ var CronService = class {
|
|
|
10619
10622
|
const now = this.clock.now();
|
|
10620
10623
|
const system = this.host.timeZone;
|
|
10621
10624
|
const due2 = [];
|
|
10622
|
-
const
|
|
10625
|
+
const keys2 = /* @__PURE__ */ new Set();
|
|
10623
10626
|
let next3 = now + WAKE_MS;
|
|
10624
10627
|
for (const entry of loaded) {
|
|
10625
10628
|
const key = keyOf2(entry);
|
|
10626
|
-
|
|
10629
|
+
keys2.add(key);
|
|
10627
10630
|
const { when } = entry.job;
|
|
10628
10631
|
if (when.reboot) {
|
|
10629
10632
|
if (this.rebooted || stamp.reboot[key] === this.host.bootId) continue;
|
|
@@ -10649,7 +10652,7 @@ var CronService = class {
|
|
|
10649
10652
|
}
|
|
10650
10653
|
this.rebooted = true;
|
|
10651
10654
|
for (const map of [stamp.jobs, stamp.reboot, stamp.when])
|
|
10652
|
-
for (const key of Object.keys(map)) if (!
|
|
10655
|
+
for (const key of Object.keys(map)) if (!keys2.has(key)) delete map[key];
|
|
10653
10656
|
await this.writeStamp(stamp);
|
|
10654
10657
|
for (const each of due2) void this.spawn(each);
|
|
10655
10658
|
return next3;
|
|
@@ -11755,16 +11758,16 @@ function missing4(err) {
|
|
|
11755
11758
|
return err?.code === "ENOENT";
|
|
11756
11759
|
}
|
|
11757
11760
|
function synthetic(directory, path) {
|
|
11758
|
-
const
|
|
11761
|
+
const epoch2 = /* @__PURE__ */ new Date(0);
|
|
11759
11762
|
return {
|
|
11760
11763
|
isFile: !directory,
|
|
11761
11764
|
isDirectory: directory,
|
|
11762
11765
|
isSymbolicLink: false,
|
|
11763
11766
|
size: 0,
|
|
11764
11767
|
mode: (directory ? S_IFDIR2 : S_IFREG2) | 493,
|
|
11765
|
-
mtime:
|
|
11766
|
-
atime:
|
|
11767
|
-
ctime:
|
|
11768
|
+
mtime: epoch2,
|
|
11769
|
+
atime: epoch2,
|
|
11770
|
+
ctime: epoch2,
|
|
11768
11771
|
ino: inodeOf(path)
|
|
11769
11772
|
};
|
|
11770
11773
|
}
|
|
@@ -11983,16 +11986,16 @@ function missing5(err) {
|
|
|
11983
11986
|
return err?.code === "ENOENT";
|
|
11984
11987
|
}
|
|
11985
11988
|
function statOf(path, bytes) {
|
|
11986
|
-
const
|
|
11989
|
+
const epoch2 = /* @__PURE__ */ new Date(0);
|
|
11987
11990
|
return {
|
|
11988
11991
|
isFile: true,
|
|
11989
11992
|
isDirectory: false,
|
|
11990
11993
|
isSymbolicLink: false,
|
|
11991
11994
|
size: bytes.length,
|
|
11992
11995
|
mode: S_IFREG3 | 420,
|
|
11993
|
-
mtime:
|
|
11994
|
-
atime:
|
|
11995
|
-
ctime:
|
|
11996
|
+
mtime: epoch2,
|
|
11997
|
+
atime: epoch2,
|
|
11998
|
+
ctime: epoch2,
|
|
11996
11999
|
ino: inodeOf(path),
|
|
11997
12000
|
nlink: 1,
|
|
11998
12001
|
uid: 0,
|
|
@@ -14048,11 +14051,11 @@ var HeldPaths = class extends Map {
|
|
|
14048
14051
|
handlesAt(path) {
|
|
14049
14052
|
return [...this.handles].filter(([, key]) => key === path).map(([id2]) => id2);
|
|
14050
14053
|
}
|
|
14051
|
-
doubt(over,
|
|
14054
|
+
doubt(over, exact2 = false) {
|
|
14052
14055
|
if (this.bound.size === 0) return;
|
|
14053
14056
|
for (const [handle, key] of this.handles) {
|
|
14054
14057
|
if (!this.bound.has(handle) || this.keptHandles.has(handle)) continue;
|
|
14055
|
-
if (
|
|
14058
|
+
if (exact2 ? key === over : within7(key, over)) this.doubted.set(handle, ++this.doubts);
|
|
14056
14059
|
}
|
|
14057
14060
|
}
|
|
14058
14061
|
boundIno(handle) {
|
|
@@ -17907,8 +17910,8 @@ function refused2(engine, session, err, opening2) {
|
|
|
17907
17910
|
const code = verifyCode(flags2);
|
|
17908
17911
|
if (code && flags2 !== -1)
|
|
17909
17912
|
return new KernelError("EPROTO", `${code}: ${engine.verifyInfo(flags2).trim()}`);
|
|
17910
|
-
const
|
|
17911
|
-
if (
|
|
17913
|
+
const record3 = recordRefusal(opening2);
|
|
17914
|
+
if (record3) return record3;
|
|
17912
17915
|
const text = err instanceof TlsError ? err.message : String(err);
|
|
17913
17916
|
return new KernelError("EPROTO", `ERR_SSL_HANDSHAKE_FAILURE: ${text}${alertOf(session)}`);
|
|
17914
17917
|
}
|
|
@@ -19023,6 +19026,120 @@ var SessionScrubs = class {
|
|
|
19023
19026
|
}
|
|
19024
19027
|
};
|
|
19025
19028
|
|
|
19029
|
+
// src/kernel/sealed-oauth.ts
|
|
19030
|
+
var SEALED_OAUTH_TIMEOUT_MS = 45e3;
|
|
19031
|
+
var SEALED_OAUTH_OPS = /* @__PURE__ */ new Set([
|
|
19032
|
+
"oauthGrant",
|
|
19033
|
+
"oauthStatus",
|
|
19034
|
+
"oauthRefresh",
|
|
19035
|
+
"oauthRemove"
|
|
19036
|
+
]);
|
|
19037
|
+
var MESSAGES = {
|
|
19038
|
+
EINVAL: "Invalid OAuth request",
|
|
19039
|
+
ENOENT: "OAuth credential not found",
|
|
19040
|
+
EEXIST: "OAuth credential identity conflicts",
|
|
19041
|
+
EACCES: "OAuth operation refused",
|
|
19042
|
+
EAGAIN: "OAuth credential changed; try again",
|
|
19043
|
+
ENOTSUP: "OAuth operation is not supported",
|
|
19044
|
+
ENOTCONN: "Vault is unavailable",
|
|
19045
|
+
ETIMEDOUT: "Vault request timed out",
|
|
19046
|
+
EIO: "Invalid vault reply"
|
|
19047
|
+
};
|
|
19048
|
+
var CAUSES = {
|
|
19049
|
+
"vault-locked": "Vault is locked",
|
|
19050
|
+
"oauth-reauth-required": "OAuth sign-in is required",
|
|
19051
|
+
"oauth-refresh-failed": "OAuth refresh failed"
|
|
19052
|
+
};
|
|
19053
|
+
var COMMON = ["v", "op", "caller"];
|
|
19054
|
+
var IDENTITY = [...COMMON, "name", "provider", "account"];
|
|
19055
|
+
var GRANT = [...IDENTITY, "accessToken", "refreshToken", "tokenType", "expiresAt", "oauth"];
|
|
19056
|
+
var CONFIG = ["tokenUrl", "clientId", "authMethod", "scope", "resource"];
|
|
19057
|
+
var UNSUPPORTED = ["auth", "clientSecret", "fields"];
|
|
19058
|
+
var STATES2 = /* @__PURE__ */ new Set([
|
|
19059
|
+
"ready",
|
|
19060
|
+
"refreshing",
|
|
19061
|
+
"expired",
|
|
19062
|
+
"reauth-required",
|
|
19063
|
+
"removed",
|
|
19064
|
+
"locked"
|
|
19065
|
+
]);
|
|
19066
|
+
var NAME3 = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
19067
|
+
var PROVIDER = /^[a-z0-9][a-z0-9-]{0,127}$/;
|
|
19068
|
+
var PLACEHOLDER2 = /^fnox_proxy_[0-9a-f]{24}$/;
|
|
19069
|
+
var CONTROL = /[\u0000-\u001f\u007f-\u009f]/;
|
|
19070
|
+
function record(value2) {
|
|
19071
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
19072
|
+
}
|
|
19073
|
+
function keys(value2, allowed) {
|
|
19074
|
+
return Object.keys(value2).every((key) => allowed.includes(key));
|
|
19075
|
+
}
|
|
19076
|
+
function exact(value2, fields) {
|
|
19077
|
+
return Object.keys(value2).length === fields.length && keys(value2, fields);
|
|
19078
|
+
}
|
|
19079
|
+
function nonempty(value2) {
|
|
19080
|
+
return typeof value2 === "string" && value2.length > 0;
|
|
19081
|
+
}
|
|
19082
|
+
function epoch(value2) {
|
|
19083
|
+
return typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 0;
|
|
19084
|
+
}
|
|
19085
|
+
function sealedOAuthOperation(op) {
|
|
19086
|
+
return op === "capabilities" || SEALED_OAUTH_OPS.has(op);
|
|
19087
|
+
}
|
|
19088
|
+
function validateSealedOAuth(req) {
|
|
19089
|
+
const config = req.oauth;
|
|
19090
|
+
if (UNSUPPORTED.some((key) => Object.hasOwn(req, key)) || record(config) && UNSUPPORTED.some((key) => Object.hasOwn(config, key)))
|
|
19091
|
+
throw new KernelError("ENOTSUP");
|
|
19092
|
+
const allowed = req.op === "capabilities" ? COMMON : req.op === "oauthGrant" ? GRANT : IDENTITY;
|
|
19093
|
+
if (!keys(req, allowed)) throw new KernelError("EINVAL");
|
|
19094
|
+
if (req.op === "capabilities") return;
|
|
19095
|
+
if (typeof req.name !== "string" || !NAME3.test(req.name) || typeof req.provider !== "string" || !PROVIDER.test(req.provider) || !nonempty(req.account) || req.account.length > 256 || CONTROL.test(req.account))
|
|
19096
|
+
throw new KernelError("EINVAL");
|
|
19097
|
+
if (req.op !== "oauthGrant") return;
|
|
19098
|
+
if (!nonempty(req.accessToken) || req.refreshToken !== void 0 && !nonempty(req.refreshToken) || req.tokenType !== void 0 && typeof req.tokenType !== "string" || req.expiresAt !== void 0 && !epoch(req.expiresAt) || !record(config) || !keys(config, CONFIG) || !nonempty(config.tokenUrl) || !nonempty(config.clientId) || typeof config.authMethod !== "string" || config.scope !== void 0 && typeof config.scope !== "string" || config.resource !== void 0 && !nonempty(config.resource))
|
|
19099
|
+
throw new KernelError("EINVAL");
|
|
19100
|
+
if (config.authMethod !== "none" || typeof req.tokenType === "string" && req.tokenType.toLowerCase() !== "bearer")
|
|
19101
|
+
throw new KernelError("ENOTSUP");
|
|
19102
|
+
}
|
|
19103
|
+
function sealedOAuthError(code = "EIO", cause) {
|
|
19104
|
+
return {
|
|
19105
|
+
v: 1,
|
|
19106
|
+
error: { code, ...cause ? { cause } : {}, message: cause ? CAUSES[cause] : MESSAGES[code] }
|
|
19107
|
+
};
|
|
19108
|
+
}
|
|
19109
|
+
function sealedOAuthReply(op, value2) {
|
|
19110
|
+
try {
|
|
19111
|
+
return checkedReply(op, value2) ?? sealedOAuthError();
|
|
19112
|
+
} catch {
|
|
19113
|
+
return sealedOAuthError();
|
|
19114
|
+
}
|
|
19115
|
+
}
|
|
19116
|
+
function checkedError(value2) {
|
|
19117
|
+
const error = value2.error;
|
|
19118
|
+
if (!exact(value2, ["v", "error"]) || !record(error) || !Object.hasOwn(error, "code") || !Object.hasOwn(error, "message"))
|
|
19119
|
+
return void 0;
|
|
19120
|
+
const { code, cause, message: message3 } = error;
|
|
19121
|
+
if (!keys(error, ["code", "cause", "message"]) || typeof code !== "string" || !Object.hasOwn(MESSAGES, code) || typeof message3 !== "string" || cause !== void 0 && (typeof cause !== "string" || !Object.hasOwn(CAUSES, cause)))
|
|
19122
|
+
return void 0;
|
|
19123
|
+
return sealedOAuthError(code, cause);
|
|
19124
|
+
}
|
|
19125
|
+
function checkedReply(op, value2) {
|
|
19126
|
+
if (!record(value2) || !Object.hasOwn(value2, "v") || value2.v !== 1) return void 0;
|
|
19127
|
+
if (Object.hasOwn(value2, "error")) return checkedError(value2);
|
|
19128
|
+
if (op === "capabilities") {
|
|
19129
|
+
const caps = value2.capabilities;
|
|
19130
|
+
if (!exact(value2, ["v", "capabilities"]) || !record(caps) || !keys(caps, ["kernelOAuth"]))
|
|
19131
|
+
return void 0;
|
|
19132
|
+
if (Object.hasOwn(caps, "kernelOAuth") && caps.kernelOAuth !== 1) return void 0;
|
|
19133
|
+
return { v: 1, capabilities: Object.hasOwn(caps, "kernelOAuth") ? { kernelOAuth: 1 } : {} };
|
|
19134
|
+
}
|
|
19135
|
+
if (op === "oauthRemove")
|
|
19136
|
+
return exact(value2, ["v", "removed"]) && value2.removed === true ? { v: 1, removed: true } : void 0;
|
|
19137
|
+
const { placeholder, state, expiresAt, refreshable } = value2;
|
|
19138
|
+
if (!exact(value2, ["v", "placeholder", "state", "expiresAt", "refreshable"]) || typeof placeholder !== "string" || !PLACEHOLDER2.test(placeholder) || typeof state !== "string" || !STATES2.has(state) || expiresAt !== null && !epoch(expiresAt) || typeof refreshable !== "boolean")
|
|
19139
|
+
return void 0;
|
|
19140
|
+
return { v: 1, placeholder, state, expiresAt, refreshable };
|
|
19141
|
+
}
|
|
19142
|
+
|
|
19026
19143
|
// src/kernel/sealed-session.ts
|
|
19027
19144
|
var SESSION_WINDOW_MS = 6e4;
|
|
19028
19145
|
var SESSION_PLACEHOLDERS = 16;
|
|
@@ -19133,8 +19250,8 @@ function sessionValues(reply, asked) {
|
|
|
19133
19250
|
const { error, values } = reply;
|
|
19134
19251
|
if (error !== void 0 || typeof values !== "object" || values === null) return void 0;
|
|
19135
19252
|
const out = {};
|
|
19136
|
-
const
|
|
19137
|
-
const wanted = asked ?? (
|
|
19253
|
+
const keys2 = Object.keys(values);
|
|
19254
|
+
const wanted = asked ?? (keys2.length === 1 && SESSION_PLACEHOLDER.test(keys2[0]) ? keys2 : []);
|
|
19138
19255
|
for (const ph of wanted) {
|
|
19139
19256
|
const value2 = values[ph];
|
|
19140
19257
|
if (typeof value2 === "string" && value2.length > 0 && !UNSAFE.test(value2)) out[ph] = value2;
|
|
@@ -19158,7 +19275,9 @@ var SEALED_OPS = /* @__PURE__ */ new Set([
|
|
|
19158
19275
|
"request",
|
|
19159
19276
|
"status",
|
|
19160
19277
|
"cancel",
|
|
19161
|
-
"materialize"
|
|
19278
|
+
"materialize",
|
|
19279
|
+
"capabilities",
|
|
19280
|
+
...SEALED_OAUTH_OPS
|
|
19162
19281
|
]);
|
|
19163
19282
|
function tagFields(tags) {
|
|
19164
19283
|
const [tag] = tags ?? [];
|
|
@@ -19193,6 +19312,7 @@ function parseSealed(bytes) {
|
|
|
19193
19312
|
throw new KernelError("EINVAL");
|
|
19194
19313
|
if (req.op === "materialize" && !materializable(req)) throw new KernelError("EINVAL");
|
|
19195
19314
|
if (req.op === "ask" && !askable(req)) throw new KernelError("EINVAL");
|
|
19315
|
+
if (sealedOAuthOperation(req.op)) validateSealedOAuth(req);
|
|
19196
19316
|
return req;
|
|
19197
19317
|
} finally {
|
|
19198
19318
|
bytes.fill(0);
|
|
@@ -19271,7 +19391,7 @@ var SealedChannel = class {
|
|
|
19271
19391
|
const ask = fields.op === "ask";
|
|
19272
19392
|
const timer = setTimeout(
|
|
19273
19393
|
() => control.abort(ask ? "expired" : "timeout"),
|
|
19274
|
-
ask ? this.broker.askTimeoutMs : this.broker.timeoutMs
|
|
19394
|
+
ask ? this.broker.askTimeoutMs : SEALED_OAUTH_OPS.has(fields.op) ? this.broker.oauthTimeoutMs : this.broker.timeoutMs
|
|
19275
19395
|
);
|
|
19276
19396
|
const req = { ...fields, v: 1, op: fields.op, caller };
|
|
19277
19397
|
const asked = ask ? this.asking(fields, caller, requester, control.signal) : void 0;
|
|
@@ -19294,24 +19414,26 @@ var SealedChannel = class {
|
|
|
19294
19414
|
if (!facts) return errorReply("EIO", "the kernel has no record of this process");
|
|
19295
19415
|
return this.answer(askRequest(fields, caller, facts), signal);
|
|
19296
19416
|
}
|
|
19297
|
-
stopped(signal) {
|
|
19417
|
+
stopped(signal, oauth = false) {
|
|
19298
19418
|
if (signal.reason === "timeout")
|
|
19299
|
-
return errorReply("ETIMEDOUT", "the vault did not answer within 10 s");
|
|
19419
|
+
return oauth ? sealedOAuthError("ETIMEDOUT") : errorReply("ETIMEDOUT", "the vault did not answer within 10 s");
|
|
19300
19420
|
return signal.reason === "expired" ? { v: 1, state: "expired" } : void 0;
|
|
19301
19421
|
}
|
|
19302
19422
|
async answer(req, signal) {
|
|
19303
19423
|
const hook = this.broker.hook;
|
|
19304
|
-
|
|
19424
|
+
const oauth = sealedOAuthOperation(req.op);
|
|
19425
|
+
if (!hook)
|
|
19426
|
+
return oauth ? sealedOAuthError("ENOTCONN") : errorReply("ENOTCONN", "no vault is connected");
|
|
19305
19427
|
const stopped = new Promise((resolve2) => {
|
|
19306
19428
|
signal.addEventListener("abort", () => resolve2(void 0), { once: true });
|
|
19307
19429
|
});
|
|
19308
19430
|
if (signal.aborted) return void 0;
|
|
19309
19431
|
const asked = Promise.resolve().then(() => hook(req, { signal })).then(
|
|
19310
|
-
(reply2) => isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
|
|
19311
|
-
(err) => errorReply("EIO", lineOf3(err))
|
|
19432
|
+
(reply2) => oauth ? sealedOAuthReply(req.op, reply2) : isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
|
|
19433
|
+
(err) => oauth ? sealedOAuthError() : errorReply("EIO", lineOf3(err))
|
|
19312
19434
|
);
|
|
19313
19435
|
const reply = await Promise.race([asked, stopped]);
|
|
19314
|
-
return signal.aborted ? this.stopped(signal) : reply;
|
|
19436
|
+
return signal.aborted ? this.stopped(signal, oauth) : reply;
|
|
19315
19437
|
}
|
|
19316
19438
|
drop() {
|
|
19317
19439
|
this.reply?.fill(0);
|
|
@@ -19374,6 +19496,7 @@ var SealedBroker = class {
|
|
|
19374
19496
|
tickets = new TicketBook();
|
|
19375
19497
|
sessions = new SessionScrubs();
|
|
19376
19498
|
askTimeoutMs = SEALED_ASK_TIMEOUT_MS;
|
|
19499
|
+
oauthTimeoutMs = SEALED_OAUTH_TIMEOUT_MS;
|
|
19377
19500
|
userOf = async () => void 0;
|
|
19378
19501
|
factsOf = async () => void 0;
|
|
19379
19502
|
constructor(hook, users, timeoutMs = SEALED_TIMEOUT_MS, tagOf = () => void 0) {
|
|
@@ -19494,7 +19617,7 @@ var Timestamps = class {
|
|
|
19494
19617
|
// src/sudoers.ts
|
|
19495
19618
|
var SUDOERS = "/etc/sudoers";
|
|
19496
19619
|
var SUDOERS_D = "/etc/sudoers.d";
|
|
19497
|
-
var
|
|
19620
|
+
var NAME4 = /^[a-z_][a-z0-9_.-]*$/;
|
|
19498
19621
|
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
19499
19622
|
var KERNEL_FORM = new RegExp(
|
|
19500
19623
|
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()]*)\)\s+)?(?:Cwd\s+(${WORD})\s+)?(?:Stdin\s+(\S+)\s+)?Cmnd(?:\s+(.*))?$`
|
|
@@ -19504,7 +19627,7 @@ var RUNAS = /^\(([^()]*)\)\s*/;
|
|
|
19504
19627
|
var TAG = /^([A-Z_]+)\s*:\s*/;
|
|
19505
19628
|
var OPTION = /^([A-Z_]+)=/;
|
|
19506
19629
|
var PLAIN2 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
19507
|
-
var
|
|
19630
|
+
var CONTROL2 = /[\p{Cc}\u2028\u2029]/u;
|
|
19508
19631
|
var CONTROLS = /[\p{Cc}\u2028\u2029]/gu;
|
|
19509
19632
|
var SHOWN_MAX = 60;
|
|
19510
19633
|
var KERNEL_SYNTAX = "[NOPASSWD] <user|%group|ALL> [(<target>)] [Cwd <dir>] [Stdin none] Cmnd <command\u2026|*>";
|
|
@@ -19513,7 +19636,7 @@ var EXPECTED = `expected '${KERNEL_SYNTAX}' or '${SUDOERS_SYNTAX}'`;
|
|
|
19513
19636
|
var TIMESTAMP_TIMEOUT = 5;
|
|
19514
19637
|
var TIMESTAMP_TYPE = "tty";
|
|
19515
19638
|
function hasControl(text) {
|
|
19516
|
-
return
|
|
19639
|
+
return CONTROL2.test(text);
|
|
19517
19640
|
}
|
|
19518
19641
|
function withoutControl(text) {
|
|
19519
19642
|
return text.replace(CONTROLS, (ch) => {
|
|
@@ -19651,7 +19774,7 @@ function commandText(cmnd) {
|
|
|
19651
19774
|
}
|
|
19652
19775
|
function validWho(who) {
|
|
19653
19776
|
if (who === "ALL") return true;
|
|
19654
|
-
return
|
|
19777
|
+
return NAME4.test(who.startsWith("%") ? who.slice(1) : who);
|
|
19655
19778
|
}
|
|
19656
19779
|
function whoError(who) {
|
|
19657
19780
|
if (validWho(who)) return void 0;
|
|
@@ -19684,7 +19807,7 @@ function kernelRules(m) {
|
|
|
19684
19807
|
const [, nopasswd, who = "", target = "root", dir, stdin, rest2 = ""] = m;
|
|
19685
19808
|
const bad = whoError(who);
|
|
19686
19809
|
if (bad !== void 0) return bad;
|
|
19687
|
-
if (target !== "ALL" && !
|
|
19810
|
+
if (target !== "ALL" && !NAME4.test(target)) return targetError(target);
|
|
19688
19811
|
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
19689
19812
|
if (cwd === "") return `Cwd expects one absolute directory, not ${shown(dir)}`;
|
|
19690
19813
|
if (stdin !== void 0 && stdin !== "none") return `Stdin takes none, not ${shown(stdin)}`;
|
|
@@ -19708,11 +19831,11 @@ function runasOf(list) {
|
|
|
19708
19831
|
return colon < 0 ? "() names no user to run as: name one, or leave the (\u2026) out for root" : `(${list}) runs as the caller with another group, which the kernel's sudo can't do`;
|
|
19709
19832
|
}
|
|
19710
19833
|
for (const name2 of names2) {
|
|
19711
|
-
if (name2 === "ALL" ||
|
|
19834
|
+
if (name2 === "ALL" || NAME4.test(name2)) continue;
|
|
19712
19835
|
return `expected user names or ALL to run as, not ${shown(name2)} (no %group, #uid or !user)`;
|
|
19713
19836
|
}
|
|
19714
19837
|
for (const group of groups) {
|
|
19715
|
-
if (group === "" || group === "ALL" ||
|
|
19838
|
+
if (group === "" || group === "ALL" || NAME4.test(group)) continue;
|
|
19716
19839
|
return `expected group names or ALL after ':' in (\u2026), not ${shown(group)}`;
|
|
19717
19840
|
}
|
|
19718
19841
|
return names2.includes("ALL") ? ["ALL"] : [...new Set(names2)];
|
|
@@ -19801,7 +19924,7 @@ function directiveError(text) {
|
|
|
19801
19924
|
}
|
|
19802
19925
|
function recordedBare(line, file, rule) {
|
|
19803
19926
|
if (rule.cmnd === "*" || rule.cmnd.args !== void 0 || !rule.nopasswd) return false;
|
|
19804
|
-
if (file !== `${SUDOERS_D}/${rule.who}` || !
|
|
19927
|
+
if (file !== `${SUDOERS_D}/${rule.who}` || !NAME4.test(rule.who) || !NAME4.test(rule.target)) {
|
|
19805
19928
|
return false;
|
|
19806
19929
|
}
|
|
19807
19930
|
const head = `NOPASSWD ${rule.who} (${rule.target}) `;
|
|
@@ -20501,7 +20624,7 @@ ${lines2}
|
|
|
20501
20624
|
async remember(self, target, cwd, argv) {
|
|
20502
20625
|
const { fs } = this.o;
|
|
20503
20626
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
20504
|
-
if (!
|
|
20627
|
+
if (!NAME4.test(self.name)) return false;
|
|
20505
20628
|
try {
|
|
20506
20629
|
await this.provision();
|
|
20507
20630
|
if (!await this.trusted(SUDOERS_D)) return false;
|
|
@@ -21870,8 +21993,8 @@ function sameCert(a, b) {
|
|
|
21870
21993
|
if (!a || !b) return a === b;
|
|
21871
21994
|
return a.cert.length === b.cert.length && a.cert.every((byte, i) => byte === b.cert[i]);
|
|
21872
21995
|
}
|
|
21873
|
-
function winner(current, expected,
|
|
21874
|
-
return sameCert(current, expected) ?
|
|
21996
|
+
function winner(current, expected, record3) {
|
|
21997
|
+
return sameCert(current, expected) ? record3 : current;
|
|
21875
21998
|
}
|
|
21876
21999
|
var DAY = 24 * 60 * 60 * 1e3;
|
|
21877
22000
|
var CA_LIFETIME = 3650 * DAY;
|
|
@@ -21904,15 +22027,15 @@ function indexedDbCaStore(dbName = "slicc-realm-ca") {
|
|
|
21904
22027
|
const store = (await open2()).transaction("ca").objectStore("ca");
|
|
21905
22028
|
return await request2(store.get(owner));
|
|
21906
22029
|
},
|
|
21907
|
-
async swap(owner, expected,
|
|
22030
|
+
async swap(owner, expected, record3) {
|
|
21908
22031
|
const tx = (await open2()).transaction("ca", "readwrite");
|
|
21909
22032
|
const store = tx.objectStore("ca");
|
|
21910
|
-
let stored2 =
|
|
22033
|
+
let stored2 = record3;
|
|
21911
22034
|
const read = store.get(owner);
|
|
21912
22035
|
read.onsuccess = () => {
|
|
21913
22036
|
const current = read.result;
|
|
21914
|
-
const kept = winner(current, expected,
|
|
21915
|
-
if (kept ===
|
|
22037
|
+
const kept = winner(current, expected, record3);
|
|
22038
|
+
if (kept === record3) store.put(record3, owner);
|
|
21916
22039
|
else stored2 = kept;
|
|
21917
22040
|
};
|
|
21918
22041
|
await new Promise((resolve2, reject) => {
|
|
@@ -21932,14 +22055,14 @@ function validLeafName(host) {
|
|
|
21932
22055
|
}
|
|
21933
22056
|
var RealmCa = class _RealmCa {
|
|
21934
22057
|
record;
|
|
21935
|
-
constructor(
|
|
21936
|
-
this.record =
|
|
22058
|
+
constructor(record3) {
|
|
22059
|
+
this.record = record3;
|
|
21937
22060
|
}
|
|
21938
22061
|
static async open(owner, store, now = Date.now()) {
|
|
21939
22062
|
const stored2 = await store.get(owner).catch(() => void 0);
|
|
21940
22063
|
if (stored2 && stored2.notAfter - now > CA_RENEW_BEFORE) return new _RealmCa(stored2);
|
|
21941
|
-
const
|
|
21942
|
-
return new _RealmCa(await store.swap(owner, stored2,
|
|
22064
|
+
const record3 = await _RealmCa.create(owner, now);
|
|
22065
|
+
return new _RealmCa(await store.swap(owner, stored2, record3));
|
|
21943
22066
|
}
|
|
21944
22067
|
static async create(owner, now) {
|
|
21945
22068
|
const pair = await crypto.subtle.generateKey(ECDSA, false, ["sign", "verify"]);
|
|
@@ -22166,8 +22289,8 @@ function memoryCaStore() {
|
|
|
22166
22289
|
const records = /* @__PURE__ */ new Map();
|
|
22167
22290
|
return {
|
|
22168
22291
|
get: async (owner) => records.get(owner),
|
|
22169
|
-
swap: async (owner, expected,
|
|
22170
|
-
const kept = winner(records.get(owner), expected,
|
|
22292
|
+
swap: async (owner, expected, record3) => {
|
|
22293
|
+
const kept = winner(records.get(owner), expected, record3);
|
|
22171
22294
|
records.set(owner, kept);
|
|
22172
22295
|
return kept;
|
|
22173
22296
|
}
|
|
@@ -22570,6 +22693,9 @@ var HttpHandles = class {
|
|
|
22570
22693
|
if (e instanceof PlaceholderRefused) {
|
|
22571
22694
|
return { ok: false, errno: e.code, message: text, detail: "placeholder" };
|
|
22572
22695
|
}
|
|
22696
|
+
if (e.detail === FORBIDDEN_HEADER) {
|
|
22697
|
+
return { ok: false, errno: "ENOTSUP", message: text, detail: FORBIDDEN_HEADER };
|
|
22698
|
+
}
|
|
22573
22699
|
const status = e.status;
|
|
22574
22700
|
if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
|
|
22575
22701
|
const code = codeOf2(e);
|
|
@@ -30416,7 +30542,7 @@ function header2(id2, flags2, counts) {
|
|
|
30416
30542
|
function opt() {
|
|
30417
30543
|
return [0, 0, TYPE_OPT, UDP_EDNS >> 8, UDP_EDNS & 255, 0, 0, 0, 0, 0, 0];
|
|
30418
30544
|
}
|
|
30419
|
-
function
|
|
30545
|
+
function record2(type, rdata) {
|
|
30420
30546
|
const ttl = DNS_STUB_TTL;
|
|
30421
30547
|
return [
|
|
30422
30548
|
192,
|
|
@@ -30524,14 +30650,14 @@ var DnsStub = class {
|
|
|
30524
30650
|
const address = reverseAddress(q.name);
|
|
30525
30651
|
const name2 = address !== void 0 ? await this.reverse(address) : void 0;
|
|
30526
30652
|
if (name2 !== void 0)
|
|
30527
|
-
return answerReply(query, q, NOERROR, [
|
|
30653
|
+
return answerReply(query, q, NOERROR, [record2(TYPE_PTR, encodeName(name2))], true);
|
|
30528
30654
|
return this.forward(query, q);
|
|
30529
30655
|
}
|
|
30530
30656
|
if (q.type === TYPE_A || q.type === TYPE_AAAA) {
|
|
30531
30657
|
const addresses = q.name === "" ? [] : await this.lookup(q.name);
|
|
30532
30658
|
const answers2 = addresses.flatMap((a) => {
|
|
30533
30659
|
const data = addressData(a, q.type);
|
|
30534
|
-
return data ? [
|
|
30660
|
+
return data ? [record2(q.type, data)] : [];
|
|
30535
30661
|
});
|
|
30536
30662
|
if (answers2.length > 0 || local(q.name) || await this.known(q.name)) {
|
|
30537
30663
|
const rcode = addresses.length > 0 ? NOERROR : NXDOMAIN;
|
|
@@ -30720,7 +30846,7 @@ var TransportError = class extends Error {
|
|
|
30720
30846
|
super(message3);
|
|
30721
30847
|
this.status = status;
|
|
30722
30848
|
this.code = code;
|
|
30723
|
-
this.detail = detail === "transport" ? detail : void 0;
|
|
30849
|
+
this.detail = detail === "transport" || detail === FORBIDDEN_HEADER ? detail : void 0;
|
|
30724
30850
|
}
|
|
30725
30851
|
};
|
|
30726
30852
|
function unfollowed2(redirect) {
|
|
@@ -34516,8 +34642,8 @@ var Launcher = class {
|
|
|
34516
34642
|
const caller = this.jobs.shown(ppid);
|
|
34517
34643
|
const named = typeof req.argv0 === "string" && !planned.script && !planned.target.fixed;
|
|
34518
34644
|
const argv = named ? [req.argv0, ...req.argv.slice(1)] : req.argv;
|
|
34519
|
-
const
|
|
34520
|
-
if (!
|
|
34645
|
+
const exact2 = booked?.pid === caller && req.file === booked.path && await physicalPathAsync(this.base, req.cwd) === booked.cwd && await argvDigest(argv) === booked.argv;
|
|
34646
|
+
if (!exact2) throw new SpawnError("EACCES");
|
|
34521
34647
|
const { requested: path, requestedCwd: cwd, path: resolved2 } = booked;
|
|
34522
34648
|
const pid = this.nextPid++;
|
|
34523
34649
|
const ids = { pid: req.exec ? caller : pid, ppid: caller };
|
|
@@ -35880,9 +36006,9 @@ var Launcher = class {
|
|
|
35880
36006
|
}
|
|
35881
36007
|
pnpmReady() {
|
|
35882
36008
|
if (this.pnpmMade !== void 0) return this.pnpmMade;
|
|
35883
|
-
const
|
|
36009
|
+
const epoch2 = this.pnpmEpoch;
|
|
35884
36010
|
const made2 = this.base.mkdir(this.pnpmHome, { recursive: true }).then(() => this.owners ? this.stampLayout() : void 0).catch(() => {
|
|
35885
|
-
if (this.pnpmEpoch ===
|
|
36011
|
+
if (this.pnpmEpoch === epoch2) this.pnpmMade = void 0;
|
|
35886
36012
|
});
|
|
35887
36013
|
this.pnpmMade = made2;
|
|
35888
36014
|
return made2;
|