@golproductions/check 3.1.1 → 3.1.3
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/package.json +1 -1
- package/src/index.js +59 -8
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { homedir, platform, arch } from "node:os";
|
|
|
5
5
|
import { pipeline } from "node:stream/promises";
|
|
6
6
|
import { Readable } from "node:stream";
|
|
7
7
|
|
|
8
|
-
const VERSION = "3.1.
|
|
8
|
+
const VERSION = "3.1.3";
|
|
9
9
|
const BINARY_VERSION = "3.0.0";
|
|
10
10
|
const API = "https://triage.golproductions.com/preflight";
|
|
11
11
|
const CDN = "https://pub-e55366a7f5994be9be04f0e205179f4a.r2.dev/releases";
|
|
@@ -37,6 +37,35 @@ async function validateKey(key) {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
// Stable anonymous device fingerprint: one-way hash of coarse machine facts.
|
|
41
|
+
// No personal data. Server uses it only to rate-limit free-key minting.
|
|
42
|
+
async function deviceFingerprint() {
|
|
43
|
+
const { createHash } = await import("node:crypto");
|
|
44
|
+
const { hostname, userInfo } = await import("node:os");
|
|
45
|
+
let user = "";
|
|
46
|
+
try { user = userInfo().username || ""; } catch {}
|
|
47
|
+
const seed = [hostname(), platform(), arch(), user].join("|");
|
|
48
|
+
return createHash("sha256").update(seed).digest("hex");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Mint a free key with no email and no browser. Returns the client_id or null.
|
|
52
|
+
async function mintInstantKey() {
|
|
53
|
+
try {
|
|
54
|
+
const fp = await deviceFingerprint();
|
|
55
|
+
const res = await fetch(API.replace("/preflight", "/instant-key"), {
|
|
56
|
+
method: "POST",
|
|
57
|
+
headers: { "Content-Type": "application/json", "User-Agent": "c/" + VERSION },
|
|
58
|
+
body: JSON.stringify({ fingerprint: fp, channel: "npm" }),
|
|
59
|
+
signal: AbortSignal.timeout(10000),
|
|
60
|
+
});
|
|
61
|
+
if (!res.ok) return null;
|
|
62
|
+
const d = await res.json();
|
|
63
|
+
return d && d.client_id ? d.client_id : null;
|
|
64
|
+
} catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
40
69
|
async function downloadBinary(dest) {
|
|
41
70
|
const os = platform() === "win32" ? "win" : platform() === "darwin" ? "macos" : "linux";
|
|
42
71
|
const cpu = arch() === "arm64" ? "arm64" : "x64";
|
|
@@ -49,14 +78,19 @@ async function downloadBinary(dest) {
|
|
|
49
78
|
}
|
|
50
79
|
|
|
51
80
|
async function install() {
|
|
52
|
-
|
|
81
|
+
let key = process.argv[3] || process.env.GOL_CLIENT_ID || "";
|
|
53
82
|
|
|
83
|
+
// No key provided: mint one instantly. No email, no browser, no copy-paste.
|
|
54
84
|
if (!key || key === "your_key") {
|
|
55
|
-
console.log("\n Check
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
85
|
+
console.log("\n Activating Check (free, no signup)...\n");
|
|
86
|
+
key = await mintInstantKey();
|
|
87
|
+
if (!key) {
|
|
88
|
+
console.log(" Could not activate automatically (offline, or this network hit its daily limit).\n");
|
|
89
|
+
console.log(" Get a key the manual way: https://golproductions.com/check\n");
|
|
90
|
+
console.log(" Then run: npx @golproductions/check --install YOUR_KEY\n");
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
console.log(" Activated. 120 free checks per day.\n");
|
|
60
94
|
}
|
|
61
95
|
|
|
62
96
|
const result = await validateKey(key);
|
|
@@ -642,11 +676,28 @@ async function main() {
|
|
|
642
676
|
const res = await fetch(API, {
|
|
643
677
|
method: "POST",
|
|
644
678
|
headers: { "Content-Type": "application/json", "X-GOL-CLIENT-ID": CLIENT_ID, "User-Agent": "c/" + VERSION },
|
|
645
|
-
body: JSON.stringify({ command: c, cwd: p.cwd || process.cwd(), platform: f, tool_name: p.tool_name, transcript_path: p.transcript_path, v: VERSION }),
|
|
679
|
+
body: JSON.stringify({ command: c, cwd: p.cwd || process.cwd(), platform: f, channel: "npm", tool_name: p.tool_name, transcript_path: p.transcript_path, v: VERSION }),
|
|
646
680
|
signal: controller.signal
|
|
647
681
|
});
|
|
648
682
|
clearTimeout(timer);
|
|
649
683
|
const d = await res.json();
|
|
684
|
+
|
|
685
|
+
// Billing and account states arrive as non-2xx and carry no `verdict`.
|
|
686
|
+
// Surface what the server actually said so the user knows this is about
|
|
687
|
+
// their account, not their command. Without this, the free-tier wall
|
|
688
|
+
// (HTTP 402) falls through to the generic "denied" below and reads like
|
|
689
|
+
// the command itself was rejected.
|
|
690
|
+
if (!res.ok) {
|
|
691
|
+
if (res.status === 402) {
|
|
692
|
+
const free = d.daily_free || 120;
|
|
693
|
+
const upsell = d.upgrade || "Top up at https://www.golproductions.com/console.html";
|
|
694
|
+
out(f, false, `check: you've used all ${free} free checks for today. Credits you buy never expire. ${upsell}`);
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
out(f, false, d.reason || d.error || "check: request not authorized, command blocked");
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
|
|
650
701
|
if (d.verdict === "runnable") { out(f, true); }
|
|
651
702
|
else { out(f, false, d.reason || "denied — address the issue before continuing"); }
|
|
652
703
|
} catch { out(f, false, "check: verification failed, command blocked"); }
|