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.
@@ -1,24 +1,27 @@
1
1
  /**
2
- * Privacy-preserving machine fingerprint. Argon2id-hashed:
2
+ * Privacy-preserving machine fingerprint. Hashed with scrypt (Node built-in):
3
3
  *
4
- * fingerprint = argon2id(machine-id || install-uuid || os-platform)
4
+ * fingerprint = scrypt(machine-id || install-uuid || os-platform, fixedSalt)
5
5
  *
6
- * The same fingerprint inputs always produce the same hash (deterministic
7
- * salt). The hash is not reversible to PII — it's only useful as a stable
8
- * identifier for re-activation flows. NEVER raw MAC address, serial number,
9
- * or hardware UUID — those are PII and unstable across OS updates.
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("vardr.crosscheck-fp-v1-salt-2026", "utf8");
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. Argon2id with the fixed salt so the server
72
- * doesn't need to know the inputs to verify.
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
- // Argon2id with modest parameters fingerprinting is one-shot at install
80
- // time so the cost only matters once.
81
- const hash = await argon2.hash(input, {
82
- type: argon2.argon2id,
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
@@ -1 +1 @@
1
- {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"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"}
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. Uses `keytar` on every platform:
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: libsecret (GNOME Keyring / KWallet)
7
+ * - Linux: Secret Service (GNOME Keyring / KWallet via libsecret)
6
8
  *
7
- * On unsupported environments (CI, headless Linux without a keyring), falls
8
- * back to an Argon2id-encrypted file under ~/.config/crosscheck/.
9
+ * The functions stay async so call sites don't change, even though the
10
+ * underlying API is synchronous.
9
11
  *
10
- * The fallback path is documented in the EULA: keys never leave the local
11
- * machine, only their storage form differs.
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 keytar from "keytar";
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
- // TODO(phase-3.5): implement Argon2id-encrypted file fallback for
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 await keytar.getPassword(KEYCHAIN_SERVICE, name);
23
+ return new Entry(KEYCHAIN_SERVICE, name).getPassword();
23
24
  }
24
25
  export async function deleteSecret(name) {
25
- return await keytar.deletePassword(KEYCHAIN_SERVICE, name);
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
- * Convenience: list every Crosscheck (XC)-owned credential. Used by `crosscheck
29
- * keys list` and by deactivation to wipe everything in one pass.
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 await keytar.findCredentials(KEYCHAIN_SERVICE);
39
+ return findCredentials(KEYCHAIN_SERVICE);
33
40
  }
34
41
  //# sourceMappingURL=keychain.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keychain.js","sourceRoot":"","sources":["../src/keychain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,KAAa;IACzD,kEAAkE;IAClE,qEAAqE;IACrE,mEAAmE;IACnE,MAAM,MAAM,CAAC,WAAW,CAAC,gBAAgB,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAY;IAC1C,OAAO,MAAM,MAAM,CAAC,WAAW,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY;IAC7C,OAAO,MAAM,MAAM,CAAC,cAAc,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAG/B,OAAO,MAAM,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC;AACxD,CAAC"}
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.6",
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
- "argon2": "^0.41.0",
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": {