crosscheck-cli 0.0.6 → 0.0.7
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/dist/fingerprint.js +18 -23
- package/dist/fingerprint.js.map +1 -1
- package/dist/keychain.js +23 -16
- package/dist/keychain.js.map +1 -1
- package/package.json +4 -4
package/dist/fingerprint.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Privacy-preserving machine fingerprint.
|
|
2
|
+
* Privacy-preserving machine fingerprint. Hashed with scrypt (Node built-in):
|
|
3
3
|
*
|
|
4
|
-
* fingerprint =
|
|
4
|
+
* fingerprint = scrypt(machine-id || install-uuid || os-platform, fixedSalt)
|
|
5
5
|
*
|
|
6
|
-
* The same
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* The same inputs always produce the same hash (fixed salt). The hash is not
|
|
7
|
+
* reversible to PII — it's only useful as a stable identifier for
|
|
8
|
+
* re-activation flows. NEVER raw MAC address, serial number, or hardware UUID
|
|
9
|
+
* — those are PII and unstable across OS updates.
|
|
10
|
+
*
|
|
11
|
+
* Uses Node's built-in crypto (no native dependency) — the fingerprint is a
|
|
12
|
+
* stable, non-secret identifier the server simply stores, so a slow password
|
|
13
|
+
* KDF (argon2) was unnecessary and added a node-gyp build step.
|
|
10
14
|
*
|
|
11
15
|
* The `installUuid` is generated once at first run and stored in the OS
|
|
12
16
|
* keychain so subsequent invocations on the same install yield the same
|
|
13
17
|
* fingerprint even if the machine-id rotates.
|
|
14
18
|
*/
|
|
15
|
-
import { randomUUID } from "node:crypto";
|
|
19
|
+
import { randomUUID, scryptSync } from "node:crypto";
|
|
16
20
|
import { readFileSync, existsSync } from "node:fs";
|
|
17
21
|
import { execSync } from "node:child_process";
|
|
18
|
-
import * as argon2 from "argon2";
|
|
19
22
|
import { getSecret, setSecret } from "./keychain.js";
|
|
20
23
|
const INSTALL_UUID_KEY = "installUuid";
|
|
21
|
-
const FIXED_SALT = Buffer.from("
|
|
24
|
+
const FIXED_SALT = Buffer.from("crosscheck-fp-v1-salt-2026", "utf8");
|
|
22
25
|
export function detectPlatform() {
|
|
23
26
|
const p = process.platform;
|
|
24
27
|
if (p === "darwin" || p === "linux" || p === "win32")
|
|
@@ -68,25 +71,17 @@ export function getMachineId() {
|
|
|
68
71
|
return `${platform}:${process.env.HOSTNAME ?? "unknown"}`;
|
|
69
72
|
}
|
|
70
73
|
/**
|
|
71
|
-
* Compute the fingerprint hash.
|
|
72
|
-
*
|
|
74
|
+
* Compute the fingerprint hash. scrypt with the fixed salt so the result is
|
|
75
|
+
* deterministic for the same machine and the server can just store the string.
|
|
73
76
|
*/
|
|
74
77
|
export async function computeFingerprintHash() {
|
|
75
78
|
const machineId = getMachineId();
|
|
76
79
|
const installUuid = await getOrCreateInstallUuid();
|
|
77
80
|
const platform = detectPlatform();
|
|
78
81
|
const input = `${machineId}|${installUuid}|${platform}`;
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
const hash =
|
|
82
|
-
|
|
83
|
-
salt: FIXED_SALT,
|
|
84
|
-
timeCost: 3,
|
|
85
|
-
memoryCost: 32 * 1024,
|
|
86
|
-
parallelism: 1,
|
|
87
|
-
raw: true,
|
|
88
|
-
hashLength: 32,
|
|
89
|
-
});
|
|
90
|
-
return Buffer.from(hash).toString("hex");
|
|
82
|
+
// 32-byte scrypt output → 64 hex chars (well within the server's
|
|
83
|
+
// varchar(128) fingerprint column). One-shot at activation time.
|
|
84
|
+
const hash = scryptSync(input, FIXED_SALT, 32);
|
|
85
|
+
return hash.toString("hex");
|
|
91
86
|
}
|
|
92
87
|
//# sourceMappingURL=fingerprint.js.map
|
package/dist/fingerprint.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"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"}
|
package/dist/keychain.js
CHANGED
|
@@ -1,34 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OS keychain abstraction.
|
|
2
|
+
* OS keychain abstraction. Backed by `@napi-rs/keyring` (Rust / N-API) which
|
|
3
|
+
* ships prebuilt binaries for every platform — no node-gyp, no Python, no
|
|
4
|
+
* compile step at install time:
|
|
3
5
|
* - macOS: Keychain
|
|
4
6
|
* - Windows: Credential Manager
|
|
5
|
-
* - Linux:
|
|
7
|
+
* - Linux: Secret Service (GNOME Keyring / KWallet via libsecret)
|
|
6
8
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
+
* The functions stay async so call sites don't change, even though the
|
|
10
|
+
* underlying API is synchronous.
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
+
* On headless environments without a system keyring (some CI / containers),
|
|
13
|
+
* the keyring calls throw; a future encrypted-file fallback under
|
|
14
|
+
* ~/.config/crosscheck/ is tracked as a TODO. Keys never leave the local
|
|
15
|
+
* machine either way — only the storage form would differ.
|
|
12
16
|
*/
|
|
13
|
-
import
|
|
17
|
+
import { Entry, findCredentials } from "@napi-rs/keyring";
|
|
14
18
|
import { KEYCHAIN_SERVICE } from "./config.js";
|
|
15
19
|
export async function setSecret(name, value) {
|
|
16
|
-
|
|
17
|
-
// environments where keytar can't talk to a system keyring (CI, some
|
|
18
|
-
// headless Linux containers). For v1 we assume a working keychain.
|
|
19
|
-
await keytar.setPassword(KEYCHAIN_SERVICE, name, value);
|
|
20
|
+
new Entry(KEYCHAIN_SERVICE, name).setPassword(value);
|
|
20
21
|
}
|
|
21
22
|
export async function getSecret(name) {
|
|
22
|
-
return
|
|
23
|
+
return new Entry(KEYCHAIN_SERVICE, name).getPassword();
|
|
23
24
|
}
|
|
24
25
|
export async function deleteSecret(name) {
|
|
25
|
-
|
|
26
|
+
try {
|
|
27
|
+
return new Entry(KEYCHAIN_SERVICE, name).deletePassword();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// No such entry — treat as a no-op delete.
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
26
33
|
}
|
|
27
34
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
35
|
+
* List every Crosscheck-owned credential. Used by `crosscheck keys list` and
|
|
36
|
+
* by deactivation to wipe everything in one pass.
|
|
30
37
|
*/
|
|
31
38
|
export async function listSecrets() {
|
|
32
|
-
return
|
|
39
|
+
return findCredentials(KEYCHAIN_SERVICE);
|
|
33
40
|
}
|
|
34
41
|
//# sourceMappingURL=keychain.js.map
|
package/dist/keychain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keychain.js","sourceRoot":"","sources":["../src/keychain.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"keychain.js","sourceRoot":"","sources":["../src/keychain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,KAAa;IACzD,IAAI,KAAK,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAY;IAC1C,OAAO,IAAI,KAAK,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;AACzD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY;IAC7C,IAAI,CAAC;QACH,OAAO,IAAI,KAAK,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC,cAAc,EAAE,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,2CAA2C;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAG/B,OAAO,eAAe,CAAC,gBAAgB,CAAC,CAAC;AAC3C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crosscheck-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Crosscheck — multi-LLM orchestration MCP for the terminal. Single-machine activation, BYO upstream LLM keys, content-free telemetry. Installs into Claude Code in one command.",
|
|
5
5
|
"license": "SEE LICENSE.md",
|
|
6
6
|
"type": "module",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
"dev": "tsx src/cli.ts",
|
|
24
24
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
25
25
|
"test": "vitest run",
|
|
26
|
-
"lint": "tsc -p tsconfig.json --noEmit"
|
|
26
|
+
"lint": "tsc -p tsconfig.json --noEmit",
|
|
27
|
+
"prepublishOnly": "npm run build"
|
|
27
28
|
},
|
|
28
29
|
"dependencies": {
|
|
29
30
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
30
|
-
"
|
|
31
|
+
"@napi-rs/keyring": "^1.3.0",
|
|
31
32
|
"crosscheck-mcp": "^0.1.0",
|
|
32
|
-
"keytar": "^7.9.0",
|
|
33
33
|
"undici": "^7.0.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|