@lifeaitools/clauth 1.30.23 → 1.30.24

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.
Files changed (40) hide show
  1. package/.clauth-skill/SKILL.md +111 -111
  2. package/README.md +25 -0
  3. package/cli/api.classify.test.js +75 -75
  4. package/cli/assets/codevelop/launcher-active.cmd.template +20 -20
  5. package/cli/assets/codevelop/launcher-static.cmd.template +7 -7
  6. package/cli/assets/codevelop/windows-terminal.profiles.json +48 -48
  7. package/cli/assets/watchdog.ps1 +42 -42
  8. package/cli/commands/agent-cron.js +396 -396
  9. package/cli/commands/agent-pool.js +1962 -1962
  10. package/cli/commands/codevelop.js +1190 -1190
  11. package/cli/commands/doctor.js +302 -302
  12. package/cli/commands/install.js +10 -10
  13. package/cli/commands/invite.js +175 -175
  14. package/cli/commands/join.js +179 -179
  15. package/cli/commands/npm.js +182 -182
  16. package/cli/commands/scrub.js +327 -327
  17. package/cli/commands/scrub.test.js +115 -115
  18. package/cli/commands/serve.js +41 -95
  19. package/cli/commands/watchdog.js +209 -209
  20. package/cli/conf-path.js +21 -21
  21. package/cli/enrollment-script.js +82 -82
  22. package/cli/fingerprint.js +143 -143
  23. package/cli/index.js +1053 -1053
  24. package/cli/lib/fs-git.js +282 -282
  25. package/cli/recovery.js +101 -101
  26. package/cli/studio-debug.js +1095 -1095
  27. package/cli/supervisor-registry.js +594 -589
  28. package/cli/supervisor-registry.test.js +397 -397
  29. package/cli/supervisor-ui.test.js +5 -83
  30. package/cli/watchdog-registry.js +209 -209
  31. package/cli/watchdog-registry.test.js +89 -89
  32. package/install.ps1 +21 -21
  33. package/package.json +2 -2
  34. package/scripts/bin/bootstrap-linux +0 -0
  35. package/scripts/bin/bootstrap-macos +0 -0
  36. package/scripts/bin/bootstrap-win.exe +0 -0
  37. package/supabase/migrations/001_clauth_schema.sql +12 -12
  38. package/supabase/migrations/003_clauth_config.sql +13 -13
  39. package/supabase/migrations/003_machine_enrollments.sql +39 -39
  40. package/cli/served-script-syntax.test.mjs +0 -54
