@joe-broadhead/messaging-bin-linux-arm64-gnu 0.1.0 → 0.1.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/bin/messagingd +1 -1
- package/lib/messagingd.mjs +585 -108
- package/package.json +1 -1
package/bin/messagingd
CHANGED
package/lib/messagingd.mjs
CHANGED
|
@@ -6756,7 +6756,9 @@ var init_ipc = __esm(() => {
|
|
|
6756
6756
|
SessionKey = string2().min(1).max(200);
|
|
6757
6757
|
SessionHost = strictObject({
|
|
6758
6758
|
kind: literal("opencode"),
|
|
6759
|
-
location: string2().min(2).max(1024).refine((path) => path.startsWith("/") && !/[\u0000-\u001f\u007f]/.test(path), {
|
|
6759
|
+
location: string2().min(2).max(1024).refine((path) => (path.startsWith("/") || /^[A-Za-z]:[\\/]./s.test(path)) && !/[\u0000-\u001f\u007f]/.test(path), {
|
|
6760
|
+
message: "an absolute path without control characters"
|
|
6761
|
+
}),
|
|
6760
6762
|
sessionID: string2().min(1).max(200),
|
|
6761
6763
|
pid: number2().int().min(1).max(2147483647)
|
|
6762
6764
|
});
|
|
@@ -7218,7 +7220,7 @@ var init_b64u = __esm(() => {
|
|
|
7218
7220
|
});
|
|
7219
7221
|
|
|
7220
7222
|
// packages/core/dist/version.js
|
|
7221
|
-
var VERSION = "0.1.
|
|
7223
|
+
var VERSION = "0.1.1";
|
|
7222
7224
|
|
|
7223
7225
|
// packages/core/dist/jcs.js
|
|
7224
7226
|
function hasLoneSurrogate(text) {
|
|
@@ -10237,19 +10239,21 @@ function messagingHome(env = process.env) {
|
|
|
10237
10239
|
return configured ? resolve(configured) : join(homedir(), ".messaging");
|
|
10238
10240
|
}
|
|
10239
10241
|
function socketPath(home, tier) {
|
|
10240
|
-
return join(home, "run", `${tier}
|
|
10242
|
+
return join(home, "run", `${tier}.${IS_WINDOWS ? "pipe" : "sock"}`);
|
|
10241
10243
|
}
|
|
10242
|
-
function configuredDaemonUid(env = process.env) {
|
|
10244
|
+
function configuredDaemonUid(env = process.env, windows = IS_WINDOWS) {
|
|
10243
10245
|
const raw = env.MESSAGING_DAEMON_UID;
|
|
10244
10246
|
if (raw === undefined || raw === "")
|
|
10245
10247
|
return;
|
|
10248
|
+
if (windows)
|
|
10249
|
+
throw new MessagingError("invalid_request", "MESSAGING_DAEMON_UID is not supported on Windows: messagingd runs as the user of its clients there");
|
|
10246
10250
|
if (!/^\d{1,10}$/.test(raw) || Number(raw) > 4294967294)
|
|
10247
10251
|
throw new MessagingError("invalid_request", "MESSAGING_DAEMON_UID must be a numeric uid");
|
|
10248
10252
|
return Number(raw);
|
|
10249
10253
|
}
|
|
10250
|
-
function daemonEnv(env, home) {
|
|
10254
|
+
function daemonEnv(env, home, windows = IS_WINDOWS) {
|
|
10251
10255
|
const out = {};
|
|
10252
|
-
for (const name of DAEMON_ENV) {
|
|
10256
|
+
for (const name of windows ? [...DAEMON_ENV, ...DAEMON_ENV_WINDOWS] : DAEMON_ENV) {
|
|
10253
10257
|
const value = env[name];
|
|
10254
10258
|
if (value !== undefined)
|
|
10255
10259
|
out[name] = value;
|
|
@@ -10257,9 +10261,10 @@ function daemonEnv(env, home) {
|
|
|
10257
10261
|
out.MESSAGING_HOME = home;
|
|
10258
10262
|
return out;
|
|
10259
10263
|
}
|
|
10260
|
-
var MAX_SOCKET_PATH_BYTES = 103, DAEMON_ENV;
|
|
10264
|
+
var MAX_SOCKET_PATH_BYTES = 103, IS_WINDOWS, DAEMON_ENV, DAEMON_ENV_WINDOWS;
|
|
10261
10265
|
var init_paths = __esm(() => {
|
|
10262
10266
|
init_dist();
|
|
10267
|
+
IS_WINDOWS = process.platform === "win32";
|
|
10263
10268
|
DAEMON_ENV = [
|
|
10264
10269
|
"PATH",
|
|
10265
10270
|
"HOME",
|
|
@@ -10285,6 +10290,74 @@ var init_paths = __esm(() => {
|
|
|
10285
10290
|
"MESSAGING_LOG_LEVEL",
|
|
10286
10291
|
"MESSAGING_IDENTITY_STORE"
|
|
10287
10292
|
];
|
|
10293
|
+
DAEMON_ENV_WINDOWS = [
|
|
10294
|
+
"SystemRoot",
|
|
10295
|
+
"SystemDrive",
|
|
10296
|
+
"windir",
|
|
10297
|
+
"ComSpec",
|
|
10298
|
+
"PATHEXT",
|
|
10299
|
+
"USERPROFILE",
|
|
10300
|
+
"USERNAME",
|
|
10301
|
+
"USERDOMAIN",
|
|
10302
|
+
"HOMEDRIVE",
|
|
10303
|
+
"HOMEPATH",
|
|
10304
|
+
"APPDATA",
|
|
10305
|
+
"LOCALAPPDATA",
|
|
10306
|
+
"ProgramData",
|
|
10307
|
+
"TEMP",
|
|
10308
|
+
"TMP",
|
|
10309
|
+
"NUMBER_OF_PROCESSORS",
|
|
10310
|
+
"PROCESSOR_ARCHITECTURE"
|
|
10311
|
+
];
|
|
10312
|
+
});
|
|
10313
|
+
|
|
10314
|
+
// packages/ipc/dist/pipes.js
|
|
10315
|
+
import { randomBytes as randomBytes5 } from "crypto";
|
|
10316
|
+
import { readFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
10317
|
+
function newPipeName(tier) {
|
|
10318
|
+
return `\\\\.\\pipe\\messaging-${randomBytes5(16).toString("hex")}-${tier}`;
|
|
10319
|
+
}
|
|
10320
|
+
function writePointer(path, pointer) {
|
|
10321
|
+
const temp = `${path}.${process.pid}.${randomBytes5(4).toString("hex")}.tmp`;
|
|
10322
|
+
try {
|
|
10323
|
+
writeFileSync(temp, `${JSON.stringify(pointer)}
|
|
10324
|
+
`, { flag: "wx" });
|
|
10325
|
+
renameSync(temp, path);
|
|
10326
|
+
} catch (error) {
|
|
10327
|
+
rmSync(temp, { force: true });
|
|
10328
|
+
throw error;
|
|
10329
|
+
}
|
|
10330
|
+
}
|
|
10331
|
+
function readPointer(path) {
|
|
10332
|
+
let text;
|
|
10333
|
+
try {
|
|
10334
|
+
const bytes = readFileSync(path);
|
|
10335
|
+
if (bytes.length > POINTER_BYTES)
|
|
10336
|
+
throw new MessagingError("forbidden", "the Messaging daemon's pipe file is too large");
|
|
10337
|
+
text = bytes.toString("utf8");
|
|
10338
|
+
} catch (error) {
|
|
10339
|
+
if (error instanceof MessagingError)
|
|
10340
|
+
throw error;
|
|
10341
|
+
if (error.code === "ENOENT")
|
|
10342
|
+
throw new MessagingError("daemon_unavailable", "the Messaging daemon's pipe file does not exist");
|
|
10343
|
+
throw new MessagingError("forbidden", "cannot read the Messaging daemon's pipe file");
|
|
10344
|
+
}
|
|
10345
|
+
let value;
|
|
10346
|
+
try {
|
|
10347
|
+
value = parseWire(text);
|
|
10348
|
+
} catch {
|
|
10349
|
+
throw new MessagingError("forbidden", "the Messaging daemon's pipe file is not valid JSON");
|
|
10350
|
+
}
|
|
10351
|
+
const { pipe, pid, ...rest } = typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
10352
|
+
if (typeof pipe !== "string" || !PIPE_NAME.test(pipe) || typeof pid !== "number" || !Number.isSafeInteger(pid) || pid < 1 || Object.keys(rest).length > 0) {
|
|
10353
|
+
throw new MessagingError("forbidden", "the Messaging daemon's pipe file does not name a Messaging pipe");
|
|
10354
|
+
}
|
|
10355
|
+
return { pipe, pid };
|
|
10356
|
+
}
|
|
10357
|
+
var PIPE_NAME, POINTER_BYTES = 1024;
|
|
10358
|
+
var init_pipes = __esm(() => {
|
|
10359
|
+
init_dist();
|
|
10360
|
+
PIPE_NAME = /^\\\\\.\\pipe\\messaging-[0-9a-f]{32}-(?:agent|admin)$/;
|
|
10288
10361
|
});
|
|
10289
10362
|
|
|
10290
10363
|
// packages/ipc/dist/rpc.js
|
|
@@ -10299,8 +10372,227 @@ var init_rpc = __esm(() => {
|
|
|
10299
10372
|
};
|
|
10300
10373
|
});
|
|
10301
10374
|
|
|
10375
|
+
// packages/ipc/dist/windows-acl.js
|
|
10376
|
+
import { spawnSync } from "child_process";
|
|
10377
|
+
import { randomBytes as randomBytes6 } from "crypto";
|
|
10378
|
+
import { existsSync, readFileSync as readFileSync2, rmSync as rmSync2 } from "fs";
|
|
10379
|
+
import { tmpdir } from "os";
|
|
10380
|
+
import { join as join2 } from "path";
|
|
10381
|
+
function parseSddlDacl(sddl) {
|
|
10382
|
+
const text = sddl.trim();
|
|
10383
|
+
let i = 0;
|
|
10384
|
+
let dacl;
|
|
10385
|
+
while (i < text.length) {
|
|
10386
|
+
const tag = text[i];
|
|
10387
|
+
if (text[i + 1] !== ":" || tag !== "O" && tag !== "G" && tag !== "D" && tag !== "S")
|
|
10388
|
+
throw new Error("not SDDL");
|
|
10389
|
+
i += 2;
|
|
10390
|
+
if (tag === "O" || tag === "G") {
|
|
10391
|
+
const sid = /^(S-1-[0-9-]+|[A-Z]{2})/.exec(text.slice(i));
|
|
10392
|
+
if (!sid)
|
|
10393
|
+
throw new Error("not SDDL: owner or group");
|
|
10394
|
+
i += sid[0].length;
|
|
10395
|
+
continue;
|
|
10396
|
+
}
|
|
10397
|
+
let flagText = /^[A-Z_]*/.exec(text.slice(i))[0];
|
|
10398
|
+
if (text[i + flagText.length] === ":")
|
|
10399
|
+
flagText = flagText.slice(0, -1);
|
|
10400
|
+
i += flagText.length;
|
|
10401
|
+
const aces = [];
|
|
10402
|
+
while (text[i] === "(") {
|
|
10403
|
+
let depth = 0;
|
|
10404
|
+
let end = i;
|
|
10405
|
+
for (;end < text.length; end++) {
|
|
10406
|
+
if (text[end] === "(")
|
|
10407
|
+
depth++;
|
|
10408
|
+
else if (text[end] === ")" && --depth === 0)
|
|
10409
|
+
break;
|
|
10410
|
+
}
|
|
10411
|
+
if (end >= text.length)
|
|
10412
|
+
throw new Error("not SDDL: an unclosed entry");
|
|
10413
|
+
aces.push(parseAce(text.slice(i + 1, end)));
|
|
10414
|
+
i = end + 1;
|
|
10415
|
+
}
|
|
10416
|
+
if (tag === "D")
|
|
10417
|
+
dacl = { nullDacl: flagText.includes("NO_ACCESS_CONTROL"), protected: flagText.replace("NO_ACCESS_CONTROL", "").includes("P"), aces };
|
|
10418
|
+
}
|
|
10419
|
+
return dacl;
|
|
10420
|
+
}
|
|
10421
|
+
function parseAce(body) {
|
|
10422
|
+
const fields = body.split(";");
|
|
10423
|
+
if (fields.length < 6)
|
|
10424
|
+
throw new Error("not SDDL: an entry");
|
|
10425
|
+
const [type = "", flagText = "", rightsText = "", , , sidText = ""] = fields;
|
|
10426
|
+
const flags = flagText.match(/.{1,2}/g) ?? [];
|
|
10427
|
+
return { type, flags, rights: parseRights(rightsText), sid: ALIASES[sidText] ?? sidText };
|
|
10428
|
+
}
|
|
10429
|
+
function parseRights(text) {
|
|
10430
|
+
if (/^0[xX][0-9a-fA-F]+$/.test(text))
|
|
10431
|
+
return Number.parseInt(text.slice(2), 16);
|
|
10432
|
+
if (/^\d+$/.test(text))
|
|
10433
|
+
return Number(text);
|
|
10434
|
+
let mask = 0;
|
|
10435
|
+
for (const code of text.match(/.{1,2}/g) ?? [])
|
|
10436
|
+
mask |= RIGHTS[code] ?? 4294967295;
|
|
10437
|
+
return mask >>> 0;
|
|
10438
|
+
}
|
|
10439
|
+
function resolveSid(sid, self) {
|
|
10440
|
+
const rid = DOMAIN_RIDS[sid];
|
|
10441
|
+
const domain = /^(S-1-5-21-\d+-\d+-\d+)-\d+$/.exec(self)?.[1];
|
|
10442
|
+
return rid !== undefined && domain !== undefined ? `${domain}-${rid}` : sid;
|
|
10443
|
+
}
|
|
10444
|
+
function applies(ace) {
|
|
10445
|
+
return !ace.flags.includes("IO");
|
|
10446
|
+
}
|
|
10447
|
+
function daclProblem(dacl, self, { pinnedOwner }) {
|
|
10448
|
+
if (dacl === undefined || dacl.nullDacl)
|
|
10449
|
+
return "has no access control list, so anyone may write it";
|
|
10450
|
+
const trusted = new Set([self, SID_SYSTEM, SID_ADMINISTRATORS]);
|
|
10451
|
+
let ownerPinned = false;
|
|
10452
|
+
for (const ace of dacl.aces) {
|
|
10453
|
+
if (!ALLOW_TYPES.has(ace.type) || !applies(ace))
|
|
10454
|
+
continue;
|
|
10455
|
+
const writes = (ace.rights & WRITE_RIGHTS) !== 0;
|
|
10456
|
+
const sid = resolveSid(ace.sid, self);
|
|
10457
|
+
if (sid === SID_OWNER_RIGHTS) {
|
|
10458
|
+
if (writes)
|
|
10459
|
+
return "lets its owner write it";
|
|
10460
|
+
ownerPinned = true;
|
|
10461
|
+
continue;
|
|
10462
|
+
}
|
|
10463
|
+
if (writes && !trusted.has(sid))
|
|
10464
|
+
return `is writable by ${/^S-1-[0-9-]+$/.test(sid) ? sid : `another principal (${sid.slice(0, 8)})`}`;
|
|
10465
|
+
}
|
|
10466
|
+
if (pinnedOwner && !ownerPinned)
|
|
10467
|
+
return "does not pin its owner's rights (no OWNER RIGHTS entry)";
|
|
10468
|
+
return;
|
|
10469
|
+
}
|
|
10470
|
+
function system32(exe) {
|
|
10471
|
+
return join2(process.env.SystemRoot || process.env.windir || "C:\\Windows", "System32", exe);
|
|
10472
|
+
}
|
|
10473
|
+
function run(exe, args) {
|
|
10474
|
+
const result = spawnSync(system32(exe), args, { encoding: "utf8", windowsHide: true, timeout: 15000 });
|
|
10475
|
+
if (result.error)
|
|
10476
|
+
throw new ToolFailed(exe, null, result.error.code ?? "error");
|
|
10477
|
+
if (result.status !== 0)
|
|
10478
|
+
throw new ToolFailed(exe, result.status, `exit ${result.status}`);
|
|
10479
|
+
return result.stdout;
|
|
10480
|
+
}
|
|
10481
|
+
function currentUserSid() {
|
|
10482
|
+
if (userSid !== undefined)
|
|
10483
|
+
return userSid;
|
|
10484
|
+
const out = run("whoami.exe", ["/user", "/fo", "csv", "/nh"]);
|
|
10485
|
+
const sid = /"(S-1-[0-9-]+)"\s*$/.exec(out.trim())?.[1];
|
|
10486
|
+
if (!sid)
|
|
10487
|
+
throw new MessagingError("forbidden", "cannot tell this user's SID");
|
|
10488
|
+
userSid = sid;
|
|
10489
|
+
return sid;
|
|
10490
|
+
}
|
|
10491
|
+
function readDacl(path) {
|
|
10492
|
+
const out = join2(tmpdir(), `messaging-acl-${process.pid}-${randomBytes6(8).toString("hex")}.txt`);
|
|
10493
|
+
try {
|
|
10494
|
+
run("icacls.exe", [path, "/save", out, "/q"]);
|
|
10495
|
+
return parseSddlDacl(sddlLine(readFileSync2(out)));
|
|
10496
|
+
} catch (error) {
|
|
10497
|
+
if (error instanceof ToolFailed && (error.status === 2 || error.status === 3 || !existsSync(path))) {
|
|
10498
|
+
throw new MessagingError("daemon_unavailable", `${path} does not exist`);
|
|
10499
|
+
}
|
|
10500
|
+
if (error instanceof MessagingError)
|
|
10501
|
+
throw error;
|
|
10502
|
+
throw new MessagingError("forbidden", "cannot read an access control list");
|
|
10503
|
+
} finally {
|
|
10504
|
+
rmSync2(out, { force: true });
|
|
10505
|
+
}
|
|
10506
|
+
}
|
|
10507
|
+
function sddlLine(bytes) {
|
|
10508
|
+
const utf16 = bytes.length >= 2 && (bytes[0] === 255 && bytes[1] === 254 ? true : bytes.includes(0));
|
|
10509
|
+
const text = (utf16 ? bytes.toString("utf16le") : bytes.toString("utf8")).replace(/^\uFEFF/, "");
|
|
10510
|
+
const line = text.split(/\r?\n/).find((l) => /^(?:[OGDS]:)/.test(l.trim()));
|
|
10511
|
+
if (line === undefined)
|
|
10512
|
+
throw new MessagingError("forbidden", "cannot read an access control list");
|
|
10513
|
+
return line.trim();
|
|
10514
|
+
}
|
|
10515
|
+
function aclProblem(path, options) {
|
|
10516
|
+
return daclProblem(readDacl(path), currentUserSid(), options);
|
|
10517
|
+
}
|
|
10518
|
+
function securePrivate(path, what) {
|
|
10519
|
+
const self = currentUserSid();
|
|
10520
|
+
let others;
|
|
10521
|
+
try {
|
|
10522
|
+
others = [...new Set((readDacl(path)?.aces ?? []).map((ace) => resolveSid(ace.sid, self)))].filter((sid) => sid !== self && sid !== SID_OWNER_RIGHTS && /^S-1-[0-9-]+$/.test(sid));
|
|
10523
|
+
run("icacls.exe", [path, "/inheritance:r", "/grant:r", `*${self}:(OI)(CI)(F)`, `*${SID_OWNER_RIGHTS}:(OI)(CI)(RC)`, "/q"]);
|
|
10524
|
+
if (others.length > 0)
|
|
10525
|
+
run("icacls.exe", [path, "/remove", ...others.map((sid) => `*${sid}`), "/q"]);
|
|
10526
|
+
} catch (error) {
|
|
10527
|
+
throw new MessagingError("forbidden", `cannot make ${what} private: ${error instanceof Error ? error.message : "icacls failed"}`);
|
|
10528
|
+
}
|
|
10529
|
+
const dacl = readDacl(path);
|
|
10530
|
+
const problem = daclProblem(dacl, self, { pinnedOwner: true });
|
|
10531
|
+
if (problem !== undefined)
|
|
10532
|
+
throw new MessagingError("forbidden", `${what} is not private: it ${problem}`);
|
|
10533
|
+
const strangers = (dacl?.aces ?? []).map((ace) => resolveSid(ace.sid, self)).filter((sid) => sid !== self && sid !== SID_OWNER_RIGHTS);
|
|
10534
|
+
if (strangers.length > 0)
|
|
10535
|
+
throw new MessagingError("forbidden", `${what} is not private: other entries remain in its access control list`);
|
|
10536
|
+
}
|
|
10537
|
+
var SID_SYSTEM = "S-1-5-18", SID_ADMINISTRATORS = "S-1-5-32-544", SID_OWNER_RIGHTS = "S-1-3-4", ALIASES, RIGHTS, WRITE_RIGHTS, ALLOW_TYPES, DOMAIN_RIDS, ToolFailed, userSid;
|
|
10538
|
+
var init_windows_acl = __esm(() => {
|
|
10539
|
+
init_dist();
|
|
10540
|
+
ALIASES = {
|
|
10541
|
+
SY: SID_SYSTEM,
|
|
10542
|
+
BA: SID_ADMINISTRATORS,
|
|
10543
|
+
OW: SID_OWNER_RIGHTS,
|
|
10544
|
+
CO: "S-1-3-0",
|
|
10545
|
+
WD: "S-1-1-0",
|
|
10546
|
+
AU: "S-1-5-11",
|
|
10547
|
+
BU: "S-1-5-32-545",
|
|
10548
|
+
AN: "S-1-5-7",
|
|
10549
|
+
NU: "S-1-5-2",
|
|
10550
|
+
IU: "S-1-5-4"
|
|
10551
|
+
};
|
|
10552
|
+
RIGHTS = {
|
|
10553
|
+
GA: 268435456,
|
|
10554
|
+
GR: 2147483648,
|
|
10555
|
+
GW: 1073741824,
|
|
10556
|
+
GX: 536870912,
|
|
10557
|
+
RC: 131072,
|
|
10558
|
+
SD: 65536,
|
|
10559
|
+
WD: 262144,
|
|
10560
|
+
WO: 524288,
|
|
10561
|
+
RP: 16,
|
|
10562
|
+
WP: 32,
|
|
10563
|
+
CC: 1,
|
|
10564
|
+
DC: 2,
|
|
10565
|
+
LC: 4,
|
|
10566
|
+
SW: 8,
|
|
10567
|
+
LO: 128,
|
|
10568
|
+
DT: 64,
|
|
10569
|
+
CR: 256,
|
|
10570
|
+
FA: 2032127,
|
|
10571
|
+
FR: 1179785,
|
|
10572
|
+
FW: 1179926,
|
|
10573
|
+
FX: 1179808,
|
|
10574
|
+
KA: 983103,
|
|
10575
|
+
KR: 131097,
|
|
10576
|
+
KW: 131078,
|
|
10577
|
+
KX: 131097,
|
|
10578
|
+
NR: 0,
|
|
10579
|
+
NW: 0,
|
|
10580
|
+
NX: 0
|
|
10581
|
+
};
|
|
10582
|
+
WRITE_RIGHTS = 2 | 4 | 16 | 64 | 256 | 65536 | 262144 | 524288 | 1073741824 | 268435456;
|
|
10583
|
+
ALLOW_TYPES = new Set(["A", "OA", "XA", "ZA"]);
|
|
10584
|
+
DOMAIN_RIDS = { LA: 500, LG: 501 };
|
|
10585
|
+
ToolFailed = class ToolFailed extends MessagingError {
|
|
10586
|
+
status;
|
|
10587
|
+
constructor(exe, status, why) {
|
|
10588
|
+
super("forbidden", `${exe} failed (${why})`);
|
|
10589
|
+
this.status = status;
|
|
10590
|
+
}
|
|
10591
|
+
};
|
|
10592
|
+
});
|
|
10593
|
+
|
|
10302
10594
|
// packages/ipc/dist/trust.js
|
|
10303
|
-
import { lstatSync, mkdirSync } from "fs";
|
|
10595
|
+
import { constants, lstatSync, mkdirSync, openSync } from "fs";
|
|
10304
10596
|
function checkPrivateDir(path, what, owners = selfOnly()) {
|
|
10305
10597
|
let stats;
|
|
10306
10598
|
try {
|
|
@@ -10310,19 +10602,51 @@ function checkPrivateDir(path, what, owners = selfOnly()) {
|
|
|
10310
10602
|
throw new MessagingError("daemon_unavailable", `${what} does not exist`);
|
|
10311
10603
|
throw new MessagingError("forbidden", `cannot inspect ${what}`);
|
|
10312
10604
|
}
|
|
10313
|
-
const problem = privacyProblem(stats, owners);
|
|
10605
|
+
const problem = IS_WINDOWS ? windowsProblem(stats, path, "directory") : privacyProblem(stats, owners);
|
|
10314
10606
|
if (problem !== undefined)
|
|
10315
10607
|
throw new MessagingError("forbidden", `${what} is not private: it ${problem}`);
|
|
10316
10608
|
}
|
|
10317
10609
|
function ensurePrivateDir(path, what) {
|
|
10610
|
+
let created = false;
|
|
10318
10611
|
try {
|
|
10319
10612
|
mkdirSync(path, { mode: 448 });
|
|
10613
|
+
created = true;
|
|
10320
10614
|
} catch (error) {
|
|
10321
10615
|
if (error.code !== "EEXIST")
|
|
10322
10616
|
throw new MessagingError("forbidden", `cannot create ${what}`);
|
|
10323
10617
|
}
|
|
10618
|
+
if (IS_WINDOWS && created)
|
|
10619
|
+
secureCreated(path, what);
|
|
10324
10620
|
checkPrivateDir(path, what);
|
|
10325
10621
|
}
|
|
10622
|
+
function secureCreated(path, what) {
|
|
10623
|
+
if (aclProblem(path, { pinnedOwner: true }) !== undefined)
|
|
10624
|
+
securePrivate(path, what);
|
|
10625
|
+
}
|
|
10626
|
+
function adoptPrivateDir(path, what, created) {
|
|
10627
|
+
if (created) {
|
|
10628
|
+
secureCreated(path, what);
|
|
10629
|
+
return;
|
|
10630
|
+
}
|
|
10631
|
+
let stats;
|
|
10632
|
+
try {
|
|
10633
|
+
stats = lstatSync(path);
|
|
10634
|
+
} catch {
|
|
10635
|
+
throw new MessagingError("forbidden", `cannot inspect ${what}`);
|
|
10636
|
+
}
|
|
10637
|
+
if (stats.isSymbolicLink())
|
|
10638
|
+
throw new MessagingError("forbidden", `${what} is not private: it is a symbolic link`);
|
|
10639
|
+
if (!stats.isDirectory())
|
|
10640
|
+
throw new MessagingError("forbidden", `${what} is not private: it is not a directory`);
|
|
10641
|
+
const self = currentUserSid();
|
|
10642
|
+
const dacl = readDacl(path);
|
|
10643
|
+
const problem = daclProblem(dacl, self, { pinnedOwner: false });
|
|
10644
|
+
if (problem !== undefined)
|
|
10645
|
+
throw new MessagingError("forbidden", `${what} is not private: it ${problem}`);
|
|
10646
|
+
const exact = daclProblem(dacl, self, { pinnedOwner: true }) === undefined && (dacl?.aces ?? []).every((ace) => [self, SID_OWNER_RIGHTS].includes(resolveSid(ace.sid, self)));
|
|
10647
|
+
if (!exact)
|
|
10648
|
+
securePrivate(path, what);
|
|
10649
|
+
}
|
|
10326
10650
|
function privacyProblem(stats, owners = selfOnly()) {
|
|
10327
10651
|
if (stats.isSymbolicLink())
|
|
10328
10652
|
return "is a symbolic link";
|
|
@@ -10334,6 +10658,13 @@ function privacyProblem(stats, owners = selfOnly()) {
|
|
|
10334
10658
|
return "is writable by group or others";
|
|
10335
10659
|
return;
|
|
10336
10660
|
}
|
|
10661
|
+
function windowsProblem(stats, path, kind) {
|
|
10662
|
+
if (stats.isSymbolicLink())
|
|
10663
|
+
return "is a symbolic link";
|
|
10664
|
+
if (kind === "directory" ? !stats.isDirectory() : !stats.isFile())
|
|
10665
|
+
return `is not a ${kind}`;
|
|
10666
|
+
return aclProblem(path, { pinnedOwner: true });
|
|
10667
|
+
}
|
|
10337
10668
|
function checkSocket(path, owners = selfOnly()) {
|
|
10338
10669
|
let stats;
|
|
10339
10670
|
try {
|
|
@@ -10343,6 +10674,12 @@ function checkSocket(path, owners = selfOnly()) {
|
|
|
10343
10674
|
throw new MessagingError("daemon_unavailable", "the Messaging daemon socket does not exist");
|
|
10344
10675
|
throw new MessagingError("forbidden", "cannot inspect the Messaging daemon socket");
|
|
10345
10676
|
}
|
|
10677
|
+
if (IS_WINDOWS) {
|
|
10678
|
+
const problem = windowsProblem(stats, path, "file");
|
|
10679
|
+
if (problem !== undefined)
|
|
10680
|
+
throw new MessagingError("forbidden", `the Messaging daemon's pipe file is not private: it ${problem}`);
|
|
10681
|
+
return;
|
|
10682
|
+
}
|
|
10346
10683
|
if (!stats.isSocket())
|
|
10347
10684
|
throw new MessagingError("forbidden", "the Messaging daemon socket path is not a socket");
|
|
10348
10685
|
if (owners.length > 0 && !owners.includes(stats.uid))
|
|
@@ -10358,8 +10695,24 @@ function selfOnly() {
|
|
|
10358
10695
|
const euid = process.geteuid?.();
|
|
10359
10696
|
return euid === undefined ? [] : [euid];
|
|
10360
10697
|
}
|
|
10698
|
+
function openNoFollow(path, flags, mode) {
|
|
10699
|
+
if (!IS_WINDOWS)
|
|
10700
|
+
return openSync(path, flags | constants.O_NOFOLLOW, mode);
|
|
10701
|
+
let link = false;
|
|
10702
|
+
try {
|
|
10703
|
+
link = lstatSync(path).isSymbolicLink();
|
|
10704
|
+
} catch (error) {
|
|
10705
|
+
if (error.code !== "ENOENT")
|
|
10706
|
+
throw error;
|
|
10707
|
+
}
|
|
10708
|
+
if (link)
|
|
10709
|
+
throw Object.assign(new Error(`ELOOP: a symbolic link, open '${path}'`), { code: "ELOOP" });
|
|
10710
|
+
return openSync(path, flags, mode);
|
|
10711
|
+
}
|
|
10361
10712
|
var init_trust = __esm(() => {
|
|
10362
10713
|
init_dist();
|
|
10714
|
+
init_paths();
|
|
10715
|
+
init_windows_acl();
|
|
10363
10716
|
});
|
|
10364
10717
|
|
|
10365
10718
|
// packages/ipc/dist/client.js
|
|
@@ -10406,16 +10759,21 @@ class MessagingClient {
|
|
|
10406
10759
|
static async connect(options = {}) {
|
|
10407
10760
|
const path = options.socketPath ?? socketPath(options.home ?? messagingHome(), options.tier ?? "agent");
|
|
10408
10761
|
const owners = trustedOwners(options.daemonUid ?? configuredDaemonUid());
|
|
10762
|
+
let pointer;
|
|
10409
10763
|
try {
|
|
10410
10764
|
checkPrivateDir(dirname(path), "the Messaging daemon's socket directory", owners);
|
|
10411
10765
|
checkSocket(path, owners);
|
|
10766
|
+
if (IS_WINDOWS)
|
|
10767
|
+
pointer = readPointer(path);
|
|
10412
10768
|
} catch (error) {
|
|
10413
10769
|
if (!(error instanceof MessagingError) || error.code !== "daemon_unavailable")
|
|
10414
10770
|
throw error;
|
|
10415
10771
|
}
|
|
10772
|
+
if (IS_WINDOWS && pointer === undefined)
|
|
10773
|
+
throw new MessagingError("daemon_unavailable", "cannot reach the Messaging daemon (ENOENT)");
|
|
10416
10774
|
const timeout = options.connectTimeoutMs ?? 2000;
|
|
10417
10775
|
const socket = await new Promise((resolve, reject) => {
|
|
10418
|
-
const s = net.connect(path);
|
|
10776
|
+
const s = net.connect(pointer?.pipe ?? path);
|
|
10419
10777
|
const timer = setTimeout(() => {
|
|
10420
10778
|
s.destroy();
|
|
10421
10779
|
reject(new MessagingError("daemon_unavailable", "timed out connecting to the Messaging daemon"));
|
|
@@ -10439,6 +10797,9 @@ class MessagingClient {
|
|
|
10439
10797
|
timer = setTimeout(() => reject(new DaemonMismatchError(`the process on the Messaging daemon socket did not say which version it is within ${wait} ms: it is a messagingd from before this version, or it is stuck. ${REMEDY}`)), wait);
|
|
10440
10798
|
})
|
|
10441
10799
|
]);
|
|
10800
|
+
if (pointer !== undefined && hello.pid !== pointer.pid) {
|
|
10801
|
+
throw new MessagingError("forbidden", "the process on the Messaging daemon's pipe is not the daemon that published it");
|
|
10802
|
+
}
|
|
10442
10803
|
const expected = options.version ?? VERSION;
|
|
10443
10804
|
if (hello.protocol !== IPC_PROTOCOL || hello.version !== expected) {
|
|
10444
10805
|
throw new DaemonMismatchError(`the Messaging daemon for this home is version ${shown(hello.version)} (IPC protocol ${hello.protocol}), and this client is version ${shown(expected)} (IPC protocol ${IPC_PROTOCOL}). ${REMEDY}`, hello);
|
|
@@ -10589,6 +10950,7 @@ var init_client = __esm(() => {
|
|
|
10589
10950
|
init_dist();
|
|
10590
10951
|
init_framing();
|
|
10591
10952
|
init_paths();
|
|
10953
|
+
init_pipes();
|
|
10592
10954
|
init_rpc();
|
|
10593
10955
|
init_trust();
|
|
10594
10956
|
DaemonMismatchError = class DaemonMismatchError extends MessagingError {
|
|
@@ -10627,15 +10989,20 @@ async function createIpcServer(options) {
|
|
|
10627
10989
|
throw new MessagingError("invalid_request", "an IPC server needs a tier: agent or admin");
|
|
10628
10990
|
if (options.group !== undefined && options.tier !== "agent")
|
|
10629
10991
|
throw new MessagingError("invalid_request", "only the agent socket may be shared with a group");
|
|
10630
|
-
if (
|
|
10992
|
+
if (options.group !== undefined && IS_WINDOWS)
|
|
10993
|
+
throw new MessagingError("invalid_request", "an agent socket shared with a group is not supported on Windows");
|
|
10994
|
+
if (!IS_WINDOWS && Buffer.byteLength(path) > MAX_SOCKET_PATH_BYTES) {
|
|
10631
10995
|
throw new MessagingError("invalid_request", `socket path is longer than ${MAX_SOCKET_PATH_BYTES} bytes`);
|
|
10632
10996
|
}
|
|
10633
10997
|
const run = dirname2(path);
|
|
10634
10998
|
const home = dirname2(run);
|
|
10635
|
-
mkdirSync2(home, { recursive: true, mode: 448 });
|
|
10999
|
+
const createdHome = mkdirSync2(home, { recursive: true, mode: 448 }) !== undefined;
|
|
11000
|
+
if (IS_WINDOWS && createdHome)
|
|
11001
|
+
secureCreated(home, "the Messaging home directory");
|
|
10636
11002
|
checkPrivateDir(home, "the Messaging home directory");
|
|
10637
11003
|
ensurePrivateDir(run, "the Messaging run directory");
|
|
10638
|
-
await removeStaleSocket(path);
|
|
11004
|
+
await (IS_WINDOWS ? removeStalePointer(path) : removeStaleSocket(path));
|
|
11005
|
+
const listenPath = IS_WINDOWS ? newPipeName(options.tier) : path;
|
|
10639
11006
|
const contexts = new Map;
|
|
10640
11007
|
const hello = { jsonrpc: "2.0", method: "hello", params: { daemon: "messagingd", version: options.version ?? VERSION, protocol: IPC_PROTOCOL, pid: process.pid } };
|
|
10641
11008
|
const server = net2.createServer((socket) => {
|
|
@@ -10718,20 +11085,25 @@ async function createIpcServer(options) {
|
|
|
10718
11085
|
}
|
|
10719
11086
|
await new Promise((resolve, reject) => {
|
|
10720
11087
|
server.once("error", reject);
|
|
10721
|
-
const umask = process.umask(127);
|
|
11088
|
+
const umask = IS_WINDOWS ? undefined : process.umask(127);
|
|
10722
11089
|
try {
|
|
10723
|
-
server.listen(
|
|
11090
|
+
server.listen(listenPath, () => {
|
|
10724
11091
|
server.off("error", reject);
|
|
10725
11092
|
resolve();
|
|
10726
11093
|
});
|
|
10727
11094
|
} finally {
|
|
10728
|
-
|
|
11095
|
+
if (umask !== undefined)
|
|
11096
|
+
process.umask(umask);
|
|
10729
11097
|
}
|
|
10730
11098
|
});
|
|
10731
11099
|
try {
|
|
10732
|
-
if (
|
|
10733
|
-
|
|
10734
|
-
|
|
11100
|
+
if (IS_WINDOWS)
|
|
11101
|
+
writePointer(path, { pipe: listenPath, pid: process.pid });
|
|
11102
|
+
else {
|
|
11103
|
+
if (options.group !== undefined)
|
|
11104
|
+
await chown(path, process.geteuid?.() ?? -1, options.group);
|
|
11105
|
+
await chmod(path, options.group === undefined ? 384 : 432);
|
|
11106
|
+
}
|
|
10735
11107
|
} catch (error) {
|
|
10736
11108
|
await new Promise((resolve) => server.close(() => resolve()));
|
|
10737
11109
|
await rm(path, { force: true });
|
|
@@ -10757,7 +11129,17 @@ async function createIpcServer(options) {
|
|
|
10757
11129
|
for (const socket of contexts.keys())
|
|
10758
11130
|
socket.destroy();
|
|
10759
11131
|
await new Promise((resolve) => server.close(() => resolve()));
|
|
10760
|
-
|
|
11132
|
+
if (IS_WINDOWS) {
|
|
11133
|
+
let ours = false;
|
|
11134
|
+
try {
|
|
11135
|
+
ours = readPointer(path).pipe === listenPath;
|
|
11136
|
+
} catch {
|
|
11137
|
+
ours = false;
|
|
11138
|
+
}
|
|
11139
|
+
if (ours)
|
|
11140
|
+
await rm(path, { force: true });
|
|
11141
|
+
} else
|
|
11142
|
+
await rm(path, { force: true });
|
|
10761
11143
|
}
|
|
10762
11144
|
};
|
|
10763
11145
|
}
|
|
@@ -10811,6 +11193,34 @@ function toRpcError(error) {
|
|
|
10811
11193
|
function describeIssues(issues) {
|
|
10812
11194
|
return `invalid params: ${issues.slice(0, 5).map((i) => `${i.path.map(String).join(".") || "(root)"}: ${i.message}`).join("; ")}`.slice(0, 500);
|
|
10813
11195
|
}
|
|
11196
|
+
async function removeStalePointer(path) {
|
|
11197
|
+
const exists = await stat(path).then((s) => s, () => {
|
|
11198
|
+
return;
|
|
11199
|
+
});
|
|
11200
|
+
if (!exists)
|
|
11201
|
+
return;
|
|
11202
|
+
if (!exists.isFile())
|
|
11203
|
+
throw new MessagingError("invalid_request", "pipe file path exists and is not a file");
|
|
11204
|
+
let pipe;
|
|
11205
|
+
try {
|
|
11206
|
+
pipe = readPointer(path).pipe;
|
|
11207
|
+
} catch {
|
|
11208
|
+
pipe = undefined;
|
|
11209
|
+
}
|
|
11210
|
+
if (pipe !== undefined && await answers(pipe))
|
|
11211
|
+
throw new MessagingError("invalid_request", "another daemon is already listening on this socket");
|
|
11212
|
+
await rm(path, { force: true });
|
|
11213
|
+
}
|
|
11214
|
+
function answers(path) {
|
|
11215
|
+
return new Promise((resolve) => {
|
|
11216
|
+
const probe = net2.connect(path);
|
|
11217
|
+
probe.once("connect", () => {
|
|
11218
|
+
probe.destroy();
|
|
11219
|
+
resolve(true);
|
|
11220
|
+
});
|
|
11221
|
+
probe.once("error", () => resolve(false));
|
|
11222
|
+
});
|
|
11223
|
+
}
|
|
10814
11224
|
async function removeStaleSocket(path) {
|
|
10815
11225
|
const exists = await stat(path).then((s) => s, () => {
|
|
10816
11226
|
return;
|
|
@@ -10836,6 +11246,7 @@ var init_server = __esm(() => {
|
|
|
10836
11246
|
init_dist();
|
|
10837
11247
|
init_framing();
|
|
10838
11248
|
init_paths();
|
|
11249
|
+
init_pipes();
|
|
10839
11250
|
init_rpc();
|
|
10840
11251
|
init_trust();
|
|
10841
11252
|
MAX_BUFFERED_BYTES = 8 * 1024 * 1024;
|
|
@@ -10849,6 +11260,7 @@ var init_dist2 = __esm(() => {
|
|
|
10849
11260
|
init_paths();
|
|
10850
11261
|
init_rpc();
|
|
10851
11262
|
init_trust();
|
|
11263
|
+
init_windows_acl();
|
|
10852
11264
|
});
|
|
10853
11265
|
|
|
10854
11266
|
// packages/daemon/dist/direct-config.js
|
|
@@ -10932,7 +11344,7 @@ var init_direct_config = __esm(() => {
|
|
|
10932
11344
|
|
|
10933
11345
|
// packages/daemon/dist/identity/record.js
|
|
10934
11346
|
import { createPrivateKey as createPrivateKey2 } from "crypto";
|
|
10935
|
-
import { closeSync as closeSync2, constants as
|
|
11347
|
+
import { closeSync as closeSync2, constants as constants3, existsSync as existsSync3, fstatSync, fsyncSync, linkSync, readFileSync as readFileSync4, renameSync as renameSync2, rmSync as rmSync3, statSync, unlinkSync, writeSync } from "fs";
|
|
10936
11348
|
function isQuotable(value) {
|
|
10937
11349
|
return QUOTABLE.test(value);
|
|
10938
11350
|
}
|
|
@@ -10971,9 +11383,9 @@ function decodeSecret(secret) {
|
|
|
10971
11383
|
function readIdentityJson(path) {
|
|
10972
11384
|
let text;
|
|
10973
11385
|
try {
|
|
10974
|
-
const fd =
|
|
11386
|
+
const fd = openNoFollow(path, constants3.O_RDONLY);
|
|
10975
11387
|
try {
|
|
10976
|
-
text =
|
|
11388
|
+
text = readFileSync4(fd, "utf8");
|
|
10977
11389
|
} finally {
|
|
10978
11390
|
closeSync2(fd);
|
|
10979
11391
|
}
|
|
@@ -10997,7 +11409,7 @@ function isPointer(raw) {
|
|
|
10997
11409
|
function replaceIdentityFile(path, text) {
|
|
10998
11410
|
let old;
|
|
10999
11411
|
try {
|
|
11000
|
-
old =
|
|
11412
|
+
old = openNoFollow(path, constants3.O_RDWR);
|
|
11001
11413
|
} catch (error) {
|
|
11002
11414
|
const code = error.code;
|
|
11003
11415
|
if (code === "ELOOP")
|
|
@@ -11005,27 +11417,56 @@ function replaceIdentityFile(path, text) {
|
|
|
11005
11417
|
if (code !== "ENOENT")
|
|
11006
11418
|
throw error;
|
|
11007
11419
|
}
|
|
11420
|
+
let aside;
|
|
11421
|
+
if (IS_WINDOWS && old !== undefined) {
|
|
11422
|
+
closeSync2(old);
|
|
11423
|
+
old = undefined;
|
|
11424
|
+
aside = `${path}.${process.pid}.old`;
|
|
11425
|
+
dropAside(aside, path);
|
|
11426
|
+
linkSync(path, aside);
|
|
11427
|
+
}
|
|
11428
|
+
let renamed = false;
|
|
11008
11429
|
try {
|
|
11009
11430
|
const temp = `${path}.${process.pid}.tmp`;
|
|
11010
|
-
const fd =
|
|
11431
|
+
const fd = openNoFollow(temp, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_TRUNC, 384);
|
|
11011
11432
|
try {
|
|
11012
11433
|
writeSync(fd, text);
|
|
11013
11434
|
fsyncSync(fd);
|
|
11014
11435
|
} finally {
|
|
11015
11436
|
closeSync2(fd);
|
|
11016
11437
|
}
|
|
11017
|
-
|
|
11438
|
+
renameSync2(temp, path);
|
|
11439
|
+
renamed = true;
|
|
11018
11440
|
if (old !== undefined)
|
|
11019
11441
|
scrub(old);
|
|
11442
|
+
if (aside !== undefined)
|
|
11443
|
+
scrubFile(aside);
|
|
11020
11444
|
} finally {
|
|
11021
11445
|
if (old !== undefined)
|
|
11022
11446
|
closeSync2(old);
|
|
11447
|
+
if (aside !== undefined && !renamed)
|
|
11448
|
+
rmSync3(aside, { force: true });
|
|
11023
11449
|
}
|
|
11024
11450
|
}
|
|
11451
|
+
function dropAside(aside, path) {
|
|
11452
|
+
let same = false;
|
|
11453
|
+
try {
|
|
11454
|
+
const a = statSync(aside, { bigint: true });
|
|
11455
|
+
const b = statSync(path, { bigint: true });
|
|
11456
|
+
same = a.ino === b.ino && a.dev === b.dev;
|
|
11457
|
+
} catch (error) {
|
|
11458
|
+
if (error.code === "ENOENT" && !existsSync3(aside))
|
|
11459
|
+
return;
|
|
11460
|
+
}
|
|
11461
|
+
if (same)
|
|
11462
|
+
rmSync3(aside, { force: true });
|
|
11463
|
+
else
|
|
11464
|
+
scrubFile(aside);
|
|
11465
|
+
}
|
|
11025
11466
|
function scrubFile(path) {
|
|
11026
11467
|
let fd;
|
|
11027
11468
|
try {
|
|
11028
|
-
fd =
|
|
11469
|
+
fd = openNoFollow(path, constants3.O_RDWR);
|
|
11029
11470
|
} catch (error) {
|
|
11030
11471
|
if (error.code === "ENOENT")
|
|
11031
11472
|
return;
|
|
@@ -11055,6 +11496,7 @@ function x25519(d) {
|
|
|
11055
11496
|
}
|
|
11056
11497
|
var MAX_RETAINED = 8, PrivateKey322, KeyRecord, QUOTABLE, KeychainPath, KeychainPointer, X25519_PKCS8;
|
|
11057
11498
|
var init_record = __esm(() => {
|
|
11499
|
+
init_dist2();
|
|
11058
11500
|
init_zod();
|
|
11059
11501
|
init_dist();
|
|
11060
11502
|
PrivateKey322 = string2().regex(/^[A-Za-z0-9_-]{43}$/, "32 bytes, base64url without padding");
|
|
@@ -11082,35 +11524,41 @@ var init_record = __esm(() => {
|
|
|
11082
11524
|
});
|
|
11083
11525
|
|
|
11084
11526
|
// packages/daemon/dist/home.js
|
|
11085
|
-
import { chmodSync, chownSync, existsSync as
|
|
11086
|
-
import { join as
|
|
11527
|
+
import { chmodSync, chownSync, existsSync as existsSync4, lstatSync as lstatSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync5, renameSync as renameSync3, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
11528
|
+
import { join as join4, resolve as resolve2 } from "path";
|
|
11087
11529
|
function homePaths(home) {
|
|
11088
11530
|
const root = resolve2(home);
|
|
11089
11531
|
return {
|
|
11090
11532
|
home: root,
|
|
11091
|
-
identity:
|
|
11092
|
-
config:
|
|
11093
|
-
db:
|
|
11094
|
-
run:
|
|
11533
|
+
identity: join4(root, "identity.json"),
|
|
11534
|
+
config: join4(root, "config.json"),
|
|
11535
|
+
db: join4(root, "messaging.db"),
|
|
11536
|
+
run: join4(root, "run"),
|
|
11095
11537
|
agentSocket: socketPath(root, "agent"),
|
|
11096
11538
|
adminSocket: socketPath(root, "admin"),
|
|
11097
|
-
lock:
|
|
11098
|
-
logs:
|
|
11099
|
-
log:
|
|
11539
|
+
lock: join4(root, "run", "messagingd.lock"),
|
|
11540
|
+
logs: join4(root, "logs"),
|
|
11541
|
+
log: join4(root, "logs", "messagingd.log")
|
|
11100
11542
|
};
|
|
11101
11543
|
}
|
|
11102
11544
|
function ensureHome(paths) {
|
|
11103
11545
|
for (const dir of [paths.home, paths.run, paths.logs]) {
|
|
11546
|
+
let created = false;
|
|
11104
11547
|
if (dir === paths.home)
|
|
11105
|
-
mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
11548
|
+
created = mkdirSync4(dir, { recursive: true, mode: 448 }) !== undefined;
|
|
11106
11549
|
else {
|
|
11107
11550
|
try {
|
|
11108
11551
|
mkdirSync4(dir, { mode: 448 });
|
|
11552
|
+
created = true;
|
|
11109
11553
|
} catch (error) {
|
|
11110
11554
|
if (error.code !== "EEXIST")
|
|
11111
11555
|
throw error;
|
|
11112
11556
|
}
|
|
11113
11557
|
}
|
|
11558
|
+
if (IS_WINDOWS) {
|
|
11559
|
+
adoptPrivateDir(dir, dir, created);
|
|
11560
|
+
continue;
|
|
11561
|
+
}
|
|
11114
11562
|
const problem = privacyProblem(lstatSync2(dir));
|
|
11115
11563
|
if (problem !== undefined)
|
|
11116
11564
|
throw new MessagingError("forbidden", `${dir} is not private: it ${problem}`);
|
|
@@ -11118,6 +11566,8 @@ function ensureHome(paths) {
|
|
|
11118
11566
|
}
|
|
11119
11567
|
}
|
|
11120
11568
|
function shareAgentSocket(paths, group) {
|
|
11569
|
+
if (IS_WINDOWS)
|
|
11570
|
+
throw new MessagingError("invalid_request", "ipc.agentGroup is not supported on Windows: messagingd and its clients run as one user there");
|
|
11121
11571
|
for (const dir of [paths.home, paths.run]) {
|
|
11122
11572
|
try {
|
|
11123
11573
|
chownSync(dir, process.geteuid?.() ?? -1, group);
|
|
@@ -11128,11 +11578,11 @@ function shareAgentSocket(paths, group) {
|
|
|
11128
11578
|
}
|
|
11129
11579
|
}
|
|
11130
11580
|
function readConfig(path) {
|
|
11131
|
-
if (!
|
|
11581
|
+
if (!existsSync4(path))
|
|
11132
11582
|
return structuredClone(DEFAULT_CONFIG);
|
|
11133
11583
|
let raw;
|
|
11134
11584
|
try {
|
|
11135
|
-
raw = parseWire(
|
|
11585
|
+
raw = parseWire(readFileSync5(path, "utf8"));
|
|
11136
11586
|
} catch {
|
|
11137
11587
|
throw new MessagingError("invalid_request", `${path} is not valid JSON`);
|
|
11138
11588
|
}
|
|
@@ -11150,16 +11600,16 @@ function writeConfig(path, config) {
|
|
|
11150
11600
|
}
|
|
11151
11601
|
function configStamp(path) {
|
|
11152
11602
|
try {
|
|
11153
|
-
return
|
|
11603
|
+
return statSync2(path).mtimeMs;
|
|
11154
11604
|
} catch {
|
|
11155
11605
|
return 0;
|
|
11156
11606
|
}
|
|
11157
11607
|
}
|
|
11158
11608
|
function writeAtomic(path, text) {
|
|
11159
11609
|
const temp = `${path}.${process.pid}.tmp`;
|
|
11160
|
-
|
|
11610
|
+
writeFileSync2(temp, text, { mode: 384 });
|
|
11161
11611
|
chmodSync(temp, 384);
|
|
11162
|
-
|
|
11612
|
+
renameSync3(temp, path);
|
|
11163
11613
|
}
|
|
11164
11614
|
var PRESENCE_FIELDS, PresenceField, Config, DEFAULT_CONFIG, RETENTION_DEFAULTS, ROTATE_ENC_DAYS = 7, QUOTA_DEFAULTS;
|
|
11165
11615
|
var init_home = __esm(() => {
|
|
@@ -11204,10 +11654,10 @@ var init_home = __esm(() => {
|
|
|
11204
11654
|
});
|
|
11205
11655
|
|
|
11206
11656
|
// packages/daemon/dist/lock.js
|
|
11207
|
-
import { chmodSync as chmodSync2, closeSync as closeSync3, openSync as
|
|
11657
|
+
import { chmodSync as chmodSync2, closeSync as closeSync3, openSync as openSync2, readFileSync as readFileSync6, renameSync as renameSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
11208
11658
|
function readPid(path) {
|
|
11209
11659
|
try {
|
|
11210
|
-
const text =
|
|
11660
|
+
const text = readFileSync6(path, "utf8").trim();
|
|
11211
11661
|
return /^\d+$/.test(text) ? Number(text) : undefined;
|
|
11212
11662
|
} catch {
|
|
11213
11663
|
return;
|
|
@@ -11220,7 +11670,7 @@ function isBusy(error) {
|
|
|
11220
11670
|
function acquireLock(path) {
|
|
11221
11671
|
const dbPath = `${path}.db`;
|
|
11222
11672
|
try {
|
|
11223
|
-
closeSync3(
|
|
11673
|
+
closeSync3(openSync2(dbPath, "wx", 384));
|
|
11224
11674
|
} catch (error) {
|
|
11225
11675
|
if (error.code !== "EEXIST")
|
|
11226
11676
|
throw error;
|
|
@@ -11238,10 +11688,10 @@ function acquireLock(path) {
|
|
|
11238
11688
|
}
|
|
11239
11689
|
try {
|
|
11240
11690
|
const temp = `${path}.${process.pid}.tmp`;
|
|
11241
|
-
|
|
11691
|
+
writeFileSync3(temp, `${process.pid}
|
|
11242
11692
|
`, { mode: 384 });
|
|
11243
11693
|
chmodSync2(temp, 384);
|
|
11244
|
-
|
|
11694
|
+
renameSync4(temp, path);
|
|
11245
11695
|
} catch (error) {
|
|
11246
11696
|
db.close();
|
|
11247
11697
|
throw error;
|
|
@@ -11281,14 +11731,14 @@ var init_lock = __esm(() => {
|
|
|
11281
11731
|
});
|
|
11282
11732
|
|
|
11283
11733
|
// packages/daemon/dist/identity/keychain.js
|
|
11284
|
-
import { spawnSync } from "child_process";
|
|
11285
|
-
import { existsSync as
|
|
11734
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
11735
|
+
import { existsSync as existsSync5 } from "fs";
|
|
11286
11736
|
function keychainAvailable(run = runSecurity) {
|
|
11287
|
-
if (process.platform !== "darwin" || !
|
|
11737
|
+
if (process.platform !== "darwin" || !existsSync5(SECURITY))
|
|
11288
11738
|
return false;
|
|
11289
11739
|
const result = run(["default-keychain", "-d", "user"], { timeoutMs: 5000 });
|
|
11290
11740
|
const path = result.status === 0 ? /"(.+)"/.exec(result.stdout)?.[1] : undefined;
|
|
11291
|
-
return path !== undefined &&
|
|
11741
|
+
return path !== undefined && existsSync5(path);
|
|
11292
11742
|
}
|
|
11293
11743
|
|
|
11294
11744
|
class KeychainStore {
|
|
@@ -11457,7 +11907,7 @@ function keychainError(op, result) {
|
|
|
11457
11907
|
}
|
|
11458
11908
|
}
|
|
11459
11909
|
var SECURITY = "/usr/bin/security", KEYCHAIN_SERVICE = "messaging-identity", LABEL = "messaging-identity", COMMENT = "Messaging machine keys: see messaging identity show", MAX_SECRET = 2000, READ_TIMEOUT_MS = 120000, WRITE_TIMEOUT_MS = 60000, runSecurity = (args, { input, timeoutMs }) => {
|
|
11460
|
-
const result =
|
|
11910
|
+
const result = spawnSync2(SECURITY, args, {
|
|
11461
11911
|
input: input ?? "",
|
|
11462
11912
|
encoding: "utf8",
|
|
11463
11913
|
timeout: timeoutMs,
|
|
@@ -11604,18 +12054,18 @@ var init_identity2 = __esm(() => {
|
|
|
11604
12054
|
});
|
|
11605
12055
|
|
|
11606
12056
|
// packages/daemon/dist/pairing.js
|
|
11607
|
-
import { chmodSync as chmodSync3, closeSync as closeSync4, constants as
|
|
11608
|
-
import { join as
|
|
12057
|
+
import { chmodSync as chmodSync3, closeSync as closeSync4, constants as constants4, fstatSync as fstatSync2, readFileSync as readFileSync7, renameSync as renameSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
12058
|
+
import { join as join6 } from "path";
|
|
11609
12059
|
function pairingPath(home) {
|
|
11610
|
-
return
|
|
12060
|
+
return join6(home, "pairing.json");
|
|
11611
12061
|
}
|
|
11612
12062
|
function readPairing(home) {
|
|
11613
12063
|
const path = pairingPath(home);
|
|
11614
12064
|
let text;
|
|
11615
12065
|
try {
|
|
11616
|
-
const fd =
|
|
12066
|
+
const fd = openNoFollow(path, constants4.O_RDONLY);
|
|
11617
12067
|
try {
|
|
11618
|
-
text =
|
|
12068
|
+
text = readFileSync7(fd, "utf8");
|
|
11619
12069
|
} finally {
|
|
11620
12070
|
closeSync4(fd);
|
|
11621
12071
|
}
|
|
@@ -11644,15 +12094,15 @@ function writePairing(home, pending) {
|
|
|
11644
12094
|
const { identity, ...rest } = pending;
|
|
11645
12095
|
const body = JSON.stringify({ v: PROTOCOL, ...rest, identity: exportIdentity(identity) });
|
|
11646
12096
|
const temp = `${path}.${process.pid}.tmp`;
|
|
11647
|
-
|
|
12097
|
+
writeFileSync4(temp, body, { mode: 384 });
|
|
11648
12098
|
chmodSync3(temp, 384);
|
|
11649
|
-
|
|
12099
|
+
renameSync5(temp, path);
|
|
11650
12100
|
}
|
|
11651
12101
|
function removePairing(home) {
|
|
11652
12102
|
const path = pairingPath(home);
|
|
11653
12103
|
let fd;
|
|
11654
12104
|
try {
|
|
11655
|
-
fd =
|
|
12105
|
+
fd = openNoFollow(path, constants4.O_WRONLY);
|
|
11656
12106
|
} catch (error) {
|
|
11657
12107
|
const code = error.code;
|
|
11658
12108
|
if (code === "ENOENT")
|
|
@@ -11662,7 +12112,7 @@ function removePairing(home) {
|
|
|
11662
12112
|
throw error;
|
|
11663
12113
|
}
|
|
11664
12114
|
try {
|
|
11665
|
-
|
|
12115
|
+
writeFileSync4(fd, Buffer.alloc(fstatSync2(fd).size));
|
|
11666
12116
|
} finally {
|
|
11667
12117
|
closeSync4(fd);
|
|
11668
12118
|
}
|
|
@@ -11670,6 +12120,7 @@ function removePairing(home) {
|
|
|
11670
12120
|
}
|
|
11671
12121
|
var PairingFile;
|
|
11672
12122
|
var init_pairing = __esm(() => {
|
|
12123
|
+
init_dist2();
|
|
11673
12124
|
init_zod();
|
|
11674
12125
|
init_dist();
|
|
11675
12126
|
PairingFile = discriminatedUnion("kind", [
|
|
@@ -12240,7 +12691,7 @@ var init_chat = __esm(() => {
|
|
|
12240
12691
|
});
|
|
12241
12692
|
|
|
12242
12693
|
// packages/daemon/dist/log.js
|
|
12243
|
-
import { closeSync as closeSync5, constants as
|
|
12694
|
+
import { closeSync as closeSync5, constants as constants5, lstatSync as lstatSync3, renameSync as renameSync6, writeSync as writeSync2 } from "fs";
|
|
12244
12695
|
function formatLine(level, event, fields = {}) {
|
|
12245
12696
|
const record = { t: new Date().toISOString(), level, event };
|
|
12246
12697
|
for (const [name, value] of Object.entries(fields))
|
|
@@ -12267,7 +12718,7 @@ function createLogger(options) {
|
|
|
12267
12718
|
rotate2(file, keep);
|
|
12268
12719
|
size = 0;
|
|
12269
12720
|
}
|
|
12270
|
-
const fd =
|
|
12721
|
+
const fd = openNoFollow(file, constants5.O_WRONLY | constants5.O_APPEND | constants5.O_CREAT, 384);
|
|
12271
12722
|
try {
|
|
12272
12723
|
writeSync2(fd, line);
|
|
12273
12724
|
} finally {
|
|
@@ -12292,10 +12743,10 @@ function currentSize(file) {
|
|
|
12292
12743
|
function rotate2(file, keep) {
|
|
12293
12744
|
for (let n = keep - 1;n >= 1; n--) {
|
|
12294
12745
|
try {
|
|
12295
|
-
|
|
12746
|
+
renameSync6(`${file}.${n}`, `${file}.${n + 1}`);
|
|
12296
12747
|
} catch {}
|
|
12297
12748
|
}
|
|
12298
|
-
|
|
12749
|
+
renameSync6(file, `${file}.1`);
|
|
12299
12750
|
}
|
|
12300
12751
|
|
|
12301
12752
|
class LogBudget {
|
|
@@ -12330,6 +12781,7 @@ function codeOf(error) {
|
|
|
12330
12781
|
}
|
|
12331
12782
|
var RANK, LOG_MAX_BYTES, LOG_KEEP = 3;
|
|
12332
12783
|
var init_log = __esm(() => {
|
|
12784
|
+
init_dist2();
|
|
12333
12785
|
RANK = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
12334
12786
|
LOG_MAX_BYTES = 10 * 1024 * 1024;
|
|
12335
12787
|
});
|
|
@@ -13401,7 +13853,7 @@ var init_storage_errors = __esm(() => {
|
|
|
13401
13853
|
});
|
|
13402
13854
|
|
|
13403
13855
|
// packages/daemon/dist/store.js
|
|
13404
|
-
import { chmodSync as chmodSync4, closeSync as closeSync6, openSync as
|
|
13856
|
+
import { chmodSync as chmodSync4, closeSync as closeSync6, openSync as openSync3 } from "fs";
|
|
13405
13857
|
import { DatabaseSync } from "node:sqlite";
|
|
13406
13858
|
function additiveColumn(decl) {
|
|
13407
13859
|
if (/\b(PRIMARY|UNIQUE|CHECK|REFERENCES|COLLATE|GENERATED|AS)\b/i.test(decl))
|
|
@@ -13454,7 +13906,7 @@ class Store {
|
|
|
13454
13906
|
#depth = 0;
|
|
13455
13907
|
constructor(path) {
|
|
13456
13908
|
if (path !== ":memory:") {
|
|
13457
|
-
closeSync6(
|
|
13909
|
+
closeSync6(openSync3(path, "a", 384));
|
|
13458
13910
|
chmodSync4(path, 384);
|
|
13459
13911
|
}
|
|
13460
13912
|
this.#db = new DatabaseSync(path, { timeout: 5000 });
|
|
@@ -14374,13 +14826,14 @@ var init_version = __esm(() => {
|
|
|
14374
14826
|
});
|
|
14375
14827
|
|
|
14376
14828
|
// packages/daemon/dist/wake-bridge.js
|
|
14377
|
-
import { closeSync as closeSync7, constants as
|
|
14829
|
+
import { closeSync as closeSync7, constants as constants6, fstatSync as fstatSync3, lstatSync as lstatSync4, openSync as openSync4, readSync } from "fs";
|
|
14378
14830
|
import { request } from "http";
|
|
14379
14831
|
import { homedir as homedir2 } from "os";
|
|
14380
|
-
import { isAbsolute, join as
|
|
14381
|
-
function serviceFile(env = process.env) {
|
|
14382
|
-
const
|
|
14383
|
-
|
|
14832
|
+
import { isAbsolute, join as join7 } from "path";
|
|
14833
|
+
function serviceFile(env = process.env, windows = IS_WINDOWS) {
|
|
14834
|
+
const home = (windows ? env.USERPROFILE : env.HOME) || homedir2();
|
|
14835
|
+
const state = env.XDG_STATE_HOME && isAbsolute(env.XDG_STATE_HOME) ? env.XDG_STATE_HOME : join7(home, ".local", "state");
|
|
14836
|
+
return join7(state, "opencode", "service.json");
|
|
14384
14837
|
}
|
|
14385
14838
|
function loopbackOrigin(url) {
|
|
14386
14839
|
let parsed;
|
|
@@ -14397,16 +14850,27 @@ function loopbackOrigin(url) {
|
|
|
14397
14850
|
return parsed.origin;
|
|
14398
14851
|
}
|
|
14399
14852
|
function readService(file) {
|
|
14853
|
+
if (IS_WINDOWS) {
|
|
14854
|
+
try {
|
|
14855
|
+
const stats = lstatSync4(file);
|
|
14856
|
+
if (stats.isSymbolicLink() || !stats.isFile() || aclProblem(file, { pinnedOwner: false }) !== undefined)
|
|
14857
|
+
return "service_unsafe";
|
|
14858
|
+
} catch (error) {
|
|
14859
|
+
if (error instanceof MessagingError && error.code === "daemon_unavailable")
|
|
14860
|
+
return "no_service";
|
|
14861
|
+
return error.code === "ENOENT" ? "no_service" : "service_unsafe";
|
|
14862
|
+
}
|
|
14863
|
+
}
|
|
14400
14864
|
let fd;
|
|
14401
14865
|
try {
|
|
14402
|
-
fd =
|
|
14866
|
+
fd = openSync4(file, constants6.O_RDONLY | constants6.O_NOFOLLOW);
|
|
14403
14867
|
} catch (error) {
|
|
14404
14868
|
return error.code === "ENOENT" ? "no_service" : "service_unsafe";
|
|
14405
14869
|
}
|
|
14406
14870
|
try {
|
|
14407
14871
|
const stats = fstatSync3(fd);
|
|
14408
14872
|
const euid = process.geteuid?.();
|
|
14409
|
-
if (!stats.isFile() || euid !== undefined && stats.uid !== euid || (stats.mode & 18) !== 0)
|
|
14873
|
+
if (!stats.isFile() || !IS_WINDOWS && (euid !== undefined && stats.uid !== euid || (stats.mode & 18) !== 0))
|
|
14410
14874
|
return "service_unsafe";
|
|
14411
14875
|
const buffer = Buffer.alloc(SERVICE_BYTES + 1);
|
|
14412
14876
|
const length = readSync(fd, buffer, 0, buffer.length, 0);
|
|
@@ -14621,6 +15085,7 @@ function post2(url, headers, body, signal) {
|
|
|
14621
15085
|
var WAKE_RPC, BRIDGE_TIMING, SERVICE_BYTES = 4096, ANSWER_BYTES = 65536, AnswerTooLarge;
|
|
14622
15086
|
var init_wake_bridge = __esm(() => {
|
|
14623
15087
|
init_dist();
|
|
15088
|
+
init_dist2();
|
|
14624
15089
|
WAKE_RPC = { id: "messaging.opencode", method: "wake" };
|
|
14625
15090
|
BRIDGE_TIMING = { timeoutMs: 1e4, retryMs: [1000, 2000, 4000], concurrency: 4, batch: 16 };
|
|
14626
15091
|
AnswerTooLarge = class AnswerTooLarge extends Error {
|
|
@@ -18479,20 +18944,20 @@ var CHAT_COMMANDS = [list, read, post, search];
|
|
|
18479
18944
|
init_dist();
|
|
18480
18945
|
init_dist2();
|
|
18481
18946
|
import { spawn } from "child_process";
|
|
18482
|
-
import { closeSync, constants, existsSync, mkdirSync as mkdirSync3,
|
|
18483
|
-
import { join as
|
|
18947
|
+
import { closeSync, constants as constants2, existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync3 } from "fs";
|
|
18948
|
+
import { join as join3 } from "path";
|
|
18484
18949
|
function logPath(home) {
|
|
18485
|
-
return
|
|
18950
|
+
return join3(home, "logs", "messagingd.log");
|
|
18486
18951
|
}
|
|
18487
18952
|
function outputPath(home) {
|
|
18488
|
-
return
|
|
18953
|
+
return join3(home, "logs", "messagingd.out");
|
|
18489
18954
|
}
|
|
18490
18955
|
function lockPath(home) {
|
|
18491
|
-
return
|
|
18956
|
+
return join3(home, "run", "messagingd.lock");
|
|
18492
18957
|
}
|
|
18493
18958
|
function openOutput(path) {
|
|
18494
18959
|
try {
|
|
18495
|
-
return
|
|
18960
|
+
return openNoFollow(path, constants2.O_WRONLY | constants2.O_APPEND | constants2.O_CREAT, 384);
|
|
18496
18961
|
} catch (error) {
|
|
18497
18962
|
const code = error.code ?? "error";
|
|
18498
18963
|
const why = code === "ELOOP" ? "it is a symlink" : code;
|
|
@@ -18508,7 +18973,7 @@ function positive(n) {
|
|
|
18508
18973
|
}
|
|
18509
18974
|
function readLockPid(home) {
|
|
18510
18975
|
try {
|
|
18511
|
-
return parseLockPid(
|
|
18976
|
+
return parseLockPid(readFileSync3(lockPath(home), "utf8"));
|
|
18512
18977
|
} catch {
|
|
18513
18978
|
return;
|
|
18514
18979
|
}
|
|
@@ -18568,7 +19033,7 @@ var start = {
|
|
|
18568
19033
|
return;
|
|
18569
19034
|
}
|
|
18570
19035
|
const command = daemonCommand(ctx.io);
|
|
18571
|
-
mkdirSync3(
|
|
19036
|
+
mkdirSync3(join3(ctx.home, "logs"), { recursive: true, mode: 448 });
|
|
18572
19037
|
const output = outputPath(ctx.home);
|
|
18573
19038
|
const fd = openOutput(output);
|
|
18574
19039
|
let exited;
|
|
@@ -18576,6 +19041,7 @@ var start = {
|
|
|
18576
19041
|
const child = spawn(command[0], [...command.slice(1), "--home", ctx.home], {
|
|
18577
19042
|
cwd: ctx.home,
|
|
18578
19043
|
detached: true,
|
|
19044
|
+
windowsHide: true,
|
|
18579
19045
|
env: daemonEnv(ctx.io.env, ctx.home),
|
|
18580
19046
|
stdio: ["ignore", fd, fd]
|
|
18581
19047
|
});
|
|
@@ -18603,12 +19069,12 @@ var start = {
|
|
|
18603
19069
|
};
|
|
18604
19070
|
function daemonCommand(io) {
|
|
18605
19071
|
if (io.daemonCommand) {
|
|
18606
|
-
if (!
|
|
19072
|
+
if (!existsSync2(io.daemonCommand[0]))
|
|
18607
19073
|
throw new MessagingError("internal", "cannot find the messagingd executable");
|
|
18608
19074
|
return io.daemonCommand;
|
|
18609
19075
|
}
|
|
18610
19076
|
const script = io.messagingd;
|
|
18611
|
-
if (!script || !
|
|
19077
|
+
if (!script || !existsSync2(script))
|
|
18612
19078
|
throw new MessagingError("internal", "cannot find messagingd.js next to messaging.js");
|
|
18613
19079
|
return [io.execPath ?? process.execPath, script];
|
|
18614
19080
|
}
|
|
@@ -18658,8 +19124,10 @@ var stop = {
|
|
|
18658
19124
|
details: [
|
|
18659
19125
|
"Asks messagingd to shut down (daemon.stop) and waits for its socket to go away.",
|
|
18660
19126
|
"If messagingd does not answer it, sends SIGTERM instead, but only to the pid the daemon on the",
|
|
18661
|
-
"socket reports, and only when <home>/run/messagingd.lock names the same pid.",
|
|
18662
|
-
"A messagingd of another Messaging version gets SIGTERM the same way, at the pid its hello reports."
|
|
19127
|
+
"socket reports, and only when <home>/run/messagingd.lock names the same pid, then and at the moment of the signal.",
|
|
19128
|
+
"A messagingd of another Messaging version gets SIGTERM the same way, at the pid its hello reports.",
|
|
19129
|
+
`On Windows, which has no signals, "SIGTERM" ends the process at once (TerminateProcess); the home's`,
|
|
19130
|
+
"lock is released and the store stays consistent."
|
|
18663
19131
|
].join(`
|
|
18664
19132
|
`),
|
|
18665
19133
|
args: { min: 0, max: 0 },
|
|
@@ -18672,8 +19140,8 @@ var stop = {
|
|
|
18672
19140
|
throw new MessagingError("daemon_mismatch", `the process on the messagingd socket does not say which version it is${locked !== undefined ? `, and its lock names pid ${locked}` : ""}; stop it with the \`messaging daemon stop\` of its own version, or end that process yourself`);
|
|
18673
19141
|
}
|
|
18674
19142
|
const pid = verifiedPid(locked, hello.pid);
|
|
18675
|
-
ctx.out.note(`messagingd for this home is version ${inline(hello.version, 64)}, not this messaging's;
|
|
18676
|
-
await terminate(ctx, pid, "SIGTERM");
|
|
19143
|
+
ctx.out.note(`messagingd for this home is version ${inline(hello.version, 64)}, not this messaging's; ${SIGNAL_NOTE} pid ${pid}.`);
|
|
19144
|
+
await terminate(ctx, pid, "SIGTERM", locked);
|
|
18677
19145
|
return;
|
|
18678
19146
|
}
|
|
18679
19147
|
if (!running) {
|
|
@@ -18690,23 +19158,30 @@ var stop = {
|
|
|
18690
19158
|
const request = await requestStop(ctx);
|
|
18691
19159
|
if (request !== "accepted") {
|
|
18692
19160
|
pid = verifiedPid(locked, pid);
|
|
18693
|
-
ctx.out.note(`messagingd did not answer daemon.stop;
|
|
19161
|
+
ctx.out.note(`messagingd did not answer daemon.stop; ${SIGNAL_NOTE} pid ${pid}.`);
|
|
18694
19162
|
}
|
|
18695
|
-
await terminate(ctx, pid, request === "accepted" ? "daemon.stop" : "SIGTERM");
|
|
19163
|
+
await terminate(ctx, pid, request === "accepted" ? "daemon.stop" : "SIGTERM", locked);
|
|
18696
19164
|
}
|
|
18697
19165
|
};
|
|
18698
|
-
|
|
19166
|
+
var SIGNAL_NOTE = IS_WINDOWS ? "ending (TerminateProcess)" : "sending SIGTERM to";
|
|
19167
|
+
async function terminate(ctx, pid, method, locked) {
|
|
18699
19168
|
if (method === "SIGTERM" && pid !== undefined) {
|
|
18700
|
-
|
|
18701
|
-
|
|
18702
|
-
|
|
18703
|
-
|
|
18704
|
-
|
|
18705
|
-
}
|
|
19169
|
+
const now = locked === undefined ? pid : readLockPid(ctx.home);
|
|
19170
|
+
if (now !== pid) {
|
|
19171
|
+
if (now !== undefined)
|
|
19172
|
+
throw new MessagingError("internal", `the lock now names pid ${now}, not ${pid}; not sending a signal`);
|
|
19173
|
+
ctx.out.note(`messagingd (pid ${pid}) released its lock; not sending a signal.`);
|
|
19174
|
+
} else
|
|
19175
|
+
try {
|
|
19176
|
+
process.kill(pid, "SIGTERM");
|
|
19177
|
+
} catch (error) {
|
|
19178
|
+
if (error.code !== "ESRCH")
|
|
19179
|
+
throw new MessagingError("forbidden", `cannot signal messagingd (pid ${pid})`);
|
|
19180
|
+
}
|
|
18706
19181
|
}
|
|
18707
19182
|
const which = pid !== undefined ? `messagingd (pid ${pid})` : "messagingd";
|
|
18708
19183
|
const deadline = Date.now() + ctx.timing.stopTimeoutMs;
|
|
18709
|
-
while (
|
|
19184
|
+
while (existsSync2(ctx.socketPath) && (pid === undefined || alive(pid))) {
|
|
18710
19185
|
if (Date.now() >= deadline) {
|
|
18711
19186
|
throw new MessagingError("internal", `${which} ${method === "daemon.stop" ? "accepted daemon.stop but " : ""}did not stop within ${duration2(ctx.timing.stopTimeoutMs)}`);
|
|
18712
19187
|
}
|
|
@@ -19462,7 +19937,7 @@ var invite = {
|
|
|
19462
19937
|
ctx.out.note(`${person} joins with: messaging team join - --label <label> (then paste the ticket and press Ctrl-D)`);
|
|
19463
19938
|
}
|
|
19464
19939
|
};
|
|
19465
|
-
var
|
|
19940
|
+
var join5 = {
|
|
19466
19941
|
name: "team join",
|
|
19467
19942
|
summary: "Join a team with an invite ticket",
|
|
19468
19943
|
usage: "<ticket|-> --label <label>",
|
|
@@ -19752,7 +20227,7 @@ var prepare = {
|
|
|
19752
20227
|
ctx.out.note("Give this machine id to the relay operator for --allow-team-create, then run `messaging team create`.");
|
|
19753
20228
|
}
|
|
19754
20229
|
};
|
|
19755
|
-
var TEAM_COMMANDS = [prepare, create, invite,
|
|
20230
|
+
var TEAM_COMMANDS = [prepare, create, invite, join5, members2, remove, role, revokeInvite, card, add, pair, claim2, pairCancel];
|
|
19756
20231
|
|
|
19757
20232
|
// packages/daemon/dist/cli/version.js
|
|
19758
20233
|
init_dist();
|
|
@@ -19815,7 +20290,7 @@ function resolveTarget(words) {
|
|
|
19815
20290
|
const spec = BY_NAME.get(first);
|
|
19816
20291
|
return spec ? { kind: "command", spec, rest: words.slice(1) } : { kind: "unknown", name: first };
|
|
19817
20292
|
}
|
|
19818
|
-
async function
|
|
20293
|
+
async function run2(argv, io) {
|
|
19819
20294
|
const args = [...argv];
|
|
19820
20295
|
let values;
|
|
19821
20296
|
let positionals;
|
|
@@ -19982,7 +20457,7 @@ function cliMain(argv, start) {
|
|
|
19982
20457
|
process.exit(process.exitCode ?? 0);
|
|
19983
20458
|
});
|
|
19984
20459
|
const env = process.env;
|
|
19985
|
-
return
|
|
20460
|
+
return run2([...argv], {
|
|
19986
20461
|
stdout: process.stdout,
|
|
19987
20462
|
stderr: process.stderr,
|
|
19988
20463
|
get stdin() {
|
|
@@ -20074,17 +20549,18 @@ ${USAGE}`);
|
|
|
20074
20549
|
`);
|
|
20075
20550
|
return 1;
|
|
20076
20551
|
}
|
|
20552
|
+
const signals = process.platform === "win32" ? ["SIGINT", "SIGBREAK"] : ["SIGTERM", "SIGINT"];
|
|
20077
20553
|
const signal = await Promise.race([
|
|
20078
20554
|
new Promise((done) => {
|
|
20079
|
-
|
|
20080
|
-
|
|
20555
|
+
for (const name of signals)
|
|
20556
|
+
process.once(name, () => done(name));
|
|
20081
20557
|
}),
|
|
20082
20558
|
daemon.closed.then(() => {
|
|
20083
20559
|
return;
|
|
20084
20560
|
})
|
|
20085
20561
|
]);
|
|
20086
20562
|
if (signal !== undefined) {
|
|
20087
|
-
for (const name of
|
|
20563
|
+
for (const name of signals)
|
|
20088
20564
|
process.once(name, () => process.exit(1));
|
|
20089
20565
|
log("info", "daemon.signal", { signal });
|
|
20090
20566
|
}
|
|
@@ -20093,9 +20569,10 @@ ${USAGE}`);
|
|
|
20093
20569
|
}
|
|
20094
20570
|
|
|
20095
20571
|
// packages/daemon/dist/bin/dispatch.js
|
|
20096
|
-
import { basename } from "path";
|
|
20097
|
-
function dispatch(argv0, argv) {
|
|
20098
|
-
|
|
20572
|
+
import { basename, win32 } from "path";
|
|
20573
|
+
function dispatch(argv0, argv, windows = process.platform === "win32") {
|
|
20574
|
+
const name = windows ? win32.basename(argv0).toLowerCase().replace(/\.exe$/, "") : basename(argv0);
|
|
20575
|
+
if (name === "messaging")
|
|
20099
20576
|
return { mode: "cli", args: argv };
|
|
20100
20577
|
if (argv[0] === "cli")
|
|
20101
20578
|
return { mode: "cli", args: argv.slice(1) };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@joe-broadhead/messaging-bin-linux-arm64-gnu",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "The self-contained messagingd executable for one platform: the Messaging daemon and its CLI (`messagingd cli …`, or invoked as `messaging`), with no Node.js, npm install or install script on the machine",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Joe Broadhead",
|