@hivefloor/cli 0.1.3 → 0.1.5
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/LICENSE +1 -1
- package/README.md +2 -1
- package/dist/{chunk-HT5KXWXM.js → chunk-3N5JYP5O.js} +7 -3
- package/dist/{chunk-TH4ANHSG.js → chunk-4DRHR7LR.js} +365 -129
- package/dist/{chunk-DQV6FAJU.js → chunk-6MDJB3BV.js} +97 -26
- package/dist/{chunk-NLZXB26Y.js → chunk-6XVIEX75.js} +293 -71
- package/dist/{chunk-KHHSRIMU.js → chunk-C627OKTW.js} +2 -2
- package/dist/chunk-H6NYMF2D.js +50 -0
- package/dist/{chunk-T7TG6WA4.js → chunk-IJRHCDIG.js} +1 -1
- package/dist/{chunk-3YOTXIFP.js → chunk-IWIDKNWC.js} +109 -29
- package/dist/{chunk-E4V47VEV.js → chunk-J36OIJBM.js} +41 -23
- package/dist/{chunk-O6VSA2JT.js → chunk-MZGGJ6ZS.js} +87 -13
- package/dist/{chunk-YRNMECUF.js → chunk-RYGL6XU4.js} +5 -3
- package/dist/chunk-SOXRITAW.js +139 -0
- package/dist/{chunk-VNCQFFQO.js → chunk-TPMFQUAW.js} +102 -1
- package/dist/chunk-U6RRUAC2.js +229 -0
- package/dist/chunk-VX7SCIF2.js +65 -0
- package/dist/{chunk-O2TC3WSS.js → chunk-X6B6R32A.js} +1 -1
- package/dist/cli-JCBZICR3.js +243 -0
- package/dist/connect-2HLVPEOL.js +23 -0
- package/dist/{disconnect-FI76IEZJ.js → disconnect-WQMDCUXT.js} +41 -27
- package/dist/{hook-N4ZTQEWM.js → hook-AYJNRGIY.js} +25 -9
- package/dist/index.js +2 -2
- package/dist/{link-5WSZHKBE.js → link-ORT4LID6.js} +29 -16
- package/dist/{machine-connect-GQJ4SB3D.js → machine-connect-N52CKQEW.js} +21 -21
- package/dist/{mcp-EUBTVJNX.js → mcp-2SF6Y73M.js} +27 -30
- package/dist/{run-BEE2ATEM.js → run-ZAZ45MKQ.js} +22 -10
- package/dist/{status-SMAVPW4D.js → status-GOCFNO7K.js} +25 -13
- package/dist/{token-AUEAWQDH.js → token-EMM4AJAU.js} +15 -6
- package/dist/voice-F5MIS3IZ.js +262 -0
- package/dist/{where-7NI7UEEF.js → where-XFXRTP7E.js} +16 -7
- package/package.json +2 -2
- package/dist/chunk-2IMJECYD.js +0 -71
- package/dist/chunk-DWHMBUCA.js +0 -30
- package/dist/chunk-NKMVO5BP.js +0 -132
- package/dist/chunk-PY74LT2W.js +0 -41
- package/dist/cli-MAHYTCYV.js +0 -103
- package/dist/connect-QA3QIEGL.js +0 -23
|
@@ -8,11 +8,15 @@ import {
|
|
|
8
8
|
isRecord,
|
|
9
9
|
readText,
|
|
10
10
|
removeFile
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-TPMFQUAW.js";
|
|
12
12
|
import {
|
|
13
|
-
|
|
14
|
-
runCmd
|
|
15
|
-
|
|
13
|
+
normalizeHost,
|
|
14
|
+
runCmd,
|
|
15
|
+
sameOrigin
|
|
16
|
+
} from "./chunk-SOXRITAW.js";
|
|
17
|
+
import {
|
|
18
|
+
cliNpxCommand
|
|
19
|
+
} from "./chunk-4DRHR7LR.js";
|
|
16
20
|
|
|
17
21
|
// src/service/units.ts
|
|
18
22
|
import os from "os";
|
|
@@ -215,8 +219,13 @@ async function uninstallService(svc, run, uid) {
|
|
|
215
219
|
}
|
|
216
220
|
|
|
217
221
|
// src/credentials.ts
|
|
222
|
+
import { createHash } from "crypto";
|
|
218
223
|
import fs from "fs";
|
|
219
|
-
var
|
|
224
|
+
var KEYCHAIN_SERVICE = "hivefloor";
|
|
225
|
+
var TOKEN_FP_HEX = 16;
|
|
226
|
+
function tokenFingerprint(token) {
|
|
227
|
+
return createHash("sha256").update(token, "utf8").digest("hex").slice(0, TOKEN_FP_HEX);
|
|
228
|
+
}
|
|
220
229
|
var realKeyring = async () => {
|
|
221
230
|
if (process.env.HIVEFLOOR_KEYRING === "0") return void 0;
|
|
222
231
|
try {
|
|
@@ -227,6 +236,19 @@ var realKeyring = async () => {
|
|
|
227
236
|
};
|
|
228
237
|
var loadKeyring = realKeyring;
|
|
229
238
|
var account = (host, tool) => `${host}#${tool}`;
|
|
239
|
+
function canonicalHost(host) {
|
|
240
|
+
try {
|
|
241
|
+
return normalizeHost(host);
|
|
242
|
+
} catch {
|
|
243
|
+
return void 0;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function hostKey(creds, host) {
|
|
247
|
+
const want = canonicalHost(host);
|
|
248
|
+
if (want === void 0) return creds.hosts[host] ? host : void 0;
|
|
249
|
+
if (creds.hosts[want]) return want;
|
|
250
|
+
return Object.keys(creds.hosts).find((k) => k === want || sameOrigin(k, want));
|
|
251
|
+
}
|
|
230
252
|
function readCredentials() {
|
|
231
253
|
const text = readText(credentialsFile());
|
|
232
254
|
const empty = { version: 1, hosts: {} };
|
|
@@ -256,33 +278,53 @@ function writeCredentials(c) {
|
|
|
256
278
|
}
|
|
257
279
|
atomicWrite(file, JSON.stringify(c, null, 2) + "\n", 384);
|
|
258
280
|
}
|
|
281
|
+
var windowsAclError = () => new Error("could not restrict the Hivefloor config to your Windows user with icacls; the token was not kept");
|
|
259
282
|
async function secureWindowsCredentials(run, username) {
|
|
260
283
|
if (!username) throw new Error("could not determine the Windows user; the token was not kept");
|
|
261
284
|
const dir = prepareConfigDir();
|
|
262
285
|
const d = await run("icacls", [dir, "/inheritance:r", "/grant:r", `${username}:(OI)(CI)F`]);
|
|
263
|
-
if (d.code !== 0) throw
|
|
286
|
+
if (d.code !== 0) throw windowsAclError();
|
|
287
|
+
}
|
|
288
|
+
async function secureWindowsCredentialsFile(run, username) {
|
|
289
|
+
const f = await run("icacls", [credentialsFile(), "/inheritance:r", "/grant:r", `${username}:F`]);
|
|
290
|
+
if (f.code !== 0) throw windowsAclError();
|
|
264
291
|
}
|
|
265
292
|
async function saveToken(host, tool, token, meta = {}, opts = {}) {
|
|
266
293
|
const creds = readCredentials();
|
|
267
|
-
const
|
|
294
|
+
const key = hostKey(creds, host) ?? canonicalHost(host) ?? host;
|
|
295
|
+
const h = creds.hosts[key] ??= { tools: {} };
|
|
268
296
|
let storage = "file";
|
|
269
297
|
const kr = await loadKeyring();
|
|
270
298
|
if (kr) {
|
|
271
299
|
try {
|
|
272
|
-
const entry = new kr.Entry(
|
|
300
|
+
const entry = new kr.Entry(KEYCHAIN_SERVICE, account(key, tool));
|
|
273
301
|
entry.setPassword(token);
|
|
274
302
|
if (entry.getPassword() === token) storage = "keychain";
|
|
275
303
|
} catch {
|
|
276
304
|
storage = "file";
|
|
277
305
|
}
|
|
278
306
|
}
|
|
279
|
-
|
|
280
|
-
|
|
307
|
+
const winFile = storage === "file" && (opts.platform ?? process.platform) === "win32";
|
|
308
|
+
const run = opts.run ?? runCmd;
|
|
309
|
+
const username = opts.username ?? windowsUser(process.env);
|
|
310
|
+
if (winFile) {
|
|
311
|
+
await secureWindowsCredentials(run, username);
|
|
281
312
|
}
|
|
313
|
+
const previous = winFile ? readText(credentialsFile()) : void 0;
|
|
282
314
|
h.tools[tool] = { ...storage === "keychain" ? { keychain: true } : { token }, ...meta, saved_at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
283
315
|
h.last_tool = tool;
|
|
284
|
-
|
|
316
|
+
h.token_fp = tokenFingerprint(token);
|
|
317
|
+
creds.default_host = key;
|
|
285
318
|
writeCredentials(creds);
|
|
319
|
+
if (winFile) {
|
|
320
|
+
try {
|
|
321
|
+
await secureWindowsCredentialsFile(run, username);
|
|
322
|
+
} catch (e) {
|
|
323
|
+
if (previous === void 0) fs.rmSync(credentialsFile(), { force: true });
|
|
324
|
+
else atomicWrite(credentialsFile(), previous, 384);
|
|
325
|
+
throw e;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
286
328
|
return storage;
|
|
287
329
|
}
|
|
288
330
|
function pickTool(h, tool) {
|
|
@@ -291,8 +333,10 @@ function pickTool(h, tool) {
|
|
|
291
333
|
return Object.keys(h.tools)[0];
|
|
292
334
|
}
|
|
293
335
|
async function loadToken(host, tool) {
|
|
294
|
-
const
|
|
295
|
-
|
|
336
|
+
const creds = readCredentials();
|
|
337
|
+
const key = hostKey(creds, host);
|
|
338
|
+
const h = key ? creds.hosts[key] : void 0;
|
|
339
|
+
if (!key || !h) return void 0;
|
|
296
340
|
const t = pickTool(h, tool);
|
|
297
341
|
const c = t ? h.tools[t] : void 0;
|
|
298
342
|
if (!t || !c) return void 0;
|
|
@@ -301,7 +345,7 @@ async function loadToken(host, tool) {
|
|
|
301
345
|
const kr = await loadKeyring();
|
|
302
346
|
if (!kr) return void 0;
|
|
303
347
|
try {
|
|
304
|
-
const v = new kr.Entry(
|
|
348
|
+
const v = new kr.Entry(KEYCHAIN_SERVICE, account(key, t)).getPassword();
|
|
305
349
|
if (v) return { token: v, tool: t };
|
|
306
350
|
} catch {
|
|
307
351
|
}
|
|
@@ -312,34 +356,57 @@ function defaultHost() {
|
|
|
312
356
|
const c = readCredentials();
|
|
313
357
|
return c.default_host && c.hosts[c.default_host] ? c.default_host : Object.keys(c.hosts)[0];
|
|
314
358
|
}
|
|
359
|
+
function deletedKeychainEntry(kr, host, tool) {
|
|
360
|
+
try {
|
|
361
|
+
const e = new kr.Entry(KEYCHAIN_SERVICE, account(host, tool));
|
|
362
|
+
let dropped;
|
|
363
|
+
if (e.deletePassword) dropped = e.deletePassword();
|
|
364
|
+
else if (e.deleteCredential) dropped = e.deleteCredential();
|
|
365
|
+
else return false;
|
|
366
|
+
if (dropped !== false) return true;
|
|
367
|
+
try {
|
|
368
|
+
const still = e.getPassword();
|
|
369
|
+
return still === null || still === void 0;
|
|
370
|
+
} catch {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
} catch {
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
315
377
|
async function deleteCredentials(host, tool) {
|
|
316
378
|
const creds = readCredentials();
|
|
317
379
|
const kr = await loadKeyring();
|
|
318
|
-
let
|
|
380
|
+
let removed = 0;
|
|
381
|
+
const leftover = [];
|
|
319
382
|
for (const [h, hc] of Object.entries(creds.hosts)) {
|
|
320
|
-
if (host && h !== host) continue;
|
|
383
|
+
if (host && h !== host && !sameOrigin(h, host)) continue;
|
|
384
|
+
let removedHere = 0;
|
|
321
385
|
for (const [t, c] of Object.entries(hc.tools)) {
|
|
322
386
|
if (tool && t !== tool) continue;
|
|
323
|
-
if (c.keychain && kr) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
if (e.deletePassword) e.deletePassword();
|
|
327
|
-
else e.deleteCredential?.();
|
|
328
|
-
} catch {
|
|
329
|
-
}
|
|
387
|
+
if (c.keychain && !(kr && deletedKeychainEntry(kr, h, t))) {
|
|
388
|
+
leftover.push(account(h, t));
|
|
389
|
+
continue;
|
|
330
390
|
}
|
|
331
391
|
delete hc.tools[t];
|
|
332
|
-
|
|
392
|
+
removed += 1;
|
|
393
|
+
removedHere += 1;
|
|
333
394
|
}
|
|
395
|
+
if (removedHere === 0) continue;
|
|
334
396
|
if (hc.last_tool && !hc.tools[hc.last_tool]) hc.last_tool = Object.keys(hc.tools)[0];
|
|
335
397
|
if (Object.keys(hc.tools).length === 0) delete creds.hosts[h];
|
|
398
|
+
else {
|
|
399
|
+
const last = hc.last_tool ? hc.tools[hc.last_tool] : void 0;
|
|
400
|
+
if (last?.token) hc.token_fp = tokenFingerprint(last.token);
|
|
401
|
+
else delete hc.token_fp;
|
|
402
|
+
}
|
|
336
403
|
}
|
|
337
404
|
if (creds.default_host && !creds.hosts[creds.default_host]) creds.default_host = Object.keys(creds.hosts)[0];
|
|
338
|
-
if (
|
|
405
|
+
if (removed > 0) {
|
|
339
406
|
if (Object.keys(creds.hosts).length === 0) fs.rmSync(credentialsFile(), { force: true });
|
|
340
407
|
else writeCredentials(creds);
|
|
341
408
|
}
|
|
342
|
-
return
|
|
409
|
+
return { removed, leftover };
|
|
343
410
|
}
|
|
344
411
|
|
|
345
412
|
export {
|
|
@@ -348,6 +415,10 @@ export {
|
|
|
348
415
|
installService,
|
|
349
416
|
windowsServiceStatus,
|
|
350
417
|
uninstallService,
|
|
418
|
+
KEYCHAIN_SERVICE,
|
|
419
|
+
TOKEN_FP_HEX,
|
|
420
|
+
tokenFingerprint,
|
|
421
|
+
hostKey,
|
|
351
422
|
readCredentials,
|
|
352
423
|
saveToken,
|
|
353
424
|
loadToken,
|