@legioncodeinc/hive 0.5.1 → 0.6.2
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 +7 -0
- package/dist/cli-commands.d.ts +20 -0
- package/dist/cli-commands.js +93 -2
- package/dist/cli-commands.js.map +1 -1
- package/dist/cli.js +8 -2
- package/dist/cli.js.map +1 -1
- package/dist/dashboard/web/wire.d.ts +2 -2
- package/dist/install/registry.d.ts +6 -0
- package/dist/install/registry.js +68 -1
- package/dist/install/registry.js.map +1 -1
- package/dist/install/state-dir.d.ts +11 -0
- package/dist/install/state-dir.js +40 -0
- package/dist/install/state-dir.js.map +1 -0
- package/dist/service/commands.d.ts +1 -0
- package/dist/service/commands.js +10 -0
- package/dist/service/commands.js.map +1 -1
- package/dist/service/index.d.ts +32 -1
- package/dist/service/index.js +150 -7
- package/dist/service/index.js.map +1 -1
- package/dist/service/templates.d.ts +16 -2
- package/dist/service/templates.js +22 -7
- package/dist/service/templates.js.map +1 -1
- package/dist/service/windows-identity.d.ts +46 -0
- package/dist/service/windows-identity.js +76 -0
- package/dist/service/windows-identity.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -157,13 +157,20 @@ The `hive` binary keeps a deliberately small surface. It's a portal daemon, not
|
|
|
157
157
|
|
|
158
158
|
```bash
|
|
159
159
|
hive start # run the portal daemon on :3853 (the default verb)
|
|
160
|
+
hive stop # stop the portal daemon (service manager or direct SIGTERM)
|
|
160
161
|
hive install-service # install the OS service unit (launchd / systemd / schtasks)
|
|
161
162
|
hive uninstall-service # remove the service unit
|
|
163
|
+
hive uninstall # stop, remove service, registry entry, and hive state dir
|
|
162
164
|
hive register # append Hive to Doctor's daemon registry
|
|
163
165
|
```
|
|
164
166
|
|
|
165
167
|
That's the whole list, on purpose. Day to day you never touch it; the installer wires the service unit and registration, Doctor keeps the process alive, and you live in the browser.
|
|
166
168
|
|
|
169
|
+
Two behaviors worth knowing:
|
|
170
|
+
|
|
171
|
+
- **Hive owns sign-in for the fleet.** When Honeycomb or Nectar detect Hive on the machine, they never open a sign-in of their own; this dashboard's onboarding is the one login surface, and the workload daemons sit degraded until it writes the shared credentials, then recover on their own.
|
|
172
|
+
- **`uninstall` is surgical and honest.** It stops the daemon, removes the service unit (current `com.legioncode.hive` and legacy `thehive` labels), deletes Hive's entry from Doctor's registry without touching anyone else's, and removes `~/.apiary/hive`, nothing more. Already gone? It exits 0 and says so. For a full-machine wipe, see `doctor purge` or the one-command uninstall at [get.theapiary.sh](https://get.theapiary.sh).
|
|
173
|
+
|
|
167
174
|
<img src="assets/brand/divider-minor.svg" width="100%" height="3">
|
|
168
175
|
|
|
169
176
|
## ✨ Open one URL, see the whole hive
|
package/dist/cli-commands.d.ts
CHANGED
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { type StartHiveOptions } from "./daemon/server.js";
|
|
15
15
|
import { type RegistryUpsertOptions } from "./install/registry.js";
|
|
16
|
+
import { type StateDirFs } from "./install/state-dir.js";
|
|
16
17
|
import { type ServiceModule } from "./service/index.js";
|
|
18
|
+
import { type FleetRootDeps } from "./shared/apiary-root.js";
|
|
17
19
|
import { type EmitDeps } from "./telemetry/emit.js";
|
|
18
20
|
/** A sink for user-facing output lines (defaults to `process.stdout`). */
|
|
19
21
|
export type OutputWriter = (text: string) => void;
|
|
@@ -39,3 +41,21 @@ export interface RegisterCommandDeps {
|
|
|
39
41
|
readonly out?: OutputWriter;
|
|
40
42
|
}
|
|
41
43
|
export declare function runRegisterCommand(deps?: RegisterCommandDeps): Promise<number>;
|
|
44
|
+
/** Injectable deps for the `stop` verb. */
|
|
45
|
+
export interface StopCommandDeps {
|
|
46
|
+
readonly service?: ServiceModule;
|
|
47
|
+
readonly fleetRoot?: FleetRootDeps;
|
|
48
|
+
readonly pidPath?: string;
|
|
49
|
+
readonly readPid?: (path: string) => number | null;
|
|
50
|
+
readonly isPidAlive?: (pid: number) => boolean;
|
|
51
|
+
readonly kill?: (pid: number, signal: NodeJS.Signals) => void;
|
|
52
|
+
readonly out?: OutputWriter;
|
|
53
|
+
}
|
|
54
|
+
export declare function runStopCommand(cliEntryPath: string, deps?: StopCommandDeps): Promise<number>;
|
|
55
|
+
/** Injectable deps for the `uninstall` verb. */
|
|
56
|
+
export interface UninstallCommandDeps extends ServiceCommandDeps {
|
|
57
|
+
readonly fleetRoot?: FleetRootDeps;
|
|
58
|
+
readonly stateDirFs?: StateDirFs;
|
|
59
|
+
readonly stop?: (cliEntryPath: string) => Promise<number>;
|
|
60
|
+
}
|
|
61
|
+
export declare function runUninstallCommand(cliEntryPath: string, deps?: UninstallCommandDeps): Promise<number>;
|
package/dist/cli-commands.js
CHANGED
|
@@ -12,8 +12,11 @@
|
|
|
12
12
|
* A telemetry failure NEVER changes a verb's exit code: emit helpers resolve, never reject.
|
|
13
13
|
*/
|
|
14
14
|
import { startHive } from "./daemon/server.js";
|
|
15
|
-
import { registerHiveWithDoctor } from "./install/registry.js";
|
|
15
|
+
import { deleteHiveFromDoctor, registerHiveWithDoctor, registryContainsHiveEntry } from "./install/registry.js";
|
|
16
|
+
import { hiveStateDirExists, removeHiveStateDir } from "./install/state-dir.js";
|
|
16
17
|
import { createServiceModule } from "./service/index.js";
|
|
18
|
+
import { isPidAlive, readPidFile } from "./lock.js";
|
|
19
|
+
import { resolveHivePidPath } from "./shared/apiary-root.js";
|
|
17
20
|
import { emitInstalled, emitUninstalled, recordStartLifecycle } from "./telemetry/emit.js";
|
|
18
21
|
const defaultOut = (text) => {
|
|
19
22
|
process.stdout.write(text);
|
|
@@ -63,7 +66,9 @@ export async function runUninstallServiceCommand(cliEntryPath, deps = {}) {
|
|
|
63
66
|
const result = await service.uninstall();
|
|
64
67
|
out(`${result.message}\n`);
|
|
65
68
|
await uninstallTelemetry;
|
|
66
|
-
|
|
69
|
+
// M-2 / b-AC-6: the current unit having already been absent is a friendly no-op,
|
|
70
|
+
// not a failure - only a genuine deregister error should flip the exit code.
|
|
71
|
+
return result.ok || result.alreadyAbsent ? 0 : 1;
|
|
67
72
|
}
|
|
68
73
|
export async function runRegisterCommand(deps = {}) {
|
|
69
74
|
const out = deps.out ?? defaultOut;
|
|
@@ -73,4 +78,90 @@ export async function runRegisterCommand(deps = {}) {
|
|
|
73
78
|
: `Registered hive in ${registration.registryPath}\n`);
|
|
74
79
|
return 0;
|
|
75
80
|
}
|
|
81
|
+
function isHiveProcessRunning(deps) {
|
|
82
|
+
const pidPath = deps.pidPath ?? resolveHivePidPath(deps.fleetRoot);
|
|
83
|
+
const pid = (deps.readPid ?? readPidFile)(pidPath);
|
|
84
|
+
return pid !== null && (deps.isPidAlive ?? isPidAlive)(pid);
|
|
85
|
+
}
|
|
86
|
+
export async function runStopCommand(cliEntryPath, deps = {}) {
|
|
87
|
+
const out = deps.out ?? defaultOut;
|
|
88
|
+
const service = deps.service ?? createServiceModule({ execPath: cliEntryPath });
|
|
89
|
+
if (await service.isRegistered()) {
|
|
90
|
+
const result = await service.stop();
|
|
91
|
+
if (!result.ok && !isHiveProcessRunning(deps)) {
|
|
92
|
+
out("hive is not running.\n");
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
out(`${result.message}\n`);
|
|
96
|
+
return result.ok ? 0 : 1;
|
|
97
|
+
}
|
|
98
|
+
if (!isHiveProcessRunning(deps)) {
|
|
99
|
+
out("hive is not running.\n");
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
const pidPath = deps.pidPath ?? resolveHivePidPath(deps.fleetRoot);
|
|
103
|
+
const pid = (deps.readPid ?? readPidFile)(pidPath);
|
|
104
|
+
if (pid === null) {
|
|
105
|
+
out("hive is not running.\n");
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
(deps.kill ?? ((targetPid, signal) => process.kill(targetPid, signal)))(pid, "SIGTERM");
|
|
110
|
+
out(`Sent SIGTERM to hive (pid ${pid}).\n`);
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
out(`Could not stop hive: ${error instanceof Error ? error.message : "unknown error"}.\n`);
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async function hiveHasInstallArtifacts(cliEntryPath, deps) {
|
|
119
|
+
const service = deps.service ?? createServiceModule({ execPath: cliEntryPath });
|
|
120
|
+
if (await service.isRegistered())
|
|
121
|
+
return true;
|
|
122
|
+
if (registryContainsHiveEntry(deps.registry))
|
|
123
|
+
return true;
|
|
124
|
+
if (hiveStateDirExists(deps.fleetRoot, deps.stateDirFs))
|
|
125
|
+
return true;
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
export async function runUninstallCommand(cliEntryPath, deps = {}) {
|
|
129
|
+
const out = deps.out ?? defaultOut;
|
|
130
|
+
if (!(await hiveHasInstallArtifacts(cliEntryPath, deps))) {
|
|
131
|
+
out("hive is not installed; nothing to remove.\n");
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
const stop = deps.stop ?? ((entryPath) => runStopCommand(entryPath, deps));
|
|
135
|
+
const service = deps.service ?? createServiceModule({ execPath: cliEntryPath });
|
|
136
|
+
const uninstallTelemetry = emitUninstalled(deps.telemetry);
|
|
137
|
+
const stopCode = await stop(cliEntryPath);
|
|
138
|
+
out(stopCode === 0 ? "Stopped hive daemon.\n" : "Stop step reported an issue; continuing uninstall.\n");
|
|
139
|
+
const serviceResult = await service.uninstall();
|
|
140
|
+
out(`${serviceResult.message}\n`);
|
|
141
|
+
const registryResult = deleteHiveFromDoctor(deps.registry);
|
|
142
|
+
out(registryResult.removed
|
|
143
|
+
? `Removed hive from doctor registry (${registryResult.registryPaths.join(", ")}).\n`
|
|
144
|
+
: "No hive registry entry to remove.\n");
|
|
145
|
+
let stateRemoved = false;
|
|
146
|
+
try {
|
|
147
|
+
stateRemoved = removeHiveStateDir(deps.fleetRoot, deps.stateDirFs);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
out(`Could not remove hive state dir: ${error instanceof Error ? error.message : "unknown error"}.\n`);
|
|
151
|
+
await uninstallTelemetry;
|
|
152
|
+
return 1;
|
|
153
|
+
}
|
|
154
|
+
out(stateRemoved ? "Removed hive state dir.\n" : "No hive state dir to remove.\n");
|
|
155
|
+
await uninstallTelemetry;
|
|
156
|
+
// M-2 / b-AC-6: the current unit having already been absent (e.g. the stop step
|
|
157
|
+
// above already boot-ed it out on macOS) is a friendly no-op, not a failure.
|
|
158
|
+
// AC-9: never print the success line on the failure path - a contradictory
|
|
159
|
+
// "hive uninstalled." after a real deregister error hides the failure.
|
|
160
|
+
if (serviceResult.ok || serviceResult.alreadyAbsent) {
|
|
161
|
+
out("hive uninstalled.\n");
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
out("hive uninstall completed with errors: the service unit may still be registered. Fix the error above and re-run 'hive uninstall'.\n");
|
|
165
|
+
return 1;
|
|
166
|
+
}
|
|
76
167
|
//# sourceMappingURL=cli-commands.js.map
|
package/dist/cli-commands.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-commands.js","sourceRoot":"","sources":["../src/cli-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,SAAS,EAAyB,MAAM,oBAAoB,CAAC;AACtE,OAAO,
|
|
1
|
+
{"version":3,"file":"cli-commands.js","sourceRoot":"","sources":["../src/cli-commands.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { runInstallServiceCommand, runRegisterCommand, runStartCommand, runUninstallServiceCommand } from "./cli-commands.js";
|
|
3
|
+
import { runInstallServiceCommand, runRegisterCommand, runStartCommand, runStopCommand, runUninstallCommand, runUninstallServiceCommand } from "./cli-commands.js";
|
|
4
4
|
import { DaemonAlreadyRunningError } from "./errors.js";
|
|
5
5
|
function printUsage() {
|
|
6
|
-
process.stderr.write("Usage: hive <start|install-service|uninstall-service|register>\n");
|
|
6
|
+
process.stderr.write("Usage: hive <start|stop|install-service|uninstall-service|uninstall|register>\n");
|
|
7
7
|
}
|
|
8
8
|
async function run() {
|
|
9
9
|
const command = process.argv[2] ?? "start";
|
|
@@ -13,12 +13,18 @@ async function run() {
|
|
|
13
13
|
case "start":
|
|
14
14
|
process.exitCode = await runStartCommand();
|
|
15
15
|
return;
|
|
16
|
+
case "stop":
|
|
17
|
+
process.exitCode = await runStopCommand(cliEntryPath);
|
|
18
|
+
return;
|
|
16
19
|
case "install-service":
|
|
17
20
|
process.exitCode = await runInstallServiceCommand(cliEntryPath);
|
|
18
21
|
return;
|
|
19
22
|
case "uninstall-service":
|
|
20
23
|
process.exitCode = await runUninstallServiceCommand(cliEntryPath);
|
|
21
24
|
return;
|
|
25
|
+
case "uninstall":
|
|
26
|
+
process.exitCode = await runUninstallCommand(cliEntryPath);
|
|
27
|
+
return;
|
|
22
28
|
case "register":
|
|
23
29
|
process.exitCode = await runRegisterCommand();
|
|
24
30
|
return;
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,eAAe,EACf,0BAA0B,EAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAExD,SAAS,UAAU;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,0BAA0B,EAC3B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAExD,SAAS,UAAU;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iFAAiF,CAAC,CAAC;AAC1G,CAAC;AAED,KAAK,UAAU,GAAG;IAChB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC;IAC3C,MAAM,YAAY,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEpD,IAAI,CAAC;QACH,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,OAAO;gBACV,OAAO,CAAC,QAAQ,GAAG,MAAM,eAAe,EAAE,CAAC;gBAC3C,OAAO;YACT,KAAK,MAAM;gBACT,OAAO,CAAC,QAAQ,GAAG,MAAM,cAAc,CAAC,YAAY,CAAC,CAAC;gBACtD,OAAO;YACT,KAAK,iBAAiB;gBACpB,OAAO,CAAC,QAAQ,GAAG,MAAM,wBAAwB,CAAC,YAAY,CAAC,CAAC;gBAChE,OAAO;YACT,KAAK,mBAAmB;gBACtB,OAAO,CAAC,QAAQ,GAAG,MAAM,0BAA0B,CAAC,YAAY,CAAC,CAAC;gBAClE,OAAO;YACT,KAAK,WAAW;gBACd,OAAO,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,YAAY,CAAC,CAAC;gBAC3D,OAAO;YACT,KAAK,UAAU;gBACb,OAAO,CAAC,QAAQ,GAAG,MAAM,kBAAkB,EAAE,CAAC;gBAC9C,OAAO;YACT;gBACE,UAAU,EAAE,CAAC;gBACb,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;gBACrB,OAAO;QACX,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,yBAAyB,EAAE,CAAC;YAC/C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;YAC3C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;YAC3C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,GAAG,EAAE,CAAC"}
|
|
@@ -1414,8 +1414,8 @@ export declare const SetupStateSchema: z.ZodObject<{
|
|
|
1414
1414
|
migration: z.ZodOptional<z.ZodObject<{
|
|
1415
1415
|
phase: z.ZodCatch<z.ZodEnum<{
|
|
1416
1416
|
link: "link";
|
|
1417
|
-
backup: "backup";
|
|
1418
1417
|
uninstall: "uninstall";
|
|
1418
|
+
backup: "backup";
|
|
1419
1419
|
done: "done";
|
|
1420
1420
|
rolled_back: "rolled_back";
|
|
1421
1421
|
}>>;
|
|
@@ -1452,8 +1452,8 @@ export declare const SetupMigrateSchema: z.ZodObject<{
|
|
|
1452
1452
|
ok: z.ZodCatch<z.ZodBoolean>;
|
|
1453
1453
|
phase: z.ZodCatch<z.ZodEnum<{
|
|
1454
1454
|
link: "link";
|
|
1455
|
-
backup: "backup";
|
|
1456
1455
|
uninstall: "uninstall";
|
|
1456
|
+
backup: "backup";
|
|
1457
1457
|
done: "done";
|
|
1458
1458
|
rolled_back: "rolled_back";
|
|
1459
1459
|
}>>;
|
|
@@ -32,4 +32,10 @@ export type RegistryDaemonEntry = Record<string, unknown> & {
|
|
|
32
32
|
export declare function createNodeRegistryFs(): RegistryFs;
|
|
33
33
|
export declare function buildHiveRegistryEntry(): RegistryDaemonEntry;
|
|
34
34
|
export declare function registerHiveWithDoctor(options?: RegistryUpsertOptions): RegistryUpsertResult;
|
|
35
|
+
export interface RegistryDeleteResult {
|
|
36
|
+
readonly removed: boolean;
|
|
37
|
+
readonly registryPaths: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
export declare function deleteHiveFromDoctor(options?: RegistryUpsertOptions): RegistryDeleteResult;
|
|
40
|
+
export declare function registryContainsHiveEntry(options?: RegistryUpsertOptions): boolean;
|
|
35
41
|
export { resolveRegistryWritePath } from "../shared/registry-paths.js";
|
package/dist/install/registry.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
|
-
import { resolveHiveRegistryPidPath } from "../shared/apiary-root.js";
|
|
3
|
+
import { resolveFleetRegistryPath, resolveHiveRegistryPidPath } from "../shared/apiary-root.js";
|
|
4
|
+
import { resolveLegacyDoctorRegistryPath } from "../shared/legacy-paths.js";
|
|
4
5
|
import { resolveRegistryWritePath } from "../shared/registry-paths.js";
|
|
5
6
|
// NOTE: there is deliberately NO exported DOCTOR_REGISTRY_PATH constant on the write side.
|
|
6
7
|
// The write target is window-dependent (`resolveRegistryWritePath()` answers differently before
|
|
@@ -113,5 +114,71 @@ export function registerHiveWithDoctor(options = {}) {
|
|
|
113
114
|
updatedExistingEntry: index >= 0
|
|
114
115
|
};
|
|
115
116
|
}
|
|
117
|
+
function registryHasHiveEntry(path, fs) {
|
|
118
|
+
const parsed = readRegistryDocument(path, fs);
|
|
119
|
+
return parsed.daemons.some((entry) => entry["name"] === HIVE_REGISTRY_NAME);
|
|
120
|
+
}
|
|
121
|
+
function deleteHiveEntryAtPath(path, fs) {
|
|
122
|
+
let parsed;
|
|
123
|
+
try {
|
|
124
|
+
parsed = readRegistryDocument(path, fs);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
const code = error.code;
|
|
128
|
+
if (code === "ENOENT")
|
|
129
|
+
return false;
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
const index = parsed.daemons.findIndex((entry) => entry["name"] === HIVE_REGISTRY_NAME);
|
|
133
|
+
if (index < 0)
|
|
134
|
+
return false;
|
|
135
|
+
const nextDaemons = parsed.daemons.filter((_, entryIndex) => entryIndex !== index);
|
|
136
|
+
const nextRoot = { ...parsed.root, daemons: nextDaemons };
|
|
137
|
+
const serialized = `${JSON.stringify(nextRoot, null, 2)}\n`;
|
|
138
|
+
const tempPath = nextTempPath(path);
|
|
139
|
+
fs.mkdirp(dirname(path));
|
|
140
|
+
fs.writeFile(tempPath, serialized);
|
|
141
|
+
try {
|
|
142
|
+
fs.rename(tempPath, path);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
fs.removeFile(tempPath);
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
export function deleteHiveFromDoctor(options = {}) {
|
|
151
|
+
const fs = options.fs ?? createNodeRegistryFs();
|
|
152
|
+
const explicitPath = options.registryPath;
|
|
153
|
+
const candidatePaths = explicitPath !== undefined
|
|
154
|
+
? [explicitPath]
|
|
155
|
+
: [resolveRegistryWritePath(), resolveFleetRegistryPath(), resolveLegacyDoctorRegistryPath()];
|
|
156
|
+
const registryPaths = [];
|
|
157
|
+
for (const path of [...new Set(candidatePaths)]) {
|
|
158
|
+
if (deleteHiveEntryAtPath(path, fs))
|
|
159
|
+
registryPaths.push(path);
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
removed: registryPaths.length > 0,
|
|
163
|
+
registryPaths
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
export function registryContainsHiveEntry(options = {}) {
|
|
167
|
+
const fs = options.fs ?? createNodeRegistryFs();
|
|
168
|
+
const explicitPath = options.registryPath;
|
|
169
|
+
const candidatePaths = explicitPath !== undefined
|
|
170
|
+
? [explicitPath]
|
|
171
|
+
: [resolveRegistryWritePath(), resolveFleetRegistryPath(), resolveLegacyDoctorRegistryPath()];
|
|
172
|
+
for (const path of [...new Set(candidatePaths)]) {
|
|
173
|
+
try {
|
|
174
|
+
if (registryHasHiveEntry(path, fs))
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
// Unreadable registry files are treated as absent for uninstall no-op detection.
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
116
183
|
export { resolveRegistryWritePath } from "../shared/registry-paths.js";
|
|
117
184
|
//# sourceMappingURL=registry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/install/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACrF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/install/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type FleetRootDeps } from "../shared/apiary-root.js";
|
|
2
|
+
export interface StateDirFs {
|
|
3
|
+
exists(path: string): boolean;
|
|
4
|
+
lstat(path: string): {
|
|
5
|
+
readonly isSymbolicLink: () => boolean;
|
|
6
|
+
};
|
|
7
|
+
removeDir(path: string): void;
|
|
8
|
+
}
|
|
9
|
+
export declare function createNodeStateDirFs(): StateDirFs;
|
|
10
|
+
export declare function removeHiveStateDir(deps?: FleetRootDeps, fs?: StateDirFs): boolean;
|
|
11
|
+
export declare function hiveStateDirExists(deps?: FleetRootDeps, fs?: StateDirFs): boolean;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { existsSync, lstatSync, rmSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, relative, resolve } from "node:path";
|
|
3
|
+
import { resolveFleetRoot, resolveHiveStateDir } from "../shared/apiary-root.js";
|
|
4
|
+
export function createNodeStateDirFs() {
|
|
5
|
+
return {
|
|
6
|
+
exists(path) {
|
|
7
|
+
return existsSync(path);
|
|
8
|
+
},
|
|
9
|
+
lstat(path) {
|
|
10
|
+
return lstatSync(path);
|
|
11
|
+
},
|
|
12
|
+
removeDir(path) {
|
|
13
|
+
rmSync(path, { recursive: true, force: true });
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function isPathWithinRoot(targetPath, rootPath) {
|
|
18
|
+
const resolvedTarget = resolve(targetPath);
|
|
19
|
+
const resolvedRoot = resolve(rootPath);
|
|
20
|
+
const rel = relative(resolvedRoot, resolvedTarget);
|
|
21
|
+
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
22
|
+
}
|
|
23
|
+
export function removeHiveStateDir(deps = {}, fs = createNodeStateDirFs()) {
|
|
24
|
+
const fleetRoot = resolveFleetRoot(deps);
|
|
25
|
+
const stateDir = resolveHiveStateDir(deps);
|
|
26
|
+
if (!isPathWithinRoot(stateDir, fleetRoot)) {
|
|
27
|
+
throw new Error(`Refusing to remove hive state dir outside the fleet root: ${stateDir}`);
|
|
28
|
+
}
|
|
29
|
+
if (!fs.exists(stateDir))
|
|
30
|
+
return false;
|
|
31
|
+
if (fs.lstat(stateDir).isSymbolicLink()) {
|
|
32
|
+
throw new Error(`Refusing to remove hive state dir because it is a symlink: ${stateDir}`);
|
|
33
|
+
}
|
|
34
|
+
fs.removeDir(stateDir);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
export function hiveStateDirExists(deps = {}, fs = createNodeStateDirFs()) {
|
|
38
|
+
return fs.exists(resolveHiveStateDir(deps));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=state-dir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-dir.js","sourceRoot":"","sources":["../../src/install/state-dir.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAsB,MAAM,0BAA0B,CAAC;AAQrG,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,MAAM,CAAC,IAAY;YACjB,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK,CAAC,IAAY;YAChB,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QACD,SAAS,CAAC,IAAY;YACpB,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAkB,EAAE,QAAgB;IAC5D,MAAM,cAAc,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvC,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IACnD,OAAO,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAsB,EAAE,EAAE,KAAiB,oBAAoB,EAAE;IAClG,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAE3C,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,6DAA6D,QAAQ,EAAE,CAAC,CAAC;IAC3F,CAAC;IAED,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,IAAI,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,8DAA8D,QAAQ,EAAE,CAAC,CAAC;IAC5F,CAAC;IAED,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACvB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAsB,EAAE,EAAE,KAAiB,oBAAoB,EAAE;IAClG,OAAO,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -6,6 +6,7 @@ export interface ServiceCommand {
|
|
|
6
6
|
export declare function launchdDomainTarget(uid: number): string;
|
|
7
7
|
export declare function launchdServiceTarget(plan: ServicePlan, uid: number): string;
|
|
8
8
|
export declare function installCommands(plan: ServicePlan, uid: number): readonly ServiceCommand[];
|
|
9
|
+
export declare function stopCommands(plan: ServicePlan, uid: number): readonly ServiceCommand[];
|
|
9
10
|
export declare function uninstallCommands(plan: ServicePlan, uid: number): readonly ServiceCommand[];
|
|
10
11
|
/**
|
|
11
12
|
* The argv to deregister the PRE-decision-#32 unit names (`thehive` / `thehive.service`).
|
package/dist/service/commands.js
CHANGED
|
@@ -21,6 +21,16 @@ export function installCommands(plan, uid) {
|
|
|
21
21
|
];
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
export function stopCommands(plan, uid) {
|
|
25
|
+
switch (plan.manager) {
|
|
26
|
+
case "launchd":
|
|
27
|
+
return [{ command: "launchctl", args: ["bootout", launchdServiceTarget(plan, uid)] }];
|
|
28
|
+
case "systemd":
|
|
29
|
+
return [{ command: "systemctl", args: ["--user", "stop", SYSTEMD_UNIT_NAME] }];
|
|
30
|
+
case "schtasks":
|
|
31
|
+
return [{ command: "schtasks", args: ["/End", "/TN", WINDOWS_TASK_NAME] }];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
24
34
|
export function uninstallCommands(plan, uid) {
|
|
25
35
|
switch (plan.manager) {
|
|
26
36
|
case "launchd":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/service/commands.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/service/commands.ts"],"names":[],"mappings":"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"}
|
package/dist/service/index.d.ts
CHANGED
|
@@ -15,14 +15,38 @@ export interface ServiceFs {
|
|
|
15
15
|
mkdirp(path: string): void;
|
|
16
16
|
writeFile(path: string, content: string): void;
|
|
17
17
|
removeFile(path: string): void;
|
|
18
|
+
fileExists(path: string): boolean;
|
|
18
19
|
}
|
|
19
20
|
export interface ServiceResult {
|
|
20
21
|
readonly ok: boolean;
|
|
21
22
|
readonly message: string;
|
|
22
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* The outcome of {@link ServiceModule.uninstall}, additionally classified so a
|
|
26
|
+
* caller can tell a genuine removal failure from the current unit simply
|
|
27
|
+
* having been absent already (M-2 / PRD-003b AC-9, b-AC-6): on macOS the
|
|
28
|
+
* `uninstall` verb runs `stop` (launchd `bootout`) before `service.uninstall()`
|
|
29
|
+
* issues its own `bootout` of the same unit, so the second call always finds
|
|
30
|
+
* "No such process" after a fully successful stop. A boot-resurrecting unit
|
|
31
|
+
* left behind by a swallowed "it was probably already gone" error is exactly
|
|
32
|
+
* the failure mode this classification exists to catch, so `alreadyAbsent`
|
|
33
|
+
* stays `false` for anything that does not match a known not-found signal.
|
|
34
|
+
*/
|
|
35
|
+
export interface ServiceUninstallResult extends ServiceResult {
|
|
36
|
+
/**
|
|
37
|
+
* True when the manager reported the current unit was not registered/found
|
|
38
|
+
* rather than a real error (permission denied, manager unreachable, etc.).
|
|
39
|
+
* A true `alreadyAbsent` is a friendly no-op; `ok` stays false either way
|
|
40
|
+
* since nothing was actually removed by THIS call - callers should treat
|
|
41
|
+
* `alreadyAbsent === true` the same as `ok === true` for exit-code purposes.
|
|
42
|
+
*/
|
|
43
|
+
readonly alreadyAbsent: boolean;
|
|
44
|
+
}
|
|
23
45
|
export interface ServiceModule {
|
|
24
46
|
install(): Promise<ServiceResult>;
|
|
25
|
-
|
|
47
|
+
stop(): Promise<ServiceResult>;
|
|
48
|
+
uninstall(): Promise<ServiceUninstallResult>;
|
|
49
|
+
isRegistered(): Promise<boolean>;
|
|
26
50
|
}
|
|
27
51
|
export interface ServiceModuleDeps {
|
|
28
52
|
readonly execPath: string;
|
|
@@ -35,6 +59,13 @@ export interface ServiceModuleDeps {
|
|
|
35
59
|
* against the plan's home; tests MUST inject a no-op so a fake `home` never touches real disk.
|
|
36
60
|
*/
|
|
37
61
|
readonly migrateState?: (environment: ServiceEnvironment) => void;
|
|
62
|
+
/**
|
|
63
|
+
* Windows-only seam resolving the SID (or `domain\user` fallback) embedded as the schtasks
|
|
64
|
+
* `LogonTrigger`/`Principal` `UserId` (see `templates.ts` `renderScheduledTaskXml`). Defaults to
|
|
65
|
+
* the real {@link resolveWindowsUserId} (execFile of `whoami.exe`, never a shell); tests MUST
|
|
66
|
+
* inject a fixed value so a run never shells out. Never invoked for launchd/systemd plans.
|
|
67
|
+
*/
|
|
68
|
+
readonly resolveWindowsUserId?: () => Promise<string | null>;
|
|
38
69
|
}
|
|
39
70
|
export declare function createExecFileRunner(): CommandRunner;
|
|
40
71
|
export declare function createNodeServiceFs(): ServiceFs;
|
package/dist/service/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
|
-
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
4
|
import { resolveStagedWindowsTaskPath } from "../shared/apiary-root.js";
|
|
5
5
|
import { migrateHiveState } from "../shared/state-migration.js";
|
|
6
|
-
import { installCommands, legacyUninstallCommands, uninstallCommands } from "./commands.js";
|
|
7
|
-
import { legacyUnitPath, resolveServiceContext, resolveServicePlan } from "./platform.js";
|
|
6
|
+
import { installCommands, legacyUninstallCommands, stopCommands, uninstallCommands } from "./commands.js";
|
|
7
|
+
import { legacyUnitPath, LEGACY_WINDOWS_TASK_NAME, resolveServiceContext, resolveServicePlan, WINDOWS_TASK_NAME } from "./platform.js";
|
|
8
8
|
import { renderUnit } from "./templates.js";
|
|
9
|
+
import { resolveWindowsUserId as resolveWindowsUserIdDefault } from "./windows-identity.js";
|
|
9
10
|
const SERVICE_COMMAND_TIMEOUT_MS = 15_000;
|
|
10
11
|
export function createExecFileRunner() {
|
|
11
12
|
return {
|
|
@@ -40,6 +41,9 @@ export function createNodeServiceFs() {
|
|
|
40
41
|
},
|
|
41
42
|
removeFile(path) {
|
|
42
43
|
rmSync(path, { force: true });
|
|
44
|
+
},
|
|
45
|
+
fileExists(path) {
|
|
46
|
+
return existsSync(path);
|
|
43
47
|
}
|
|
44
48
|
};
|
|
45
49
|
}
|
|
@@ -67,13 +71,69 @@ function scopePhrase(plan) {
|
|
|
67
71
|
}
|
|
68
72
|
async function runAll(runner, commands) {
|
|
69
73
|
let firstFailure = null;
|
|
74
|
+
let firstFailureResult = null;
|
|
70
75
|
for (const command of commands) {
|
|
71
76
|
const result = await runner.run(command.command, command.args, { timeoutMs: SERVICE_COMMAND_TIMEOUT_MS });
|
|
72
77
|
if (!result.ok && firstFailure === null) {
|
|
73
78
|
firstFailure = command;
|
|
79
|
+
firstFailureResult = result;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return { allOk: firstFailure === null, firstFailure, firstFailureResult };
|
|
83
|
+
}
|
|
84
|
+
/** Cap how much of a command's own output is ever echoed back in a result message. */
|
|
85
|
+
const MAX_FAILURE_DETAIL_CHARS = 200;
|
|
86
|
+
function lastNonEmptyLine(text) {
|
|
87
|
+
const lines = text
|
|
88
|
+
.split(/\r?\n/)
|
|
89
|
+
.map((line) => line.trim())
|
|
90
|
+
.filter((line) => line !== "");
|
|
91
|
+
return lines.length > 0 ? (lines[lines.length - 1] ?? null) : null;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Reduce a failed {@link CommandResult} to one short, secret-free line worth
|
|
95
|
+
* surfacing to the operator (e.g. "No such process", "Access is denied.").
|
|
96
|
+
* Prefers the runner's own `detail` (a spawn-error message); otherwise falls
|
|
97
|
+
* back to the last non-empty line of stderr, then stdout, since launchctl/
|
|
98
|
+
* systemctl/schtasks all print their real error there. A genuine failure must
|
|
99
|
+
* surface the underlying error rather than a generic "something failed" -
|
|
100
|
+
* that is what lets an operator tell a real problem from a no-op.
|
|
101
|
+
*/
|
|
102
|
+
function describeFailure(result) {
|
|
103
|
+
if (result === null)
|
|
104
|
+
return "unknown error";
|
|
105
|
+
const candidate = result.detail ?? lastNonEmptyLine(result.stderr) ?? lastNonEmptyLine(result.stdout) ?? "unknown error";
|
|
106
|
+
return candidate.length > MAX_FAILURE_DETAIL_CHARS
|
|
107
|
+
? `${candidate.slice(0, MAX_FAILURE_DETAIL_CHARS)}...`
|
|
108
|
+
: candidate;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* True when a failed stop/uninstall command's result indicates the unit was
|
|
112
|
+
* already absent (not currently registered/running) rather than a genuine
|
|
113
|
+
* failure. Each service manager reports "not found" differently; launchd's
|
|
114
|
+
* `ESRCH`-derived exit code (3) is locale-independent so it is checked
|
|
115
|
+
* directly. Every manager additionally falls back to a broad, case-insensitive
|
|
116
|
+
* text match over stdout/stderr/detail. Anything that does not match is
|
|
117
|
+
* conservatively treated as a GENUINE failure (never silently swallowed) -
|
|
118
|
+
* this is the classification M-2 / AC-9 / b-AC-6 depend on.
|
|
119
|
+
*/
|
|
120
|
+
function isAlreadyAbsentFailure(manager, result) {
|
|
121
|
+
if (result === null)
|
|
122
|
+
return false;
|
|
123
|
+
const text = `${result.detail ?? ""} ${result.stderr} ${result.stdout}`.toLowerCase();
|
|
124
|
+
const genericAbsent = /does not exist|cannot find|no such process|not[- ]loaded|could not find|not found/;
|
|
125
|
+
switch (manager) {
|
|
126
|
+
case "launchd":
|
|
127
|
+
return result.code === 3 || genericAbsent.test(text);
|
|
128
|
+
case "systemd":
|
|
129
|
+
return genericAbsent.test(text);
|
|
130
|
+
case "schtasks":
|
|
131
|
+
return genericAbsent.test(text);
|
|
132
|
+
default: {
|
|
133
|
+
const unreachable = manager;
|
|
134
|
+
return unreachable;
|
|
74
135
|
}
|
|
75
136
|
}
|
|
76
|
-
return { allOk: firstFailure === null, firstFailure };
|
|
77
137
|
}
|
|
78
138
|
function withResolvedUnitPath(plan) {
|
|
79
139
|
if (plan.manager !== "schtasks" || plan.unitPath !== "")
|
|
@@ -92,10 +152,36 @@ export function createServiceModule(deps) {
|
|
|
92
152
|
((env) => {
|
|
93
153
|
migrateHiveState({ home: env.home, env: process.env });
|
|
94
154
|
});
|
|
155
|
+
const resolveWindowsUserId = deps.resolveWindowsUserId ?? (() => resolveWindowsUserIdDefault());
|
|
95
156
|
function plan() {
|
|
96
157
|
return resolveServicePlan(environment);
|
|
97
158
|
}
|
|
159
|
+
async function isRegisteredForPlan(resolvedPlan) {
|
|
160
|
+
if (resolvedPlan.manager === "schtasks") {
|
|
161
|
+
const current = await runner.run("schtasks", ["/Query", "/TN", WINDOWS_TASK_NAME], {
|
|
162
|
+
timeoutMs: SERVICE_COMMAND_TIMEOUT_MS
|
|
163
|
+
});
|
|
164
|
+
if (current.ok)
|
|
165
|
+
return true;
|
|
166
|
+
const legacy = await runner.run("schtasks", ["/Query", "/TN", LEGACY_WINDOWS_TASK_NAME], {
|
|
167
|
+
timeoutMs: SERVICE_COMMAND_TIMEOUT_MS
|
|
168
|
+
});
|
|
169
|
+
return legacy.ok;
|
|
170
|
+
}
|
|
171
|
+
if (resolvedPlan.unitPath !== "" && fs.fileExists(resolvedPlan.unitPath))
|
|
172
|
+
return true;
|
|
173
|
+
const legacyPath = legacyUnitPath(resolvedPlan);
|
|
174
|
+
return legacyPath !== "" && fs.fileExists(legacyPath);
|
|
175
|
+
}
|
|
98
176
|
return {
|
|
177
|
+
async isRegistered() {
|
|
178
|
+
try {
|
|
179
|
+
return await isRegisteredForPlan(withResolvedUnitPath(plan()));
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
},
|
|
99
185
|
async install() {
|
|
100
186
|
let resolvedPlan;
|
|
101
187
|
try {
|
|
@@ -125,7 +211,8 @@ export function createServiceModule(deps) {
|
|
|
125
211
|
if (needsUnitFile) {
|
|
126
212
|
try {
|
|
127
213
|
fs.mkdirp(dirname(resolvedPlan.unitPath));
|
|
128
|
-
|
|
214
|
+
const windowsUserId = resolvedPlan.manager === "schtasks" ? await resolveWindowsUserId() : null;
|
|
215
|
+
fs.writeFile(resolvedPlan.unitPath, renderUnit(resolvedPlan, process.env, windowsUserId));
|
|
129
216
|
}
|
|
130
217
|
catch (error) {
|
|
131
218
|
return {
|
|
@@ -146,6 +233,39 @@ export function createServiceModule(deps) {
|
|
|
146
233
|
message: `hive registered as a ${scopePhrase(resolvedPlan)} service and started. It will restart on crash and start on boot/login.`
|
|
147
234
|
};
|
|
148
235
|
},
|
|
236
|
+
async stop() {
|
|
237
|
+
let resolvedPlan;
|
|
238
|
+
try {
|
|
239
|
+
resolvedPlan = withResolvedUnitPath(plan());
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
return {
|
|
243
|
+
ok: false,
|
|
244
|
+
message: `Could not stop hive service: ${error instanceof Error ? error.message : "unknown error"}.`
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
const { allOk, firstFailure, firstFailureResult } = await runAll(runner, stopCommands(resolvedPlan, uid));
|
|
248
|
+
if (!allOk) {
|
|
249
|
+
// M-2 posture applied to stop too: a manager reporting "already not running/
|
|
250
|
+
// loaded" (e.g. a repeat `hive stop`, or launchd having nothing left to boot
|
|
251
|
+
// out) is a friendly no-op, not a failure - there is nothing left to stop
|
|
252
|
+
// either way. A genuine failure still fails honestly with the real detail.
|
|
253
|
+
if (isAlreadyAbsentFailure(resolvedPlan.manager, firstFailureResult)) {
|
|
254
|
+
return {
|
|
255
|
+
ok: true,
|
|
256
|
+
message: `hive service was already stopped (${scopePhrase(resolvedPlan)}).`
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return {
|
|
260
|
+
ok: false,
|
|
261
|
+
message: `A service-manager stop command (${firstFailure?.command ?? "unknown"}) reported an error: ${describeFailure(firstFailureResult)}.`
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
ok: true,
|
|
266
|
+
message: `hive service stopped (${scopePhrase(resolvedPlan)}).`
|
|
267
|
+
};
|
|
268
|
+
},
|
|
149
269
|
async uninstall() {
|
|
150
270
|
let resolvedPlan;
|
|
151
271
|
try {
|
|
@@ -154,25 +274,48 @@ export function createServiceModule(deps) {
|
|
|
154
274
|
catch (error) {
|
|
155
275
|
return {
|
|
156
276
|
ok: false,
|
|
277
|
+
alreadyAbsent: false,
|
|
157
278
|
message: `Could not unregister hive service: ${error instanceof Error ? error.message : "unknown error"}.`
|
|
158
279
|
};
|
|
159
280
|
}
|
|
160
|
-
|
|
281
|
+
// Legacy deregister is best-effort (same posture as install()): it is EXPECTED to fail
|
|
282
|
+
// when no pre-decision-#32 unit exists, so it must never fail the uninstall verdict.
|
|
283
|
+
// Only a current-unit deregister failure may flip `ok` to false.
|
|
284
|
+
await runAll(runner, legacyUninstallCommands(resolvedPlan, uid));
|
|
285
|
+
const { allOk, firstFailure, firstFailureResult } = await runAll(runner, uninstallCommands(resolvedPlan, uid));
|
|
161
286
|
try {
|
|
162
287
|
if (resolvedPlan.unitPath !== "")
|
|
163
288
|
fs.removeFile(resolvedPlan.unitPath);
|
|
289
|
+
const legacyPath = legacyUnitPath(resolvedPlan);
|
|
290
|
+
if (legacyPath !== "")
|
|
291
|
+
fs.removeFile(legacyPath);
|
|
164
292
|
}
|
|
165
293
|
catch {
|
|
166
294
|
// A stale unit file should not block uninstall feedback.
|
|
167
295
|
}
|
|
168
296
|
if (!allOk) {
|
|
297
|
+
// M-2: on macOS, `uninstall` runs stop (launchd `bootout`) before this current-unit
|
|
298
|
+
// `bootout`, so the unit is routinely already gone by the time this call runs - that
|
|
299
|
+
// is a friendly no-op (b-AC-6), not a failure, and must be classified as such rather
|
|
300
|
+
// than flipping the whole verb to exit 1 despite complete success (AC-9). A GENUINE
|
|
301
|
+
// failure (permission denied, manager unreachable, etc.) still fails honestly with
|
|
302
|
+
// the underlying error surfaced.
|
|
303
|
+
if (isAlreadyAbsentFailure(resolvedPlan.manager, firstFailureResult)) {
|
|
304
|
+
return {
|
|
305
|
+
ok: false,
|
|
306
|
+
alreadyAbsent: true,
|
|
307
|
+
message: `hive ${resolvedPlan.manager} unit was already absent (nothing to remove).`
|
|
308
|
+
};
|
|
309
|
+
}
|
|
169
310
|
return {
|
|
170
311
|
ok: false,
|
|
171
|
-
|
|
312
|
+
alreadyAbsent: false,
|
|
313
|
+
message: `Removed hive unit file; a deregister command (${firstFailure?.command ?? "unknown"}) reported an error: ${describeFailure(firstFailureResult)}.`
|
|
172
314
|
};
|
|
173
315
|
}
|
|
174
316
|
return {
|
|
175
317
|
ok: true,
|
|
318
|
+
alreadyAbsent: false,
|
|
176
319
|
message: `hive service unregistered (${scopePhrase(resolvedPlan)}). It will not start on next boot/login.`
|
|
177
320
|
};
|
|
178
321
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,12 @@ import { type ServicePlan } from "./platform.js";
|
|
|
2
2
|
export declare const HIVE_START_COMMAND: "start";
|
|
3
3
|
export declare const RESTART_SEC: 5;
|
|
4
4
|
export declare const WINDOWS_RESTART_INTERVAL: "PT1M";
|
|
5
|
+
/**
|
|
6
|
+
* The task action runs under `conhost.exe --headless` instead of `node.exe` directly, so the
|
|
7
|
+
* scheduled task never pops a visible console window at logon/run (proven empirically: the
|
|
8
|
+
* identical task ran with Last Result 0 and no window under this wrapper).
|
|
9
|
+
*/
|
|
10
|
+
export declare const WINDOWS_CONHOST_COMMAND: "C:\\Windows\\System32\\conhost.exe";
|
|
5
11
|
/**
|
|
6
12
|
* rr-AC-10 / 010a implementation note: when the root resolved at render time differs from the
|
|
7
13
|
* default `<home>/.apiary` (an `APIARY_HOME` or Linux XDG override is active), the installer must
|
|
@@ -24,6 +30,14 @@ export declare function renderSystemdUnit(plan: ServicePlan, env?: NodeJS.Proces
|
|
|
24
30
|
* root at render time, but the task-started daemon resolves the default root unless the operator
|
|
25
31
|
* sets APIARY_HOME machine-wide (setx / system properties). Recorded in PRD-010a implementation
|
|
26
32
|
* notes; hive's Windows service is per-user InteractiveToken only, so no LocalSystem edge exists.
|
|
33
|
+
*
|
|
34
|
+
* `userId` (a SID or a `domain\user` fallback, resolved by the caller and passed in already
|
|
35
|
+
* escaped-ready) scopes the `LogonTrigger` and `Principal` to a concrete identity. An unscoped
|
|
36
|
+
* logon trigger/principal means "any user's logon", which a hardened Windows 11 25H2 machine
|
|
37
|
+
* (Administrator Protection enabled) refuses to register from a non-elevated shell. `null` renders
|
|
38
|
+
* with no `UserId`, matching prior behavior for machines where no identity could be resolved.
|
|
39
|
+
* `UserId` is placed first inside `<Principal>` and after `<Enabled>` inside `<LogonTrigger>` per
|
|
40
|
+
* the Task Scheduler schema's element ordering.
|
|
27
41
|
*/
|
|
28
|
-
export declare function renderScheduledTaskXml(plan: ServicePlan): string;
|
|
29
|
-
export declare function renderUnit(plan: ServicePlan, env?: NodeJS.ProcessEnv): string;
|
|
42
|
+
export declare function renderScheduledTaskXml(plan: ServicePlan, userId?: string | null): string;
|
|
43
|
+
export declare function renderUnit(plan: ServicePlan, env?: NodeJS.ProcessEnv, windowsUserId?: string | null): string;
|
|
@@ -4,6 +4,12 @@ import { resolveFleetRoot, resolveLaunchdLogPaths } from "../shared/apiary-root.
|
|
|
4
4
|
export const HIVE_START_COMMAND = "start";
|
|
5
5
|
export const RESTART_SEC = 5;
|
|
6
6
|
export const WINDOWS_RESTART_INTERVAL = "PT1M";
|
|
7
|
+
/**
|
|
8
|
+
* The task action runs under `conhost.exe --headless` instead of `node.exe` directly, so the
|
|
9
|
+
* scheduled task never pops a visible console window at logon/run (proven empirically: the
|
|
10
|
+
* identical task ran with Last Result 0 and no window under this wrapper).
|
|
11
|
+
*/
|
|
12
|
+
export const WINDOWS_CONHOST_COMMAND = "C:\\Windows\\System32\\conhost.exe";
|
|
7
13
|
/**
|
|
8
14
|
* rr-AC-10 / 010a implementation note: when the root resolved at render time differs from the
|
|
9
15
|
* default `<home>/.apiary` (an `APIARY_HOME` or Linux XDG override is active), the installer must
|
|
@@ -99,10 +105,19 @@ WantedBy=default.target
|
|
|
99
105
|
* root at render time, but the task-started daemon resolves the default root unless the operator
|
|
100
106
|
* sets APIARY_HOME machine-wide (setx / system properties). Recorded in PRD-010a implementation
|
|
101
107
|
* notes; hive's Windows service is per-user InteractiveToken only, so no LocalSystem edge exists.
|
|
108
|
+
*
|
|
109
|
+
* `userId` (a SID or a `domain\user` fallback, resolved by the caller and passed in already
|
|
110
|
+
* escaped-ready) scopes the `LogonTrigger` and `Principal` to a concrete identity. An unscoped
|
|
111
|
+
* logon trigger/principal means "any user's logon", which a hardened Windows 11 25H2 machine
|
|
112
|
+
* (Administrator Protection enabled) refuses to register from a non-elevated shell. `null` renders
|
|
113
|
+
* with no `UserId`, matching prior behavior for machines where no identity could be resolved.
|
|
114
|
+
* `UserId` is placed first inside `<Principal>` and after `<Enabled>` inside `<LogonTrigger>` per
|
|
115
|
+
* the Task Scheduler schema's element ordering.
|
|
102
116
|
*/
|
|
103
|
-
export function renderScheduledTaskXml(plan) {
|
|
117
|
+
export function renderScheduledTaskXml(plan, userId = null) {
|
|
104
118
|
const node = escapeXml(process.execPath);
|
|
105
119
|
const exec = escapeXml(plan.execPath);
|
|
120
|
+
const userIdBlock = userId === null ? "" : `\n <UserId>${escapeXml(userId)}</UserId>`;
|
|
106
121
|
return `<?xml version="1.0" encoding="UTF-16"?>
|
|
107
122
|
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
108
123
|
<RegistrationInfo>
|
|
@@ -111,11 +126,11 @@ export function renderScheduledTaskXml(plan) {
|
|
|
111
126
|
</RegistrationInfo>
|
|
112
127
|
<Triggers>
|
|
113
128
|
<LogonTrigger>
|
|
114
|
-
<Enabled>true</Enabled
|
|
129
|
+
<Enabled>true</Enabled>${userIdBlock}
|
|
115
130
|
</LogonTrigger>
|
|
116
131
|
</Triggers>
|
|
117
132
|
<Principals>
|
|
118
|
-
<Principal id="Author"
|
|
133
|
+
<Principal id="Author">${userIdBlock}
|
|
119
134
|
<LogonType>InteractiveToken</LogonType>
|
|
120
135
|
<RunLevel>LeastPrivilege</RunLevel>
|
|
121
136
|
</Principal>
|
|
@@ -137,21 +152,21 @@ export function renderScheduledTaskXml(plan) {
|
|
|
137
152
|
</Settings>
|
|
138
153
|
<Actions Context="Author">
|
|
139
154
|
<Exec>
|
|
140
|
-
<Command>${
|
|
141
|
-
<Arguments
|
|
155
|
+
<Command>${WINDOWS_CONHOST_COMMAND}</Command>
|
|
156
|
+
<Arguments>--headless "${node}" "${exec}" ${HIVE_START_COMMAND}</Arguments>
|
|
142
157
|
</Exec>
|
|
143
158
|
</Actions>
|
|
144
159
|
</Task>
|
|
145
160
|
`;
|
|
146
161
|
}
|
|
147
|
-
export function renderUnit(plan, env = process.env) {
|
|
162
|
+
export function renderUnit(plan, env = process.env, windowsUserId = null) {
|
|
148
163
|
switch (plan.manager) {
|
|
149
164
|
case "launchd":
|
|
150
165
|
return renderLaunchdPlist(plan, env);
|
|
151
166
|
case "systemd":
|
|
152
167
|
return renderSystemdUnit(plan, env);
|
|
153
168
|
case "schtasks":
|
|
154
|
-
return renderScheduledTaskXml(plan);
|
|
169
|
+
return renderScheduledTaskXml(plan, windowsUserId);
|
|
155
170
|
}
|
|
156
171
|
}
|
|
157
172
|
//# sourceMappingURL=templates.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/service/templates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,iBAAiB,EAAoB,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEpF,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAgB,CAAC;AACnD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAU,CAAC;AACtC,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/service/templates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Matches a Windows SID string such as `S-1-5-21-...-1001`. */
|
|
2
|
+
export declare const WINDOWS_SID_PATTERN: RegExp;
|
|
3
|
+
export interface WhoamiResult {
|
|
4
|
+
readonly ok: boolean;
|
|
5
|
+
readonly stdout: string;
|
|
6
|
+
}
|
|
7
|
+
/** Injectable seam over the `whoami.exe` invocation (hermetic tests mirror production env). */
|
|
8
|
+
export type WhoamiRunner = (executable: string, args: readonly string[]) => Promise<WhoamiResult>;
|
|
9
|
+
/** Injectable seams for Windows identity resolution (hermetic tests mirror production env). */
|
|
10
|
+
export interface WindowsUserIdResolverDeps {
|
|
11
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
12
|
+
readonly runWhoami?: WhoamiRunner;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolves `whoami.exe` under `%SystemRoot%\System32` explicitly (never bare `whoami`
|
|
16
|
+
* on PATH), so a git-bash `whoami` shadowing the real binary on some machines can never
|
|
17
|
+
* be picked up instead.
|
|
18
|
+
*/
|
|
19
|
+
export declare function whoamiExecutablePath(env: NodeJS.ProcessEnv): string;
|
|
20
|
+
/** Real `whoami.exe` runner: execFile, never a shell. */
|
|
21
|
+
export declare function createExecFileWhoamiRunner(): WhoamiRunner;
|
|
22
|
+
/**
|
|
23
|
+
* Parses the SID out of `whoami /user /fo csv /nh` output, e.g.
|
|
24
|
+
* `"domain\user","S-1-5-21-...-1001"`. Takes the last non-empty line (defensive
|
|
25
|
+
* against a stray header row) and the last CSV field, strips surrounding quotes,
|
|
26
|
+
* and validates the shape. Returns `null` on anything that does not look like a SID.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseWhoamiSid(stdout: string): string | null;
|
|
29
|
+
/** `${USERDOMAIN}\${USERNAME}`, or `null` when either is unset/empty. */
|
|
30
|
+
export declare function fallbackWindowsAccount(env: NodeJS.ProcessEnv): string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Resolves the value to embed as the schtasks `LogonTrigger`/`Principal` `UserId`.
|
|
33
|
+
*
|
|
34
|
+
* On a hardened Windows 11 25H2 machine (Administrator Protection enabled), an
|
|
35
|
+
* unscoped `LogonTrigger`/`Principal` (no `UserId`, meaning "any user's logon") is
|
|
36
|
+
* exactly what makes `schtasks /Create` refuse registration from a non-elevated
|
|
37
|
+
* shell with "ERROR: Access is denied." Scoping both elements to a concrete
|
|
38
|
+
* identity is the fix.
|
|
39
|
+
*
|
|
40
|
+
* Resolution order: the current user's SID via `whoami.exe /user /fo csv /nh`
|
|
41
|
+
* (execFile, never a shell); falling back to `${USERDOMAIN}\${USERNAME}` when the
|
|
42
|
+
* SID cannot be determined; falling back to `null` (render with no `UserId`,
|
|
43
|
+
* today's unscoped behavior) when neither is available, so non-hardened machines
|
|
44
|
+
* keep working unchanged.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveWindowsUserId(deps?: WindowsUserIdResolverDeps): Promise<string | null>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { win32 } from "node:path";
|
|
3
|
+
/** Matches a Windows SID string such as `S-1-5-21-...-1001`. */
|
|
4
|
+
export const WINDOWS_SID_PATTERN = /^S-1-\d+(-\d+)+$/;
|
|
5
|
+
/**
|
|
6
|
+
* Resolves `whoami.exe` under `%SystemRoot%\System32` explicitly (never bare `whoami`
|
|
7
|
+
* on PATH), so a git-bash `whoami` shadowing the real binary on some machines can never
|
|
8
|
+
* be picked up instead.
|
|
9
|
+
*/
|
|
10
|
+
export function whoamiExecutablePath(env) {
|
|
11
|
+
return win32.join(env.SystemRoot ?? "C:\\Windows", "System32", "whoami.exe");
|
|
12
|
+
}
|
|
13
|
+
/** Real `whoami.exe` runner: execFile, never a shell. */
|
|
14
|
+
export function createExecFileWhoamiRunner() {
|
|
15
|
+
return (executable, args) => new Promise((resolve) => {
|
|
16
|
+
execFile(executable, [...args], (error, stdout) => {
|
|
17
|
+
resolve({ ok: error === null, stdout });
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Parses the SID out of `whoami /user /fo csv /nh` output, e.g.
|
|
23
|
+
* `"domain\user","S-1-5-21-...-1001"`. Takes the last non-empty line (defensive
|
|
24
|
+
* against a stray header row) and the last CSV field, strips surrounding quotes,
|
|
25
|
+
* and validates the shape. Returns `null` on anything that does not look like a SID.
|
|
26
|
+
*/
|
|
27
|
+
export function parseWhoamiSid(stdout) {
|
|
28
|
+
const line = stdout
|
|
29
|
+
.split(/\r?\n/)
|
|
30
|
+
.map((entry) => entry.trim())
|
|
31
|
+
.filter((entry) => entry !== "")
|
|
32
|
+
.pop();
|
|
33
|
+
if (line === undefined)
|
|
34
|
+
return null;
|
|
35
|
+
const fields = line.split(",");
|
|
36
|
+
const rawLast = fields[fields.length - 1];
|
|
37
|
+
if (rawLast === undefined)
|
|
38
|
+
return null;
|
|
39
|
+
const sid = rawLast.trim().replace(/^"/, "").replace(/"$/, "");
|
|
40
|
+
return WINDOWS_SID_PATTERN.test(sid) ? sid : null;
|
|
41
|
+
}
|
|
42
|
+
/** `${USERDOMAIN}\${USERNAME}`, or `null` when either is unset/empty. */
|
|
43
|
+
export function fallbackWindowsAccount(env) {
|
|
44
|
+
const domain = env.USERDOMAIN;
|
|
45
|
+
const user = env.USERNAME;
|
|
46
|
+
if (domain === undefined || domain === "" || user === undefined || user === "")
|
|
47
|
+
return null;
|
|
48
|
+
return `${domain}\\${user}`;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolves the value to embed as the schtasks `LogonTrigger`/`Principal` `UserId`.
|
|
52
|
+
*
|
|
53
|
+
* On a hardened Windows 11 25H2 machine (Administrator Protection enabled), an
|
|
54
|
+
* unscoped `LogonTrigger`/`Principal` (no `UserId`, meaning "any user's logon") is
|
|
55
|
+
* exactly what makes `schtasks /Create` refuse registration from a non-elevated
|
|
56
|
+
* shell with "ERROR: Access is denied." Scoping both elements to a concrete
|
|
57
|
+
* identity is the fix.
|
|
58
|
+
*
|
|
59
|
+
* Resolution order: the current user's SID via `whoami.exe /user /fo csv /nh`
|
|
60
|
+
* (execFile, never a shell); falling back to `${USERDOMAIN}\${USERNAME}` when the
|
|
61
|
+
* SID cannot be determined; falling back to `null` (render with no `UserId`,
|
|
62
|
+
* today's unscoped behavior) when neither is available, so non-hardened machines
|
|
63
|
+
* keep working unchanged.
|
|
64
|
+
*/
|
|
65
|
+
export async function resolveWindowsUserId(deps = {}) {
|
|
66
|
+
const env = deps.env ?? process.env;
|
|
67
|
+
const runWhoami = deps.runWhoami ?? createExecFileWhoamiRunner();
|
|
68
|
+
const result = await runWhoami(whoamiExecutablePath(env), ["/user", "/fo", "csv", "/nh"]);
|
|
69
|
+
if (result.ok) {
|
|
70
|
+
const sid = parseWhoamiSid(result.stdout);
|
|
71
|
+
if (sid !== null)
|
|
72
|
+
return sid;
|
|
73
|
+
}
|
|
74
|
+
return fallbackWindowsAccount(env);
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=windows-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows-identity.js","sourceRoot":"","sources":["../../src/service/windows-identity.ts"],"names":[],"mappings":"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"}
|