@@ -1,143 +1,143 @@
1
- // cli/fingerprint.js
2
- // Collects stable hardware identifiers and derives HMAC tokens
3
- // Works on Windows (primary) + Linux/macOS (fallback)
4
-
5
- import { execSync } from "child_process";
6
- import { createHmac, createHash } from "crypto";
7
- import os from "os";
8
- import fs from "fs";
9
- import path from "path";
10
-
11
- // ============================================================
12
- // Machine ID collection
13
- // ============================================================
14
-
15
- // Cache path — avoids re-querying WMI/CIM on every daemon start.
16
- // This eliminates the spawnSync cmd.exe ETIMEDOUT crash that occurs
17
- // when PowerShell/WMI is slow on first call after boot.
18
- const CACHE_FILE = path.join(os.tmpdir(), "clauth-machine.cache");
19
-
20
- function readCache() {
21
- try {
22
- const raw = fs.readFileSync(CACHE_FILE, "utf8").trim();
23
- // Validate: must be two non-empty lines (primary:secondary)
24
- const [primary, secondary] = raw.split("\n");
25
- if (primary && secondary) return { primary: primary.trim(), secondary: secondary.trim() };
26
- } catch { /* cache miss */ }
27
- return null;
28
- }
29
-
30
- function writeCache(primary, secondary) {
31
- try { fs.writeFileSync(CACHE_FILE, `${primary}\n${secondary}`, "utf8"); } catch { /* best effort */ }
32
- }
33
-
34
- function getMachineId() {
35
- // Containers do not have a durable /etc/machine-id. Coolify supplies this
36
- // value as a private runtime secret so a redeploy remains the same enrolled
37
- // clauth machine. Accept the lowercase-dash form used by Coolify too.
38
- const containerMachineId = process.env.CLAUTH_MACHINE_ID || process.env["clauth-machine-id"];
39
- if (containerMachineId) {
40
- const value = containerMachineId.trim();
41
- if (!value) throw new Error("CLAUTH_MACHINE_ID must not be empty");
42
- return { primary: value, secondary: value, platform: os.platform() };
43
- }
44
-
45
- // Fast path: use cached IDs if available (avoids WMI/PowerShell on every restart)
46
- const cached = readCache();
47
- if (cached) return { ...cached, platform: os.platform() };
48
-
49
- const platform = os.platform();
50
-
51
- try {
52
- if (platform === "win32") {
53
- const psPath = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
54
- // Increased timeout to 15s — CimInstance/WMI can be slow after boot or under load.
55
- // Each call is wrapped independently so a partial failure still yields a result.
56
- let uuid = "";
57
- try {
58
- uuid = execSync(
59
- `${psPath} -NoProfile -Command "(Get-CimInstance Win32_ComputerSystemProduct).UUID"`,
60
- { encoding: "utf8", timeout: 15000, stdio: ["pipe", "pipe", "pipe"] }
61
- ).trim();
62
- } catch { /* fall through to registry-only path */ }
63
-
64
- let machineGuid = "";
65
- try {
66
- machineGuid = execSync(
67
- `${psPath} -NoProfile -Command "(Get-ItemProperty 'HKLM:\\SOFTWARE\\Microsoft\\Cryptography').MachineGuid"`,
68
- { encoding: "utf8", timeout: 15000, stdio: ["pipe", "pipe", "pipe"] }
69
- ).trim();
70
- } catch { /* fall through */ }
71
-
72
- // Require at least one identifier
73
- if (!uuid && !machineGuid) throw new Error("Could not read any Windows machine ID");
74
-
75
- // Use hostname as fallback secondary if registry query failed
76
- const primary = uuid || machineGuid;
77
- const secondary = machineGuid || os.hostname();
78
-
79
- writeCache(primary, secondary);
80
- return { primary, secondary, platform: "win32" };
81
- }
82
-
83
- if (platform === "darwin") {
84
- const uuid = execSync(
85
- "ioreg -rd1 -c IOPlatformExpertDevice | awk '/IOPlatformUUID/ { print $3 }'",
86
- { encoding: "utf8", timeout: 5000, stdio: ["pipe", "pipe", "pipe"] }
87
- ).replace(/['"]/g, "").trim();
88
- writeCache(uuid, os.hostname());
89
- return { primary: uuid, secondary: os.hostname(), platform: "darwin" };
90
- }
91
-
92
- // Linux
93
- let uuid = "";
94
- try { uuid = execSync("cat /etc/machine-id", { encoding: "utf8", timeout: 2000 }).trim(); }
95
- catch { uuid = execSync("cat /var/lib/dbus/machine-id", { encoding: "utf8", timeout: 2000 }).trim(); }
96
- writeCache(uuid, os.hostname());
97
- return { primary: uuid, secondary: os.hostname(), platform: "linux" };
98
-
99
- } catch (err) {
100
- throw new Error(`Machine ID collection failed: ${err.message}`);
101
- }
102
- }
103
-
104
- // ============================================================
105
- // Derive stable machine hash (what gets stored in Supabase)
106
- // ============================================================
107
-
108
- export function getMachineHash() {
109
- const { primary, secondary } = getMachineId();
110
- return createHash("sha256")
111
- .update(`${primary}:${secondary}`)
112
- .digest("hex");
113
- }
114
-
115
- // ============================================================
116
- // Derive HMAC token for a given password + timestamp
117
- // ============================================================
118
-
119
- export function deriveToken(password, machineHash) {
120
- const windowMs = 5 * 60 * 1000;
121
- const window = Math.floor(Date.now() / windowMs);
122
- const message = `${machineHash}:${window}`;
123
-
124
- // Server reconstructs this — password + CLAUTH_HMAC_SALT
125
- // Client sends token; server adds its SALT to the password before verifying
126
- const token = createHmac("sha256", password)
127
- .update(message)
128
- .digest("hex");
129
-
130
- return { token, timestamp: window * windowMs, machineHash };
131
- }
132
-
133
- // ============================================================
134
- // Derive HMAC seed hash (stored during machine registration)
135
- // ============================================================
136
-
137
- export function deriveSeedHash(machineHash, password) {
138
- return createHash("sha256")
139
- .update(`seed:${machineHash}:${password}`)
140
- .digest("hex");
141
- }
142
-
143
- export default { getMachineHash, deriveToken, deriveSeedHash };
1
+ // cli/fingerprint.js
2
+ // Collects stable hardware identifiers and derives HMAC tokens
3
+ // Works on Windows (primary) + Linux/macOS (fallback)
4
+
5
+ import { execSync } from "child_process";
6
+ import { createHmac, createHash } from "crypto";
7
+ import os from "os";
8
+ import fs from "fs";
9
+ import path from "path";
10
+
11
+ // ============================================================
12
+ // Machine ID collection
13
+ // ============================================================
14
+
15
+ // Cache path — avoids re-querying WMI/CIM on every daemon start.
16
+ // This eliminates the spawnSync cmd.exe ETIMEDOUT crash that occurs
17
+ // when PowerShell/WMI is slow on first call after boot.
18
+ const CACHE_FILE = path.join(os.tmpdir(), "clauth-machine.cache");
19
+
20
+ function readCache() {
21
+ try {
22
+ const raw = fs.readFileSync(CACHE_FILE, "utf8").trim();
23
+ // Validate: must be two non-empty lines (primary:secondary)
24
+ const [primary, secondary] = raw.split("\n");
25
+ if (primary && secondary) return { primary: primary.trim(), secondary: secondary.trim() };
26
+ } catch { /* cache miss */ }
27
+ return null;
28
+ }
29
+
30
+ function writeCache(primary, secondary) {
31
+ try { fs.writeFileSync(CACHE_FILE, `${primary}\n${secondary}`, "utf8"); } catch { /* best effort */ }
32
+ }
33
+
34
+ function getMachineId() {
35
+ // Containers do not have a durable /etc/machine-id. Coolify supplies this
36
+ // value as a private runtime secret so a redeploy remains the same enrolled
37
+ // clauth machine. Accept the lowercase-dash form used by Coolify too.
38
+ const containerMachineId = process.env.CLAUTH_MACHINE_ID || process.env["clauth-machine-id"];
39
+ if (containerMachineId) {
40
+ const value = containerMachineId.trim();
41
+ if (!value) throw new Error("CLAUTH_MACHINE_ID must not be empty");
42
+ return { primary: value, secondary: value, platform: os.platform() };
43
+ }
44
+
45
+ // Fast path: use cached IDs if available (avoids WMI/PowerShell on every restart)
46
+ const cached = readCache();
47
+ if (cached) return { ...cached, platform: os.platform() };
48
+
49
+ const platform = os.platform();
50
+
51
+ try {
52
+ if (platform === "win32") {
53
+ const psPath = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe";
54
+ // Increased timeout to 15s — CimInstance/WMI can be slow after boot or under load.
55
+ // Each call is wrapped independently so a partial failure still yields a result.
56
+ let uuid = "";
57
+ try {
58
+ uuid = execSync(
59
+ `${psPath} -NoProfile -Command "(Get-CimInstance Win32_ComputerSystemProduct).UUID"`,
60
+ { encoding: "utf8", timeout: 15000, stdio: ["pipe", "pipe", "pipe"] }
61
+ ).trim();
62
+ } catch { /* fall through to registry-only path */ }
63
+
64
+ let machineGuid = "";
65
+ try {
66
+ machineGuid = execSync(
67
+ `${psPath} -NoProfile -Command "(Get-ItemProperty 'HKLM:\\SOFTWARE\\Microsoft\\Cryptography').MachineGuid"`,
68
+ { encoding: "utf8", timeout: 15000, stdio: ["pipe", "pipe", "pipe"] }
69
+ ).trim();
70
+ } catch { /* fall through */ }
71
+
72
+ // Require at least one identifier
73
+ if (!uuid && !machineGuid) throw new Error("Could not read any Windows machine ID");
74
+
75
+ // Use hostname as fallback secondary if registry query failed
76
+ const primary = uuid || machineGuid;
77
+ const secondary = machineGuid || os.hostname();
78
+
79
+ writeCache(primary, secondary);
80
+ return { primary, secondary, platform: "win32" };
81
+ }
82
+
83
+ if (platform === "darwin") {
84
+ const uuid = execSync(
85
+ "ioreg -rd1 -c IOPlatformExpertDevice | awk '/IOPlatformUUID/ { print $3 }'",
86
+ { encoding: "utf8", timeout: 5000, stdio: ["pipe", "pipe", "pipe"] }
87
+ ).replace(/['"]/g, "").trim();
88
+ writeCache(uuid, os.hostname());
89
+ return { primary: uuid, secondary: os.hostname(), platform: "darwin" };
90
+ }
91
+
92
+ // Linux
93
+ let uuid = "";
94
+ try { uuid = execSync("cat /etc/machine-id", { encoding: "utf8", timeout: 2000 }).trim(); }
95
+ catch { uuid = execSync("cat /var/lib/dbus/machine-id", { encoding: "utf8", timeout: 2000 }).trim(); }
96
+ writeCache(uuid, os.hostname());
97
+ return { primary: uuid, secondary: os.hostname(), platform: "linux" };
98
+
99
+ } catch (err) {
100
+ throw new Error(`Machine ID collection failed: ${err.message}`);
101
+ }
102
+ }
103
+
104
+ // ============================================================
105
+ // Derive stable machine hash (what gets stored in Supabase)
106
+ // ============================================================
107
+
108
+ export function getMachineHash() {
109
+ const { primary, secondary } = getMachineId();
110
+ return createHash("sha256")
111
+ .update(`${primary}:${secondary}`)
112
+ .digest("hex");
113
+ }
114
+
115
+ // ============================================================
116
+ // Derive HMAC token for a given password + timestamp
117
+ // ============================================================
118
+
119
+ export function deriveToken(password, machineHash) {
120
+ const windowMs = 5 * 60 * 1000;
121
+ const window = Math.floor(Date.now() / windowMs);
122
+ const message = `${machineHash}:${window}`;
123
+
124
+ // Server reconstructs this — password + CLAUTH_HMAC_SALT
125
+ // Client sends token; server adds its SALT to the password before verifying
126
+ const token = createHmac("sha256", password)
127
+ .update(message)
128
+ .digest("hex");
129
+
130
+ return { token, timestamp: window * windowMs, machineHash };
131
+ }
132
+
133
+ // ============================================================
134
+ // Derive HMAC seed hash (stored during machine registration)
135
+ // ============================================================
136
+
137
+ export function deriveSeedHash(machineHash, password) {
138
+ return createHash("sha256")
139
+ .update(`seed:${machineHash}:${password}`)
140
+ .digest("hex");
141
+ }
142
+
143
+ export default { getMachineHash, deriveToken, deriveSeedHash };