@ai-ecoverse/slicc-kernel 1.177.0 → 1.178.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 +20 -2
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +192 -72
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +187 -67
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +1 -1
- package/dist/types/index.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/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}`);
|
|
@@ -8682,12 +8682,12 @@ function next(p) {
|
|
|
8682
8682
|
var ANY = [[">=", [0, 0, 0, []]]];
|
|
8683
8683
|
var NOTHING = [["<", [0, 0, 0, ["0"]]]];
|
|
8684
8684
|
function plain(op, p) {
|
|
8685
|
-
const
|
|
8685
|
+
const exact2 = !p.parts.includes(void 0);
|
|
8686
8686
|
const low = floor(p);
|
|
8687
8687
|
const high = next(p);
|
|
8688
8688
|
if (op === ">=") return [[">=", low]];
|
|
8689
|
-
if (op === "<") return [["<",
|
|
8690
|
-
if (
|
|
8689
|
+
if (op === "<") return [["<", exact2 ? low : [low[0], low[1], low[2], ["0"]]]];
|
|
8690
|
+
if (exact2) return [[op === "" ? "=" : op, low]];
|
|
8691
8691
|
if (op === ">") return high ? [[">=", high]] : NOTHING;
|
|
8692
8692
|
if (op === "<=") return high ? [["<", high]] : ANY;
|
|
8693
8693
|
return high ? [
|
|
@@ -8774,7 +8774,7 @@ function satisfies(version, range2) {
|
|
|
8774
8774
|
}
|
|
8775
8775
|
|
|
8776
8776
|
// src/version.ts
|
|
8777
|
-
var KERNEL_VERSION = true ? "1.
|
|
8777
|
+
var KERNEL_VERSION = true ? "1.178.0" : "0.0.0-dev";
|
|
8778
8778
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8779
8779
|
function procVersion() {
|
|
8780
8780
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9364,7 +9364,7 @@ function intlZone(name2) {
|
|
|
9364
9364
|
minute: "numeric",
|
|
9365
9365
|
second: "numeric"
|
|
9366
9366
|
});
|
|
9367
|
-
const
|
|
9367
|
+
const exact2 = (at) => {
|
|
9368
9368
|
const parts2 = {};
|
|
9369
9369
|
for (const part of format.formatToParts(at)) parts2[part.type] = Number(part.value);
|
|
9370
9370
|
const wall = Date.UTC(
|
|
@@ -9384,12 +9384,12 @@ function intlZone(name2) {
|
|
|
9384
9384
|
const bucket = Math.floor(at / BUCKET_MS);
|
|
9385
9385
|
let known = buckets.get(bucket);
|
|
9386
9386
|
if (known === void 0) {
|
|
9387
|
-
const start2 =
|
|
9388
|
-
known = start2 ===
|
|
9387
|
+
const start2 = exact2(bucket * BUCKET_MS);
|
|
9388
|
+
known = start2 === exact2(bucket * BUCKET_MS + BUCKET_MS - MINUTE_MS) ? start2 : null;
|
|
9389
9389
|
if (buckets.size >= CACHE_MAX) buckets.clear();
|
|
9390
9390
|
buckets.set(bucket, known);
|
|
9391
9391
|
}
|
|
9392
|
-
return known ??
|
|
9392
|
+
return known ?? exact2(at);
|
|
9393
9393
|
}
|
|
9394
9394
|
};
|
|
9395
9395
|
}
|
|
@@ -10619,11 +10619,11 @@ var CronService = class {
|
|
|
10619
10619
|
const now = this.clock.now();
|
|
10620
10620
|
const system = this.host.timeZone;
|
|
10621
10621
|
const due2 = [];
|
|
10622
|
-
const
|
|
10622
|
+
const keys2 = /* @__PURE__ */ new Set();
|
|
10623
10623
|
let next3 = now + WAKE_MS;
|
|
10624
10624
|
for (const entry of loaded) {
|
|
10625
10625
|
const key = keyOf2(entry);
|
|
10626
|
-
|
|
10626
|
+
keys2.add(key);
|
|
10627
10627
|
const { when } = entry.job;
|
|
10628
10628
|
if (when.reboot) {
|
|
10629
10629
|
if (this.rebooted || stamp.reboot[key] === this.host.bootId) continue;
|
|
@@ -10649,7 +10649,7 @@ var CronService = class {
|
|
|
10649
10649
|
}
|
|
10650
10650
|
this.rebooted = true;
|
|
10651
10651
|
for (const map of [stamp.jobs, stamp.reboot, stamp.when])
|
|
10652
|
-
for (const key of Object.keys(map)) if (!
|
|
10652
|
+
for (const key of Object.keys(map)) if (!keys2.has(key)) delete map[key];
|
|
10653
10653
|
await this.writeStamp(stamp);
|
|
10654
10654
|
for (const each of due2) void this.spawn(each);
|
|
10655
10655
|
return next3;
|
|
@@ -11755,16 +11755,16 @@ function missing4(err) {
|
|
|
11755
11755
|
return err?.code === "ENOENT";
|
|
11756
11756
|
}
|
|
11757
11757
|
function synthetic(directory, path) {
|
|
11758
|
-
const
|
|
11758
|
+
const epoch2 = /* @__PURE__ */ new Date(0);
|
|
11759
11759
|
return {
|
|
11760
11760
|
isFile: !directory,
|
|
11761
11761
|
isDirectory: directory,
|
|
11762
11762
|
isSymbolicLink: false,
|
|
11763
11763
|
size: 0,
|
|
11764
11764
|
mode: (directory ? S_IFDIR2 : S_IFREG2) | 493,
|
|
11765
|
-
mtime:
|
|
11766
|
-
atime:
|
|
11767
|
-
ctime:
|
|
11765
|
+
mtime: epoch2,
|
|
11766
|
+
atime: epoch2,
|
|
11767
|
+
ctime: epoch2,
|
|
11768
11768
|
ino: inodeOf(path)
|
|
11769
11769
|
};
|
|
11770
11770
|
}
|
|
@@ -11983,16 +11983,16 @@ function missing5(err) {
|
|
|
11983
11983
|
return err?.code === "ENOENT";
|
|
11984
11984
|
}
|
|
11985
11985
|
function statOf(path, bytes) {
|
|
11986
|
-
const
|
|
11986
|
+
const epoch2 = /* @__PURE__ */ new Date(0);
|
|
11987
11987
|
return {
|
|
11988
11988
|
isFile: true,
|
|
11989
11989
|
isDirectory: false,
|
|
11990
11990
|
isSymbolicLink: false,
|
|
11991
11991
|
size: bytes.length,
|
|
11992
11992
|
mode: S_IFREG3 | 420,
|
|
11993
|
-
mtime:
|
|
11994
|
-
atime:
|
|
11995
|
-
ctime:
|
|
11993
|
+
mtime: epoch2,
|
|
11994
|
+
atime: epoch2,
|
|
11995
|
+
ctime: epoch2,
|
|
11996
11996
|
ino: inodeOf(path),
|
|
11997
11997
|
nlink: 1,
|
|
11998
11998
|
uid: 0,
|
|
@@ -14048,11 +14048,11 @@ var HeldPaths = class extends Map {
|
|
|
14048
14048
|
handlesAt(path) {
|
|
14049
14049
|
return [...this.handles].filter(([, key]) => key === path).map(([id2]) => id2);
|
|
14050
14050
|
}
|
|
14051
|
-
doubt(over,
|
|
14051
|
+
doubt(over, exact2 = false) {
|
|
14052
14052
|
if (this.bound.size === 0) return;
|
|
14053
14053
|
for (const [handle, key] of this.handles) {
|
|
14054
14054
|
if (!this.bound.has(handle) || this.keptHandles.has(handle)) continue;
|
|
14055
|
-
if (
|
|
14055
|
+
if (exact2 ? key === over : within7(key, over)) this.doubted.set(handle, ++this.doubts);
|
|
14056
14056
|
}
|
|
14057
14057
|
}
|
|
14058
14058
|
boundIno(handle) {
|
|
@@ -17907,8 +17907,8 @@ function refused2(engine, session, err, opening2) {
|
|
|
17907
17907
|
const code = verifyCode(flags2);
|
|
17908
17908
|
if (code && flags2 !== -1)
|
|
17909
17909
|
return new KernelError("EPROTO", `${code}: ${engine.verifyInfo(flags2).trim()}`);
|
|
17910
|
-
const
|
|
17911
|
-
if (
|
|
17910
|
+
const record3 = recordRefusal(opening2);
|
|
17911
|
+
if (record3) return record3;
|
|
17912
17912
|
const text = err instanceof TlsError ? err.message : String(err);
|
|
17913
17913
|
return new KernelError("EPROTO", `ERR_SSL_HANDSHAKE_FAILURE: ${text}${alertOf(session)}`);
|
|
17914
17914
|
}
|
|
@@ -19023,6 +19023,120 @@ var SessionScrubs = class {
|
|
|
19023
19023
|
}
|
|
19024
19024
|
};
|
|
19025
19025
|
|
|
19026
|
+
// src/kernel/sealed-oauth.ts
|
|
19027
|
+
var SEALED_OAUTH_TIMEOUT_MS = 45e3;
|
|
19028
|
+
var SEALED_OAUTH_OPS = /* @__PURE__ */ new Set([
|
|
19029
|
+
"oauthGrant",
|
|
19030
|
+
"oauthStatus",
|
|
19031
|
+
"oauthRefresh",
|
|
19032
|
+
"oauthRemove"
|
|
19033
|
+
]);
|
|
19034
|
+
var MESSAGES = {
|
|
19035
|
+
EINVAL: "Invalid OAuth request",
|
|
19036
|
+
ENOENT: "OAuth credential not found",
|
|
19037
|
+
EEXIST: "OAuth credential identity conflicts",
|
|
19038
|
+
EACCES: "OAuth operation refused",
|
|
19039
|
+
EAGAIN: "OAuth credential changed; try again",
|
|
19040
|
+
ENOTSUP: "OAuth operation is not supported",
|
|
19041
|
+
ENOTCONN: "Vault is unavailable",
|
|
19042
|
+
ETIMEDOUT: "Vault request timed out",
|
|
19043
|
+
EIO: "Invalid vault reply"
|
|
19044
|
+
};
|
|
19045
|
+
var CAUSES = {
|
|
19046
|
+
"vault-locked": "Vault is locked",
|
|
19047
|
+
"oauth-reauth-required": "OAuth sign-in is required",
|
|
19048
|
+
"oauth-refresh-failed": "OAuth refresh failed"
|
|
19049
|
+
};
|
|
19050
|
+
var COMMON = ["v", "op", "caller"];
|
|
19051
|
+
var IDENTITY = [...COMMON, "name", "provider", "account"];
|
|
19052
|
+
var GRANT = [...IDENTITY, "accessToken", "refreshToken", "tokenType", "expiresAt", "oauth"];
|
|
19053
|
+
var CONFIG = ["tokenUrl", "clientId", "authMethod", "scope", "resource"];
|
|
19054
|
+
var UNSUPPORTED = ["auth", "clientSecret", "fields"];
|
|
19055
|
+
var STATES2 = /* @__PURE__ */ new Set([
|
|
19056
|
+
"ready",
|
|
19057
|
+
"refreshing",
|
|
19058
|
+
"expired",
|
|
19059
|
+
"reauth-required",
|
|
19060
|
+
"removed",
|
|
19061
|
+
"locked"
|
|
19062
|
+
]);
|
|
19063
|
+
var NAME3 = /^[A-Za-z_][A-Za-z0-9_]{0,127}$/;
|
|
19064
|
+
var PROVIDER = /^[a-z0-9][a-z0-9-]{0,127}$/;
|
|
19065
|
+
var PLACEHOLDER2 = /^fnox_proxy_[0-9a-f]{24}$/;
|
|
19066
|
+
var CONTROL = /[\u0000-\u001f\u007f-\u009f]/;
|
|
19067
|
+
function record(value2) {
|
|
19068
|
+
return typeof value2 === "object" && value2 !== null && !Array.isArray(value2);
|
|
19069
|
+
}
|
|
19070
|
+
function keys(value2, allowed) {
|
|
19071
|
+
return Object.keys(value2).every((key) => allowed.includes(key));
|
|
19072
|
+
}
|
|
19073
|
+
function exact(value2, fields) {
|
|
19074
|
+
return Object.keys(value2).length === fields.length && keys(value2, fields);
|
|
19075
|
+
}
|
|
19076
|
+
function nonempty(value2) {
|
|
19077
|
+
return typeof value2 === "string" && value2.length > 0;
|
|
19078
|
+
}
|
|
19079
|
+
function epoch(value2) {
|
|
19080
|
+
return typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 0;
|
|
19081
|
+
}
|
|
19082
|
+
function sealedOAuthOperation(op) {
|
|
19083
|
+
return op === "capabilities" || SEALED_OAUTH_OPS.has(op);
|
|
19084
|
+
}
|
|
19085
|
+
function validateSealedOAuth(req) {
|
|
19086
|
+
const config = req.oauth;
|
|
19087
|
+
if (UNSUPPORTED.some((key) => Object.hasOwn(req, key)) || record(config) && UNSUPPORTED.some((key) => Object.hasOwn(config, key)))
|
|
19088
|
+
throw new KernelError("ENOTSUP");
|
|
19089
|
+
const allowed = req.op === "capabilities" ? COMMON : req.op === "oauthGrant" ? GRANT : IDENTITY;
|
|
19090
|
+
if (!keys(req, allowed)) throw new KernelError("EINVAL");
|
|
19091
|
+
if (req.op === "capabilities") return;
|
|
19092
|
+
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))
|
|
19093
|
+
throw new KernelError("EINVAL");
|
|
19094
|
+
if (req.op !== "oauthGrant") return;
|
|
19095
|
+
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))
|
|
19096
|
+
throw new KernelError("EINVAL");
|
|
19097
|
+
if (config.authMethod !== "none" || typeof req.tokenType === "string" && req.tokenType.toLowerCase() !== "bearer")
|
|
19098
|
+
throw new KernelError("ENOTSUP");
|
|
19099
|
+
}
|
|
19100
|
+
function sealedOAuthError(code = "EIO", cause) {
|
|
19101
|
+
return {
|
|
19102
|
+
v: 1,
|
|
19103
|
+
error: { code, ...cause ? { cause } : {}, message: cause ? CAUSES[cause] : MESSAGES[code] }
|
|
19104
|
+
};
|
|
19105
|
+
}
|
|
19106
|
+
function sealedOAuthReply(op, value2) {
|
|
19107
|
+
try {
|
|
19108
|
+
return checkedReply(op, value2) ?? sealedOAuthError();
|
|
19109
|
+
} catch {
|
|
19110
|
+
return sealedOAuthError();
|
|
19111
|
+
}
|
|
19112
|
+
}
|
|
19113
|
+
function checkedError(value2) {
|
|
19114
|
+
const error = value2.error;
|
|
19115
|
+
if (!exact(value2, ["v", "error"]) || !record(error) || !Object.hasOwn(error, "code") || !Object.hasOwn(error, "message"))
|
|
19116
|
+
return void 0;
|
|
19117
|
+
const { code, cause, message: message3 } = error;
|
|
19118
|
+
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)))
|
|
19119
|
+
return void 0;
|
|
19120
|
+
return sealedOAuthError(code, cause);
|
|
19121
|
+
}
|
|
19122
|
+
function checkedReply(op, value2) {
|
|
19123
|
+
if (!record(value2) || !Object.hasOwn(value2, "v") || value2.v !== 1) return void 0;
|
|
19124
|
+
if (Object.hasOwn(value2, "error")) return checkedError(value2);
|
|
19125
|
+
if (op === "capabilities") {
|
|
19126
|
+
const caps = value2.capabilities;
|
|
19127
|
+
if (!exact(value2, ["v", "capabilities"]) || !record(caps) || !keys(caps, ["kernelOAuth"]))
|
|
19128
|
+
return void 0;
|
|
19129
|
+
if (Object.hasOwn(caps, "kernelOAuth") && caps.kernelOAuth !== 1) return void 0;
|
|
19130
|
+
return { v: 1, capabilities: Object.hasOwn(caps, "kernelOAuth") ? { kernelOAuth: 1 } : {} };
|
|
19131
|
+
}
|
|
19132
|
+
if (op === "oauthRemove")
|
|
19133
|
+
return exact(value2, ["v", "removed"]) && value2.removed === true ? { v: 1, removed: true } : void 0;
|
|
19134
|
+
const { placeholder, state, expiresAt, refreshable } = value2;
|
|
19135
|
+
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")
|
|
19136
|
+
return void 0;
|
|
19137
|
+
return { v: 1, placeholder, state, expiresAt, refreshable };
|
|
19138
|
+
}
|
|
19139
|
+
|
|
19026
19140
|
// src/kernel/sealed-session.ts
|
|
19027
19141
|
var SESSION_WINDOW_MS = 6e4;
|
|
19028
19142
|
var SESSION_PLACEHOLDERS = 16;
|
|
@@ -19133,8 +19247,8 @@ function sessionValues(reply, asked) {
|
|
|
19133
19247
|
const { error, values } = reply;
|
|
19134
19248
|
if (error !== void 0 || typeof values !== "object" || values === null) return void 0;
|
|
19135
19249
|
const out = {};
|
|
19136
|
-
const
|
|
19137
|
-
const wanted = asked ?? (
|
|
19250
|
+
const keys2 = Object.keys(values);
|
|
19251
|
+
const wanted = asked ?? (keys2.length === 1 && SESSION_PLACEHOLDER.test(keys2[0]) ? keys2 : []);
|
|
19138
19252
|
for (const ph of wanted) {
|
|
19139
19253
|
const value2 = values[ph];
|
|
19140
19254
|
if (typeof value2 === "string" && value2.length > 0 && !UNSAFE.test(value2)) out[ph] = value2;
|
|
@@ -19158,7 +19272,9 @@ var SEALED_OPS = /* @__PURE__ */ new Set([
|
|
|
19158
19272
|
"request",
|
|
19159
19273
|
"status",
|
|
19160
19274
|
"cancel",
|
|
19161
|
-
"materialize"
|
|
19275
|
+
"materialize",
|
|
19276
|
+
"capabilities",
|
|
19277
|
+
...SEALED_OAUTH_OPS
|
|
19162
19278
|
]);
|
|
19163
19279
|
function tagFields(tags) {
|
|
19164
19280
|
const [tag] = tags ?? [];
|
|
@@ -19193,6 +19309,7 @@ function parseSealed(bytes) {
|
|
|
19193
19309
|
throw new KernelError("EINVAL");
|
|
19194
19310
|
if (req.op === "materialize" && !materializable(req)) throw new KernelError("EINVAL");
|
|
19195
19311
|
if (req.op === "ask" && !askable(req)) throw new KernelError("EINVAL");
|
|
19312
|
+
if (sealedOAuthOperation(req.op)) validateSealedOAuth(req);
|
|
19196
19313
|
return req;
|
|
19197
19314
|
} finally {
|
|
19198
19315
|
bytes.fill(0);
|
|
@@ -19271,7 +19388,7 @@ var SealedChannel = class {
|
|
|
19271
19388
|
const ask = fields.op === "ask";
|
|
19272
19389
|
const timer = setTimeout(
|
|
19273
19390
|
() => control.abort(ask ? "expired" : "timeout"),
|
|
19274
|
-
ask ? this.broker.askTimeoutMs : this.broker.timeoutMs
|
|
19391
|
+
ask ? this.broker.askTimeoutMs : SEALED_OAUTH_OPS.has(fields.op) ? this.broker.oauthTimeoutMs : this.broker.timeoutMs
|
|
19275
19392
|
);
|
|
19276
19393
|
const req = { ...fields, v: 1, op: fields.op, caller };
|
|
19277
19394
|
const asked = ask ? this.asking(fields, caller, requester, control.signal) : void 0;
|
|
@@ -19294,24 +19411,26 @@ var SealedChannel = class {
|
|
|
19294
19411
|
if (!facts) return errorReply("EIO", "the kernel has no record of this process");
|
|
19295
19412
|
return this.answer(askRequest(fields, caller, facts), signal);
|
|
19296
19413
|
}
|
|
19297
|
-
stopped(signal) {
|
|
19414
|
+
stopped(signal, oauth = false) {
|
|
19298
19415
|
if (signal.reason === "timeout")
|
|
19299
|
-
return errorReply("ETIMEDOUT", "the vault did not answer within 10 s");
|
|
19416
|
+
return oauth ? sealedOAuthError("ETIMEDOUT") : errorReply("ETIMEDOUT", "the vault did not answer within 10 s");
|
|
19300
19417
|
return signal.reason === "expired" ? { v: 1, state: "expired" } : void 0;
|
|
19301
19418
|
}
|
|
19302
19419
|
async answer(req, signal) {
|
|
19303
19420
|
const hook = this.broker.hook;
|
|
19304
|
-
|
|
19421
|
+
const oauth = sealedOAuthOperation(req.op);
|
|
19422
|
+
if (!hook)
|
|
19423
|
+
return oauth ? sealedOAuthError("ENOTCONN") : errorReply("ENOTCONN", "no vault is connected");
|
|
19305
19424
|
const stopped = new Promise((resolve2) => {
|
|
19306
19425
|
signal.addEventListener("abort", () => resolve2(void 0), { once: true });
|
|
19307
19426
|
});
|
|
19308
19427
|
if (signal.aborted) return void 0;
|
|
19309
19428
|
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))
|
|
19429
|
+
(reply2) => oauth ? sealedOAuthReply(req.op, reply2) : isRecord(reply2) ? reply2 : errorReply("EIO", "the vault gave no reply"),
|
|
19430
|
+
(err) => oauth ? sealedOAuthError() : errorReply("EIO", lineOf3(err))
|
|
19312
19431
|
);
|
|
19313
19432
|
const reply = await Promise.race([asked, stopped]);
|
|
19314
|
-
return signal.aborted ? this.stopped(signal) : reply;
|
|
19433
|
+
return signal.aborted ? this.stopped(signal, oauth) : reply;
|
|
19315
19434
|
}
|
|
19316
19435
|
drop() {
|
|
19317
19436
|
this.reply?.fill(0);
|
|
@@ -19374,6 +19493,7 @@ var SealedBroker = class {
|
|
|
19374
19493
|
tickets = new TicketBook();
|
|
19375
19494
|
sessions = new SessionScrubs();
|
|
19376
19495
|
askTimeoutMs = SEALED_ASK_TIMEOUT_MS;
|
|
19496
|
+
oauthTimeoutMs = SEALED_OAUTH_TIMEOUT_MS;
|
|
19377
19497
|
userOf = async () => void 0;
|
|
19378
19498
|
factsOf = async () => void 0;
|
|
19379
19499
|
constructor(hook, users, timeoutMs = SEALED_TIMEOUT_MS, tagOf = () => void 0) {
|
|
@@ -19494,7 +19614,7 @@ var Timestamps = class {
|
|
|
19494
19614
|
// src/sudoers.ts
|
|
19495
19615
|
var SUDOERS = "/etc/sudoers";
|
|
19496
19616
|
var SUDOERS_D = "/etc/sudoers.d";
|
|
19497
|
-
var
|
|
19617
|
+
var NAME4 = /^[a-z_][a-z0-9_.-]*$/;
|
|
19498
19618
|
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
19499
19619
|
var KERNEL_FORM = new RegExp(
|
|
19500
19620
|
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()]*)\)\s+)?(?:Cwd\s+(${WORD})\s+)?(?:Stdin\s+(\S+)\s+)?Cmnd(?:\s+(.*))?$`
|
|
@@ -19504,7 +19624,7 @@ var RUNAS = /^\(([^()]*)\)\s*/;
|
|
|
19504
19624
|
var TAG = /^([A-Z_]+)\s*:\s*/;
|
|
19505
19625
|
var OPTION = /^([A-Z_]+)=/;
|
|
19506
19626
|
var PLAIN2 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
19507
|
-
var
|
|
19627
|
+
var CONTROL2 = /[\p{Cc}\u2028\u2029]/u;
|
|
19508
19628
|
var CONTROLS = /[\p{Cc}\u2028\u2029]/gu;
|
|
19509
19629
|
var SHOWN_MAX = 60;
|
|
19510
19630
|
var KERNEL_SYNTAX = "[NOPASSWD] <user|%group|ALL> [(<target>)] [Cwd <dir>] [Stdin none] Cmnd <command\u2026|*>";
|
|
@@ -19513,7 +19633,7 @@ var EXPECTED = `expected '${KERNEL_SYNTAX}' or '${SUDOERS_SYNTAX}'`;
|
|
|
19513
19633
|
var TIMESTAMP_TIMEOUT = 5;
|
|
19514
19634
|
var TIMESTAMP_TYPE = "tty";
|
|
19515
19635
|
function hasControl(text) {
|
|
19516
|
-
return
|
|
19636
|
+
return CONTROL2.test(text);
|
|
19517
19637
|
}
|
|
19518
19638
|
function withoutControl(text) {
|
|
19519
19639
|
return text.replace(CONTROLS, (ch) => {
|
|
@@ -19651,7 +19771,7 @@ function commandText(cmnd) {
|
|
|
19651
19771
|
}
|
|
19652
19772
|
function validWho(who) {
|
|
19653
19773
|
if (who === "ALL") return true;
|
|
19654
|
-
return
|
|
19774
|
+
return NAME4.test(who.startsWith("%") ? who.slice(1) : who);
|
|
19655
19775
|
}
|
|
19656
19776
|
function whoError(who) {
|
|
19657
19777
|
if (validWho(who)) return void 0;
|
|
@@ -19684,7 +19804,7 @@ function kernelRules(m) {
|
|
|
19684
19804
|
const [, nopasswd, who = "", target = "root", dir, stdin, rest2 = ""] = m;
|
|
19685
19805
|
const bad = whoError(who);
|
|
19686
19806
|
if (bad !== void 0) return bad;
|
|
19687
|
-
if (target !== "ALL" && !
|
|
19807
|
+
if (target !== "ALL" && !NAME4.test(target)) return targetError(target);
|
|
19688
19808
|
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
19689
19809
|
if (cwd === "") return `Cwd expects one absolute directory, not ${shown(dir)}`;
|
|
19690
19810
|
if (stdin !== void 0 && stdin !== "none") return `Stdin takes none, not ${shown(stdin)}`;
|
|
@@ -19708,11 +19828,11 @@ function runasOf(list) {
|
|
|
19708
19828
|
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
19829
|
}
|
|
19710
19830
|
for (const name2 of names2) {
|
|
19711
|
-
if (name2 === "ALL" ||
|
|
19831
|
+
if (name2 === "ALL" || NAME4.test(name2)) continue;
|
|
19712
19832
|
return `expected user names or ALL to run as, not ${shown(name2)} (no %group, #uid or !user)`;
|
|
19713
19833
|
}
|
|
19714
19834
|
for (const group of groups) {
|
|
19715
|
-
if (group === "" || group === "ALL" ||
|
|
19835
|
+
if (group === "" || group === "ALL" || NAME4.test(group)) continue;
|
|
19716
19836
|
return `expected group names or ALL after ':' in (\u2026), not ${shown(group)}`;
|
|
19717
19837
|
}
|
|
19718
19838
|
return names2.includes("ALL") ? ["ALL"] : [...new Set(names2)];
|
|
@@ -19801,7 +19921,7 @@ function directiveError(text) {
|
|
|
19801
19921
|
}
|
|
19802
19922
|
function recordedBare(line, file, rule) {
|
|
19803
19923
|
if (rule.cmnd === "*" || rule.cmnd.args !== void 0 || !rule.nopasswd) return false;
|
|
19804
|
-
if (file !== `${SUDOERS_D}/${rule.who}` || !
|
|
19924
|
+
if (file !== `${SUDOERS_D}/${rule.who}` || !NAME4.test(rule.who) || !NAME4.test(rule.target)) {
|
|
19805
19925
|
return false;
|
|
19806
19926
|
}
|
|
19807
19927
|
const head = `NOPASSWD ${rule.who} (${rule.target}) `;
|
|
@@ -20501,7 +20621,7 @@ ${lines2}
|
|
|
20501
20621
|
async remember(self, target, cwd, argv) {
|
|
20502
20622
|
const { fs } = this.o;
|
|
20503
20623
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
20504
|
-
if (!
|
|
20624
|
+
if (!NAME4.test(self.name)) return false;
|
|
20505
20625
|
try {
|
|
20506
20626
|
await this.provision();
|
|
20507
20627
|
if (!await this.trusted(SUDOERS_D)) return false;
|
|
@@ -21870,8 +21990,8 @@ function sameCert(a, b) {
|
|
|
21870
21990
|
if (!a || !b) return a === b;
|
|
21871
21991
|
return a.cert.length === b.cert.length && a.cert.every((byte, i) => byte === b.cert[i]);
|
|
21872
21992
|
}
|
|
21873
|
-
function winner(current, expected,
|
|
21874
|
-
return sameCert(current, expected) ?
|
|
21993
|
+
function winner(current, expected, record3) {
|
|
21994
|
+
return sameCert(current, expected) ? record3 : current;
|
|
21875
21995
|
}
|
|
21876
21996
|
var DAY = 24 * 60 * 60 * 1e3;
|
|
21877
21997
|
var CA_LIFETIME = 3650 * DAY;
|
|
@@ -21904,15 +22024,15 @@ function indexedDbCaStore(dbName = "slicc-realm-ca") {
|
|
|
21904
22024
|
const store = (await open2()).transaction("ca").objectStore("ca");
|
|
21905
22025
|
return await request2(store.get(owner));
|
|
21906
22026
|
},
|
|
21907
|
-
async swap(owner, expected,
|
|
22027
|
+
async swap(owner, expected, record3) {
|
|
21908
22028
|
const tx = (await open2()).transaction("ca", "readwrite");
|
|
21909
22029
|
const store = tx.objectStore("ca");
|
|
21910
|
-
let stored2 =
|
|
22030
|
+
let stored2 = record3;
|
|
21911
22031
|
const read = store.get(owner);
|
|
21912
22032
|
read.onsuccess = () => {
|
|
21913
22033
|
const current = read.result;
|
|
21914
|
-
const kept = winner(current, expected,
|
|
21915
|
-
if (kept ===
|
|
22034
|
+
const kept = winner(current, expected, record3);
|
|
22035
|
+
if (kept === record3) store.put(record3, owner);
|
|
21916
22036
|
else stored2 = kept;
|
|
21917
22037
|
};
|
|
21918
22038
|
await new Promise((resolve2, reject) => {
|
|
@@ -21932,14 +22052,14 @@ function validLeafName(host) {
|
|
|
21932
22052
|
}
|
|
21933
22053
|
var RealmCa = class _RealmCa {
|
|
21934
22054
|
record;
|
|
21935
|
-
constructor(
|
|
21936
|
-
this.record =
|
|
22055
|
+
constructor(record3) {
|
|
22056
|
+
this.record = record3;
|
|
21937
22057
|
}
|
|
21938
22058
|
static async open(owner, store, now = Date.now()) {
|
|
21939
22059
|
const stored2 = await store.get(owner).catch(() => void 0);
|
|
21940
22060
|
if (stored2 && stored2.notAfter - now > CA_RENEW_BEFORE) return new _RealmCa(stored2);
|
|
21941
|
-
const
|
|
21942
|
-
return new _RealmCa(await store.swap(owner, stored2,
|
|
22061
|
+
const record3 = await _RealmCa.create(owner, now);
|
|
22062
|
+
return new _RealmCa(await store.swap(owner, stored2, record3));
|
|
21943
22063
|
}
|
|
21944
22064
|
static async create(owner, now) {
|
|
21945
22065
|
const pair = await crypto.subtle.generateKey(ECDSA, false, ["sign", "verify"]);
|
|
@@ -22166,8 +22286,8 @@ function memoryCaStore() {
|
|
|
22166
22286
|
const records = /* @__PURE__ */ new Map();
|
|
22167
22287
|
return {
|
|
22168
22288
|
get: async (owner) => records.get(owner),
|
|
22169
|
-
swap: async (owner, expected,
|
|
22170
|
-
const kept = winner(records.get(owner), expected,
|
|
22289
|
+
swap: async (owner, expected, record3) => {
|
|
22290
|
+
const kept = winner(records.get(owner), expected, record3);
|
|
22171
22291
|
records.set(owner, kept);
|
|
22172
22292
|
return kept;
|
|
22173
22293
|
}
|
|
@@ -30416,7 +30536,7 @@ function header2(id2, flags2, counts) {
|
|
|
30416
30536
|
function opt() {
|
|
30417
30537
|
return [0, 0, TYPE_OPT, UDP_EDNS >> 8, UDP_EDNS & 255, 0, 0, 0, 0, 0, 0];
|
|
30418
30538
|
}
|
|
30419
|
-
function
|
|
30539
|
+
function record2(type, rdata) {
|
|
30420
30540
|
const ttl = DNS_STUB_TTL;
|
|
30421
30541
|
return [
|
|
30422
30542
|
192,
|
|
@@ -30524,14 +30644,14 @@ var DnsStub = class {
|
|
|
30524
30644
|
const address = reverseAddress(q.name);
|
|
30525
30645
|
const name2 = address !== void 0 ? await this.reverse(address) : void 0;
|
|
30526
30646
|
if (name2 !== void 0)
|
|
30527
|
-
return answerReply(query, q, NOERROR, [
|
|
30647
|
+
return answerReply(query, q, NOERROR, [record2(TYPE_PTR, encodeName(name2))], true);
|
|
30528
30648
|
return this.forward(query, q);
|
|
30529
30649
|
}
|
|
30530
30650
|
if (q.type === TYPE_A || q.type === TYPE_AAAA) {
|
|
30531
30651
|
const addresses = q.name === "" ? [] : await this.lookup(q.name);
|
|
30532
30652
|
const answers2 = addresses.flatMap((a) => {
|
|
30533
30653
|
const data = addressData(a, q.type);
|
|
30534
|
-
return data ? [
|
|
30654
|
+
return data ? [record2(q.type, data)] : [];
|
|
30535
30655
|
});
|
|
30536
30656
|
if (answers2.length > 0 || local(q.name) || await this.known(q.name)) {
|
|
30537
30657
|
const rcode = addresses.length > 0 ? NOERROR : NXDOMAIN;
|
|
@@ -34516,8 +34636,8 @@ var Launcher = class {
|
|
|
34516
34636
|
const caller = this.jobs.shown(ppid);
|
|
34517
34637
|
const named = typeof req.argv0 === "string" && !planned.script && !planned.target.fixed;
|
|
34518
34638
|
const argv = named ? [req.argv0, ...req.argv.slice(1)] : req.argv;
|
|
34519
|
-
const
|
|
34520
|
-
if (!
|
|
34639
|
+
const exact2 = booked?.pid === caller && req.file === booked.path && await physicalPathAsync(this.base, req.cwd) === booked.cwd && await argvDigest(argv) === booked.argv;
|
|
34640
|
+
if (!exact2) throw new SpawnError("EACCES");
|
|
34521
34641
|
const { requested: path, requestedCwd: cwd, path: resolved2 } = booked;
|
|
34522
34642
|
const pid = this.nextPid++;
|
|
34523
34643
|
const ids = { pid: req.exec ? caller : pid, ppid: caller };
|
|
@@ -35880,9 +36000,9 @@ var Launcher = class {
|
|
|
35880
36000
|
}
|
|
35881
36001
|
pnpmReady() {
|
|
35882
36002
|
if (this.pnpmMade !== void 0) return this.pnpmMade;
|
|
35883
|
-
const
|
|
36003
|
+
const epoch2 = this.pnpmEpoch;
|
|
35884
36004
|
const made2 = this.base.mkdir(this.pnpmHome, { recursive: true }).then(() => this.owners ? this.stampLayout() : void 0).catch(() => {
|
|
35885
|
-
if (this.pnpmEpoch ===
|
|
36005
|
+
if (this.pnpmEpoch === epoch2) this.pnpmMade = void 0;
|
|
35886
36006
|
});
|
|
35887
36007
|
this.pnpmMade = made2;
|
|
35888
36008
|
return made2;
|