@lifeaitools/clauth 1.30.3 ā 1.30.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/cli/commands/agent-pool.js +22 -6
- package/cli/commands/serve.js +1076 -148
- package/cli/enrollment-script.js +82 -0
- package/cli/index.js +6 -44
- package/package.json +1 -1
- package/scripts/bin/bootstrap-linux +0 -0
- package/scripts/bin/bootstrap-macos +0 -0
- package/scripts/bin/bootstrap-win.exe +0 -0
- package/cli/commands/serve/tools/fs.js +0 -1055
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
function shellSingleQuote(value) {
|
|
6
|
+
return `'${String(value ?? "").replace(/'/g, "''")}'`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function posixShellQuote(value) {
|
|
10
|
+
return `'${String(value ?? "").replace(/'/g, "'\\\"'\\\"'")}'`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function enrollmentScriptName(label, target = "windows") {
|
|
14
|
+
const slug = String(label || "new-computer")
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
17
|
+
.replace(/^-+|-+$/g, "")
|
|
18
|
+
.slice(0, 40) || "new-computer";
|
|
19
|
+
return `clauth-enroll-${slug}${target === "linux" ? ".sh" : ".ps1"}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function windowsScript({ supabaseUrl, anonKey, enrollmentCode }) {
|
|
23
|
+
return [
|
|
24
|
+
"$ErrorActionPreference = 'Stop'",
|
|
25
|
+
"$label = $env:COMPUTERNAME",
|
|
26
|
+
"if (-not $label) { $label = [System.Net.Dns]::GetHostName() }",
|
|
27
|
+
"npm install -g @lifeaitools/clauth@latest",
|
|
28
|
+
["clauth setup", `--supabase-url ${shellSingleQuote(supabaseUrl)}`, `--anon-key ${shellSingleQuote(anonKey)}`, `--enrollment-code ${shellSingleQuote(enrollmentCode)}`, "--label \"$label\""].join(" "),
|
|
29
|
+
"clauth serve install",
|
|
30
|
+
"$self = $PSCommandPath",
|
|
31
|
+
"Start-Process powershell.exe -WindowStyle Hidden -ArgumentList @('-NoProfile','-Command',\"Start-Sleep -Seconds 2; & ('Remove' + '-Item') -LiteralPath '$self' -Force -ErrorAction SilentlyContinue\")",
|
|
32
|
+
].join("\r\n");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function linuxScript({ supabaseUrl, anonKey, enrollmentCode }) {
|
|
36
|
+
return [
|
|
37
|
+
"#!/usr/bin/env sh",
|
|
38
|
+
"set -eu",
|
|
39
|
+
"label=$(hostname)",
|
|
40
|
+
"as_root() { if [ \"$(id -u)\" -eq 0 ]; then \"$@\"; elif command -v sudo >/dev/null; then sudo \"$@\"; else echo 'Root or sudo is required to install prerequisites.' >&2; exit 1; fi; }",
|
|
41
|
+
"install_prerequisites() {",
|
|
42
|
+
" if command -v apt-get >/dev/null; then as_root apt-get update; as_root apt-get install -y nodejs npm openssl;",
|
|
43
|
+
" elif command -v dnf >/dev/null; then as_root dnf install -y nodejs npm openssl;",
|
|
44
|
+
" else echo 'Headless enrollment supports systemd hosts with apt-get or dnf. Install Node.js 18+, npm, and openssl, then rerun this script.' >&2; exit 1; fi",
|
|
45
|
+
"}",
|
|
46
|
+
"if ! command -v systemctl >/dev/null || ! command -v loginctl >/dev/null; then echo 'Headless enrollment requires systemd and loginctl.' >&2; exit 1; fi",
|
|
47
|
+
"if ! command -v node >/dev/null || ! command -v npm >/dev/null || ! command -v openssl >/dev/null; then install_prerequisites; fi",
|
|
48
|
+
"node_major=$(node -p \"process.versions.node.split('.')[0]\")",
|
|
49
|
+
"if [ \"$node_major\" -lt 18 ]; then echo 'Node.js 18+ is required.' >&2; exit 1; fi",
|
|
50
|
+
"if ! npm install -g @lifeaitools/clauth@latest; then as_root npm install -g @lifeaitools/clauth@latest; fi",
|
|
51
|
+
["clauth setup", `--supabase-url ${posixShellQuote(supabaseUrl)}`, `--anon-key ${posixShellQuote(anonKey)}`, `--enrollment-code ${posixShellQuote(enrollmentCode)}`, '--label "$label"'].join(" "),
|
|
52
|
+
"user_name=$(id -un)",
|
|
53
|
+
"if loginctl enable-linger \"$user_name\"; then echo \"Linger enabled for $user_name.\"; elif as_root loginctl enable-linger \"$user_name\"; then echo \"Linger enabled for $user_name.\"; else echo 'Could not enable linger for unattended restart.' >&2; exit 1; fi",
|
|
54
|
+
"if ! test -t 0; then echo 'Headless enrollment requires an interactive TTY to set the vault password.' >&2; exit 1; fi",
|
|
55
|
+
"restore_echo() { stty echo 2>/dev/null || true; }",
|
|
56
|
+
"trap restore_echo EXIT HUP INT TERM",
|
|
57
|
+
"printf 'Re-enter the vault password to enable unattended restart: ' >&2",
|
|
58
|
+
"stty -echo",
|
|
59
|
+
"IFS= read -r vault_password",
|
|
60
|
+
"stty echo",
|
|
61
|
+
"trap - EXIT HUP INT TERM",
|
|
62
|
+
"printf '\\n' >&2",
|
|
63
|
+
"[ -n \"$vault_password\" ] || { echo 'A vault password is required for unattended restart.' >&2; exit 1; }",
|
|
64
|
+
"printf %s \"$vault_password\" | clauth serve install --pw-stdin",
|
|
65
|
+
"unset vault_password",
|
|
66
|
+
"rm -f -- \"$0\"",
|
|
67
|
+
].join("\n");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function writeEnrollmentScript({ supabaseUrl, anonKey, enrollmentCode, label, target = "windows", appDir } = {}) {
|
|
71
|
+
if (!["windows", "linux"].includes(target)) throw new Error(`Unsupported enrollment target: ${target}`);
|
|
72
|
+
const outputDir = appDir || (process.platform === "win32"
|
|
73
|
+
? path.join(process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"), "clauth")
|
|
74
|
+
: path.join(os.homedir(), ".config", "clauth"));
|
|
75
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
76
|
+
const scriptPath = path.join(outputDir, enrollmentScriptName(label, target));
|
|
77
|
+
const script = target === "linux"
|
|
78
|
+
? linuxScript({ supabaseUrl, anonKey, enrollmentCode })
|
|
79
|
+
: windowsScript({ supabaseUrl, anonKey, enrollmentCode });
|
|
80
|
+
fs.writeFileSync(scriptPath, `${script}\n`, { encoding: "utf8", mode: target === "linux" ? 0o700 : undefined });
|
|
81
|
+
return scriptPath;
|
|
82
|
+
}
|
package/cli/index.js
CHANGED
|
@@ -13,53 +13,11 @@ import { writeCredentialWithRecovery } from "./recovery.js";
|
|
|
13
13
|
import os from "os";
|
|
14
14
|
import fs from "fs";
|
|
15
15
|
import path from "path";
|
|
16
|
+
import { writeEnrollmentScript } from "./enrollment-script.js";
|
|
16
17
|
|
|
17
18
|
const config = new Conf(getConfOptions());
|
|
18
19
|
const VERSION = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
19
20
|
|
|
20
|
-
function shellSingleQuote(value) {
|
|
21
|
-
return `'${String(value ?? "").replace(/'/g, "''")}'`;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function enrollmentScriptName(label) {
|
|
25
|
-
const slug = String(label || "new-computer")
|
|
26
|
-
.toLowerCase()
|
|
27
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
28
|
-
.replace(/^-+|-+$/g, "")
|
|
29
|
-
.slice(0, 40) || "new-computer";
|
|
30
|
-
return `clauth-enroll-${slug}.ps1`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function writeEnrollmentScript({ supabaseUrl, anonKey, enrollmentCode, label }) {
|
|
34
|
-
const appDir = process.platform === "win32"
|
|
35
|
-
? path.join(process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"), "clauth")
|
|
36
|
-
: path.join(os.homedir(), ".config", "clauth");
|
|
37
|
-
fs.mkdirSync(appDir, { recursive: true });
|
|
38
|
-
const scriptPath = path.join(appDir, enrollmentScriptName(label));
|
|
39
|
-
const script = [
|
|
40
|
-
"$ErrorActionPreference = 'Stop'",
|
|
41
|
-
"$label = $env:COMPUTERNAME",
|
|
42
|
-
"if (-not $label) { $label = [System.Net.Dns]::GetHostName() }",
|
|
43
|
-
"Write-Host 'Installing clauth...'",
|
|
44
|
-
"npm install -g @lifeaitools/clauth@latest",
|
|
45
|
-
"Write-Host 'Enrolling this computer with clauth...'",
|
|
46
|
-
[
|
|
47
|
-
"clauth setup",
|
|
48
|
-
`--supabase-url ${shellSingleQuote(supabaseUrl)}`,
|
|
49
|
-
`--anon-key ${shellSingleQuote(anonKey)}`,
|
|
50
|
-
`--enrollment-code ${shellSingleQuote(enrollmentCode)}`,
|
|
51
|
-
"--label \"$label\"",
|
|
52
|
-
].join(" "),
|
|
53
|
-
"Write-Host 'Installing clauth startup service...'",
|
|
54
|
-
"clauth serve install",
|
|
55
|
-
"Write-Host 'clauth enrollment complete.'",
|
|
56
|
-
"$self = $PSCommandPath",
|
|
57
|
-
"Start-Process powershell.exe -WindowStyle Hidden -ArgumentList @('-NoProfile','-Command',\"Start-Sleep -Seconds 2; Remove-Item -LiteralPath '$self' -Force -ErrorAction SilentlyContinue\")",
|
|
58
|
-
].join("\r\n");
|
|
59
|
-
fs.writeFileSync(scriptPath, `${script}\r\n`, "utf8");
|
|
60
|
-
return scriptPath;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
21
|
// ============================================================
|
|
64
22
|
// Password prompt helper
|
|
65
23
|
// ============================================================
|
|
@@ -391,6 +349,7 @@ program
|
|
|
391
349
|
.option("--label <label>", "Suggested label for the new computer")
|
|
392
350
|
.option("--ttl-minutes <minutes>", "Enrollment lifetime, 5 to 1440 minutes", "60")
|
|
393
351
|
.option("--install-id <id>", "Override install id; default is current machine's install id")
|
|
352
|
+
.option("--target <target>", "Enrollment target: windows or linux", "windows")
|
|
394
353
|
.option("-p, --pw <password>", "Password (or will prompt)")
|
|
395
354
|
.action(async (opts) => {
|
|
396
355
|
console.log(chalk.cyan("\nš clauth enroll\n"));
|
|
@@ -414,6 +373,7 @@ program
|
|
|
414
373
|
anonKey,
|
|
415
374
|
enrollmentCode: result.enrollment_code,
|
|
416
375
|
label: opts.label,
|
|
376
|
+
target: opts.target,
|
|
417
377
|
});
|
|
418
378
|
spinner.succeed(chalk.green(`Enrollment created for install_id=${result.install_id}`));
|
|
419
379
|
console.log("");
|
|
@@ -1047,7 +1007,9 @@ program
|
|
|
1047
1007
|
.option("--tunnel <hostname>", "Fixed tunnel hostname (e.g. clauth.prtrust.fund) ā uses named Cloudflare Tunnel instead of random URL")
|
|
1048
1008
|
.option("--staged", "Start on staging port (52438) for blue-green verification before make-live")
|
|
1049
1009
|
.option("--isolated", "Run on a non-live port without touching live PID files, browser, or boot-key credentials")
|
|
1050
|
-
.option("--from-boot-key", "Internal: password came from boot.key auto-unlock (degrade gracefully on verify failure)")
|
|
1010
|
+
.option("--from-boot-key", "Internal: password came from boot.key auto-unlock (degrade gracefully on verify failure)")
|
|
1011
|
+
.option("--pw-env", "Internal: read the daemon password from CLAUTH_BOOT_PASSWORD")
|
|
1012
|
+
.option("--pw-stdin", "Internal: read the installer password from standard input")
|
|
1051
1013
|
.option("--action <action>", "Internal: action override for daemon child")
|
|
1052
1014
|
.addHelpText("after", `
|
|
1053
1015
|
Actions:
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|