@zdevzone/keyforge-client 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +133 -2
- package/dist/client.d.ts +105 -0
- package/dist/client.js +563 -0
- package/dist/client.js.map +1 -0
- package/dist/device-signals-node.d.ts +22 -0
- package/dist/device-signals-node.js +130 -0
- package/dist/device-signals-node.js.map +1 -0
- package/dist/device-signals.d.ts +13 -0
- package/dist/device-signals.js +17 -0
- package/dist/device-signals.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/linux.d.ts +8 -0
- package/dist/linux.js +35 -0
- package/dist/linux.js.map +1 -0
- package/dist/macos.d.ts +7 -0
- package/dist/macos.js +27 -0
- package/dist/macos.js.map +1 -0
- package/dist/tokens.d.ts +63 -0
- package/dist/tokens.js +113 -0
- package/dist/tokens.js.map +1 -0
- package/dist/types.d.ts +136 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/windows.d.ts +8 -0
- package/dist/windows.js +27 -0
- package/dist/windows.js.map +1 -0
- package/package.json +49 -3
- package/skill/keyforge-integrate/SKILL.md +26 -0
- package/skill/keyforge-integrate/references/integration.md +51 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/** Internal Node-only primitives shared by opt-in desktop collectors. */
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { open, constants } from "node:fs/promises";
|
|
5
|
+
export const QUERY_TIMEOUT_MS = 8000;
|
|
6
|
+
export class DeviceSignalQueryError extends Error {
|
|
7
|
+
status;
|
|
8
|
+
constructor(status) {
|
|
9
|
+
super(`Device signal query: ${status}`);
|
|
10
|
+
this.status = status;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function queryError(error) {
|
|
14
|
+
const value = error;
|
|
15
|
+
return new DeviceSignalQueryError(value?.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER"
|
|
16
|
+
? "query_failed"
|
|
17
|
+
: value?.killed
|
|
18
|
+
? "timeout"
|
|
19
|
+
: value?.code === "EACCES" || value?.code === "EPERM" || value?.code === 5
|
|
20
|
+
? "permission_denied"
|
|
21
|
+
: value?.code === "ENOENT"
|
|
22
|
+
? "unavailable"
|
|
23
|
+
: "query_failed");
|
|
24
|
+
}
|
|
25
|
+
export function executeQuery(file, args, maxBuffer = 4096) {
|
|
26
|
+
return new Promise((resolve, reject) => execFile(file, [...args], { windowsHide: true, timeout: QUERY_TIMEOUT_MS, maxBuffer, encoding: "utf8" }, (error, stdout) => (error ? reject(queryError(error)) : resolve(stdout))));
|
|
27
|
+
}
|
|
28
|
+
/** Fixed local files only; one bounded nonblocking read also works for size-zero sysfs files. */
|
|
29
|
+
export async function readIdentifier(file) {
|
|
30
|
+
try {
|
|
31
|
+
const handle = await open(file, constants.O_RDONLY | constants.O_NONBLOCK);
|
|
32
|
+
try {
|
|
33
|
+
if (!(await handle.stat()).isFile())
|
|
34
|
+
throw new DeviceSignalQueryError("unavailable");
|
|
35
|
+
const bytes = Buffer.alloc(4097);
|
|
36
|
+
const { bytesRead } = await handle.read(bytes, 0, bytes.length, 0);
|
|
37
|
+
if (bytesRead > 4096)
|
|
38
|
+
throw new DeviceSignalQueryError("query_failed");
|
|
39
|
+
return bytes.subarray(0, bytesRead).toString("utf8");
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
await handle.close();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
throw error instanceof DeviceSignalQueryError ? error : queryError(error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** UUIDs use lowercase unbraced hyphenated hex; volume serials use eight lowercase hex digits. */
|
|
50
|
+
export function normalizeDeviceIdentifier(kind, input) {
|
|
51
|
+
if (input.length > 256)
|
|
52
|
+
return null;
|
|
53
|
+
const value = input.trim().toLowerCase();
|
|
54
|
+
if (kind === "volume-serial") {
|
|
55
|
+
const hex = value.replace(/^([a-f0-9]{4})-([a-f0-9]{4})$/, "$1$2");
|
|
56
|
+
return /^[a-f0-9]{8}$/.test(hex) && !/^(0{8}|f{8}|12345678)$/.test(hex) ? hex : null;
|
|
57
|
+
}
|
|
58
|
+
if (kind === "linux-machine-id")
|
|
59
|
+
return /^[a-f0-9]{32}$/.test(value) && !/^([a-f0-9])\1{31}$/.test(value) ? value : null;
|
|
60
|
+
const uuid = value.replace(/^\{([a-f0-9-]+)\}$/, "$1");
|
|
61
|
+
if (!/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/.test(uuid))
|
|
62
|
+
return null;
|
|
63
|
+
const compact = uuid.replaceAll("-", "");
|
|
64
|
+
if (/^(0{32}|f{32}|([a-f0-9])\2{31})$/.test(compact) ||
|
|
65
|
+
compact === "03000200040005000006000700080009")
|
|
66
|
+
return null;
|
|
67
|
+
return uuid;
|
|
68
|
+
}
|
|
69
|
+
/** v1: SHA-256 of UTF-8 JSON [domain, version, canonical deployment URL, product, kind, identifier]. */
|
|
70
|
+
export function hashDeviceIdentifier(context, kind, normalized) {
|
|
71
|
+
const url = new URL(context.serverUrl);
|
|
72
|
+
if (url.username ||
|
|
73
|
+
url.password ||
|
|
74
|
+
url.search ||
|
|
75
|
+
url.hash ||
|
|
76
|
+
!/^[a-z][a-z0-9-]{0,59}$/.test(context.productId))
|
|
77
|
+
throw new Error("Invalid device signal scope");
|
|
78
|
+
const deployment = url.toString().replace(/\/$/, "");
|
|
79
|
+
return createHash("sha256")
|
|
80
|
+
.update(JSON.stringify([
|
|
81
|
+
"keyforge-device-signals",
|
|
82
|
+
1,
|
|
83
|
+
deployment,
|
|
84
|
+
context.productId,
|
|
85
|
+
kind,
|
|
86
|
+
normalized,
|
|
87
|
+
]), "utf8")
|
|
88
|
+
.digest("hex");
|
|
89
|
+
}
|
|
90
|
+
export function boundedQuery(query, kind) {
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
const timer = setTimeout(() => reject(new DeviceSignalQueryError("timeout")), QUERY_TIMEOUT_MS);
|
|
93
|
+
Promise.resolve()
|
|
94
|
+
.then(() => query(kind))
|
|
95
|
+
.then((value) => {
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
if (typeof value !== "string" || Buffer.byteLength(value, "utf8") > 4096)
|
|
98
|
+
reject(new DeviceSignalQueryError("query_failed"));
|
|
99
|
+
else
|
|
100
|
+
resolve(value);
|
|
101
|
+
}, (error) => {
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
reject(error);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
export function createSignalProvider(platform, kinds, options, nativeQuery) {
|
|
108
|
+
return async (context) => {
|
|
109
|
+
const report = { signals: [], diagnostics: [] };
|
|
110
|
+
for (const kind of kinds) {
|
|
111
|
+
let status = "unsupported";
|
|
112
|
+
if ((options.platform ?? process.platform) === platform) {
|
|
113
|
+
try {
|
|
114
|
+
const raw = await boundedQuery(options.query ?? nativeQuery, kind);
|
|
115
|
+
const normalized = normalizeDeviceIdentifier(kind, raw);
|
|
116
|
+
status = normalized ? "available" : raw.trim() ? "invalid" : "unavailable";
|
|
117
|
+
if (normalized)
|
|
118
|
+
report.signals.push({ kind, hash: hashDeviceIdentifier(context, kind, normalized) });
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
status =
|
|
122
|
+
error instanceof DeviceSignalQueryError ? error.status : queryError(error).status;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
report.diagnostics.push({ kind, status });
|
|
126
|
+
}
|
|
127
|
+
return report;
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=device-signals-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-signals-node.js","sourceRoot":"","sources":["../src/device-signals-node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Optional Node-only auto-detection. The core @zdevzone/keyforge-client entry point never imports this. */
|
|
2
|
+
import { type LinuxDeviceSignalsOptions } from "./linux.js";
|
|
3
|
+
import { type MacOSDeviceSignalsOptions } from "./macos.js";
|
|
4
|
+
import type { DeviceSignalsProvider } from "./types.js";
|
|
5
|
+
import { type WindowsDeviceSignalsOptions } from "./windows.js";
|
|
6
|
+
export { DeviceSignalQueryError, hashDeviceIdentifier, normalizeDeviceIdentifier, } from "./device-signals-node.js";
|
|
7
|
+
export interface DeviceSignalsOptions {
|
|
8
|
+
platform?: string;
|
|
9
|
+
windows?: Omit<WindowsDeviceSignalsOptions, "platform">;
|
|
10
|
+
linux?: Omit<LinuxDeviceSignalsOptions, "platform">;
|
|
11
|
+
macos?: Omit<MacOSDeviceSignalsOptions, "platform">;
|
|
12
|
+
}
|
|
13
|
+
export declare function createDeviceSignalsProvider(options?: DeviceSignalsOptions): DeviceSignalsProvider;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Optional Node-only auto-detection. The core @zdevzone/keyforge-client entry point never imports this. */
|
|
2
|
+
import { createLinuxDeviceSignalsProvider } from "./linux.js";
|
|
3
|
+
import { createMacOSDeviceSignalsProvider } from "./macos.js";
|
|
4
|
+
import { createWindowsDeviceSignalsProvider } from "./windows.js";
|
|
5
|
+
export { DeviceSignalQueryError, hashDeviceIdentifier, normalizeDeviceIdentifier, } from "./device-signals-node.js";
|
|
6
|
+
export function createDeviceSignalsProvider(options = {}) {
|
|
7
|
+
const platform = options.platform ?? process.platform;
|
|
8
|
+
if (platform === "win32")
|
|
9
|
+
return createWindowsDeviceSignalsProvider({ ...options.windows, platform });
|
|
10
|
+
if (platform === "linux")
|
|
11
|
+
return createLinuxDeviceSignalsProvider({ ...options.linux, platform });
|
|
12
|
+
if (platform === "darwin")
|
|
13
|
+
return createMacOSDeviceSignalsProvider({ ...options.macos, platform });
|
|
14
|
+
// Other runtimes retain installation licensing; no fake fingerprint is manufactured.
|
|
15
|
+
return async () => ({ signals: [], diagnostics: [] });
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=device-signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-signals.js","sourceRoot":"","sources":["../src/device-signals.ts"],"names":[],"mappings":"AAAA,4GAA4G;AAC5G,OAAO,EAAE,gCAAgC,EAAkC,MAAM,YAAY,CAAC;AAC9F,OAAO,EAAE,gCAAgC,EAAkC,MAAM,YAAY,CAAC;AAE9F,OAAO,EAAE,kCAAkC,EAAoC,MAAM,cAAc,CAAC;AAEpG,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,0BAA0B,CAAC;AAOlC,MAAM,UAAU,2BAA2B,CACzC,OAAO,GAAyB,EAAE;IAElC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACtD,IAAI,QAAQ,KAAK,OAAO;QACtB,OAAO,kCAAkC,CAAC,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC9E,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,gCAAgC,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClG,IAAI,QAAQ,KAAK,QAAQ;QACvB,OAAO,gCAAgC,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1E,qFAAqF;IACrF,OAAO,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;AACxD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { KeyForgeClient, KeyForgeError, MemoryStorage } from "./client.js";
|
|
2
|
+
export { verifySignedToken, TokenError } from "./tokens.js";
|
|
3
|
+
export type { LicenseToken, TrialToken, SignedToken, VerificationContext } from "./tokens.js";
|
|
4
|
+
export type { ClientOptions } from "./client.js";
|
|
5
|
+
export type * from "./types.js";
|
|
6
|
+
export { DEVICE_SIGNAL_KINDS } from "./types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/linux.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DeviceSignalsProvider } from "./types.js";
|
|
2
|
+
export interface LinuxDeviceSignalsOptions {
|
|
3
|
+
platform?: string;
|
|
4
|
+
/** Inject read-only OS operations for integration tests. */
|
|
5
|
+
readFile?: (path: string) => Promise<string>;
|
|
6
|
+
execute?: (file: string, args: readonly string[]) => Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
export declare function createLinuxDeviceSignalsProvider(options?: LinuxDeviceSignalsOptions): DeviceSignalsProvider;
|
package/dist/linux.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Optional Node-only Linux adapter. No sudo, dmidecode, disk reads or shell scripts. */
|
|
2
|
+
import { createSignalProvider, DeviceSignalQueryError, executeQuery, readIdentifier, } from "./device-signals-node.js";
|
|
3
|
+
export function createLinuxDeviceSignalsProvider(options = {}) {
|
|
4
|
+
const read = options.readFile ?? readIdentifier, execute = options.execute ?? executeQuery;
|
|
5
|
+
const query = async (kind) => {
|
|
6
|
+
if (kind === "linux-machine-id") {
|
|
7
|
+
try {
|
|
8
|
+
const value = await read("/etc/machine-id");
|
|
9
|
+
if (value.trim())
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (!(error instanceof DeviceSignalQueryError && error.status === "unavailable") &&
|
|
14
|
+
error?.code !== "ENOENT")
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
return read("/var/lib/dbus/machine-id");
|
|
18
|
+
}
|
|
19
|
+
if (kind === "smbios-uuid")
|
|
20
|
+
return read("/sys/class/dmi/id/product_uuid");
|
|
21
|
+
for (const file of ["/usr/bin/findmnt", "/bin/findmnt"]) {
|
|
22
|
+
try {
|
|
23
|
+
return await execute(file, ["--noheadings", "--raw", "--output", "UUID", "--target", "/"]);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (!(error instanceof DeviceSignalQueryError && error.status === "unavailable") &&
|
|
27
|
+
error?.code !== "ENOENT")
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
throw new DeviceSignalQueryError("unavailable");
|
|
32
|
+
};
|
|
33
|
+
return createSignalProvider("linux", ["linux-machine-id", "smbios-uuid", "root-volume-uuid"], { ...options, query }, query);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=linux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linux.js","sourceRoot":"","sources":["../src/linux.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,YAAY,EACZ,cAAc,GACf,MAAM,0BAA0B,CAAC;AASlC,MAAM,UAAU,gCAAgC,CAC9C,OAAO,GAA8B,EAAE;IAEvC,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,IAAI,cAAc,EAC7C,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,YAAY,CAAC;IAC5C,MAAM,KAAK,GAAG,KAAK,EAAE,IAAsB,EAAmB,EAAE;QAC9D,IAAI,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAChC,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBAC5C,IAAI,KAAK,CAAC,IAAI,EAAE;oBAAE,OAAO,KAAK,CAAC;YACjC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IACE,CAAC,CAAC,KAAK,YAAY,sBAAsB,IAAI,KAAK,CAAC,MAAM,KAAK,aAAa,CAAC;oBAC3E,KAA2B,EAAE,IAAI,KAAK,QAAQ;oBAE/C,MAAM,KAAK,CAAC;YAChB,CAAC;YACD,OAAO,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,IAAI,KAAK,aAAa;YAAE,OAAO,IAAI,CAAC,gCAAgC,CAAC,CAAC;QAC1E,KAAK,MAAM,IAAI,IAAI,CAAC,kBAAkB,EAAE,cAAc,CAAC,EAAE,CAAC;YACxD,IAAI,CAAC;gBACH,OAAO,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,cAAc,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;YAC7F,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IACE,CAAC,CAAC,KAAK,YAAY,sBAAsB,IAAI,KAAK,CAAC,MAAM,KAAK,aAAa,CAAC;oBAC3E,KAA2B,EAAE,IAAI,KAAK,QAAQ;oBAE/C,MAAM,KAAK,CAAC;YAChB,CAAC;QACH,CAAC;QACD,MAAM,IAAI,sBAAsB,CAAC,aAAa,CAAC,CAAC;IAClD,CAAC,CAAC;IACF,OAAO,oBAAoB,CACzB,OAAO,EACP,CAAC,kBAAkB,EAAE,aAAa,EAAE,kBAAkB,CAAC,EACvD,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,EACrB,KAAK,CACN,CAAC;AACJ,CAAC"}
|
package/dist/macos.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DeviceSignalsProvider } from "./types.js";
|
|
2
|
+
export interface MacOSDeviceSignalsOptions {
|
|
3
|
+
platform?: string;
|
|
4
|
+
/** Test seam. Raw utility output stays local and is never returned in reports. */
|
|
5
|
+
execute?: (file: string, args: readonly string[]) => Promise<string>;
|
|
6
|
+
}
|
|
7
|
+
export declare function createMacOSDeviceSignalsProvider(options?: MacOSDeviceSignalsOptions): DeviceSignalsProvider;
|
package/dist/macos.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Optional Node-only macOS adapter; fixed read-only Apple system utilities. */
|
|
2
|
+
import { createSignalProvider, executeQuery } from "./device-signals-node.js";
|
|
3
|
+
export function createMacOSDeviceSignalsProvider(options = {}) {
|
|
4
|
+
const execute = options.execute ?? ((file, args) => executeQuery(file, args, 65536));
|
|
5
|
+
return createSignalProvider("darwin", ["macos-platform-uuid", "root-volume-uuid"], options, async (kind) => {
|
|
6
|
+
if (kind === "macos-platform-uuid") {
|
|
7
|
+
const value = await execute("/usr/sbin/ioreg", [
|
|
8
|
+
"-r",
|
|
9
|
+
"-d",
|
|
10
|
+
"1",
|
|
11
|
+
"-c",
|
|
12
|
+
"IOPlatformExpertDevice",
|
|
13
|
+
"-w",
|
|
14
|
+
"0",
|
|
15
|
+
]);
|
|
16
|
+
if (Buffer.byteLength(value, "utf8") > 65536)
|
|
17
|
+
throw new Error("query_failed");
|
|
18
|
+
return /"IOPlatformUUID"\s*=\s*"([^"\r\n]{0,256})"/.exec(value)?.[1] ?? "";
|
|
19
|
+
}
|
|
20
|
+
const value = await execute("/usr/sbin/diskutil", ["info", "-plist", "/"]);
|
|
21
|
+
if (Buffer.byteLength(value, "utf8") > 65536)
|
|
22
|
+
throw new Error("query_failed");
|
|
23
|
+
// Read one known plist scalar, not arbitrary XML/entities or snapshot identifiers.
|
|
24
|
+
return /<key>VolumeUUID<\/key>\s*<string>([^<\r\n]{0,256})<\/string>/.exec(value)?.[1] ?? "";
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=macos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macos.js","sourceRoot":"","sources":["../src/macos.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAQ9E,MAAM,UAAU,gCAAgC,CAC9C,OAAO,GAA8B,EAAE;IAEvC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IACrF,OAAO,oBAAoB,CACzB,QAAQ,EACR,CAAC,qBAAqB,EAAE,kBAAkB,CAAC,EAC3C,OAAO,EACP,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACnC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,iBAAiB,EAAE;gBAC7C,IAAI;gBACJ,IAAI;gBACJ,GAAG;gBACH,IAAI;gBACJ,wBAAwB;gBACxB,IAAI;gBACJ,GAAG;aACJ,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;YAC9E,OAAO,4CAA4C,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7E,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;QAC3E,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;QAC9E,mFAAmF;QACnF,OAAO,8DAA8D,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/F,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/tokens.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const licenseSchema: z.ZodObject<{
|
|
3
|
+
iss: z.ZodLiteral<"default">;
|
|
4
|
+
productId: z.ZodString;
|
|
5
|
+
kid: z.ZodString;
|
|
6
|
+
installationId: z.ZodString;
|
|
7
|
+
issuedAt: z.ZodString;
|
|
8
|
+
expiresAt: z.ZodNullable<z.ZodString>;
|
|
9
|
+
v: z.ZodLiteral<4>;
|
|
10
|
+
kind: z.ZodLiteral<"license">;
|
|
11
|
+
licenseId: z.ZodString;
|
|
12
|
+
plan: z.ZodString;
|
|
13
|
+
entitlements: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>>;
|
|
14
|
+
issuedTo: z.ZodString;
|
|
15
|
+
subject: z.ZodObject<{
|
|
16
|
+
kind: z.ZodEnum<{
|
|
17
|
+
installation: "installation";
|
|
18
|
+
service: "service";
|
|
19
|
+
}>;
|
|
20
|
+
id: z.ZodString;
|
|
21
|
+
}, z.core.$strict>;
|
|
22
|
+
offlineGraceUntil: z.ZodString;
|
|
23
|
+
status: z.ZodEnum<{
|
|
24
|
+
active: "active";
|
|
25
|
+
expired: "expired";
|
|
26
|
+
revoked: "revoked";
|
|
27
|
+
}>;
|
|
28
|
+
}, z.core.$strict>;
|
|
29
|
+
export declare const trialSchema: z.ZodObject<{
|
|
30
|
+
iss: z.ZodLiteral<"default">;
|
|
31
|
+
productId: z.ZodString;
|
|
32
|
+
kid: z.ZodString;
|
|
33
|
+
installationId: z.ZodString;
|
|
34
|
+
issuedAt: z.ZodString;
|
|
35
|
+
expiresAt: z.ZodNullable<z.ZodString>;
|
|
36
|
+
v: z.ZodLiteral<2>;
|
|
37
|
+
kind: z.ZodLiteral<"trial">;
|
|
38
|
+
verdict: z.ZodEnum<{
|
|
39
|
+
fresh: "fresh";
|
|
40
|
+
spent: "spent";
|
|
41
|
+
}>;
|
|
42
|
+
allowance: z.ZodNullable<z.ZodNumber>;
|
|
43
|
+
supportReference: z.ZodNullable<z.ZodString>;
|
|
44
|
+
}, z.core.$strict>;
|
|
45
|
+
export type LicenseToken = z.infer<typeof licenseSchema>;
|
|
46
|
+
export type TrialToken = z.infer<typeof trialSchema>;
|
|
47
|
+
export type SignedToken = LicenseToken | TrialToken;
|
|
48
|
+
export declare class TokenError extends Error {
|
|
49
|
+
readonly code: string;
|
|
50
|
+
constructor(code: string);
|
|
51
|
+
}
|
|
52
|
+
export interface VerificationContext {
|
|
53
|
+
productId: string;
|
|
54
|
+
installationId: string;
|
|
55
|
+
publicKeys: Readonly<Record<string, string>>;
|
|
56
|
+
subjectKind?: "installation" | "service";
|
|
57
|
+
now?: number;
|
|
58
|
+
clockToleranceMs?: number;
|
|
59
|
+
}
|
|
60
|
+
export declare function encodeBase64url(bytes: Uint8Array): string;
|
|
61
|
+
/** Authenticates a token, including its context. Expiry/status are evaluated separately
|
|
62
|
+
* so signed negative grants can replace a previously active cached grant. */
|
|
63
|
+
export declare function verifySignedToken(token: string, context: VerificationContext): Promise<SignedToken>;
|
package/dist/tokens.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const id = z.string().min(1).max(200);
|
|
3
|
+
const date = z.string().datetime({ offset: true });
|
|
4
|
+
const common = {
|
|
5
|
+
iss: z.literal("default"),
|
|
6
|
+
productId: id,
|
|
7
|
+
kid: id,
|
|
8
|
+
installationId: id,
|
|
9
|
+
issuedAt: date,
|
|
10
|
+
expiresAt: date.nullable(),
|
|
11
|
+
};
|
|
12
|
+
export const licenseSchema = z
|
|
13
|
+
.object({
|
|
14
|
+
...common,
|
|
15
|
+
v: z.literal(4),
|
|
16
|
+
kind: z.literal("license"),
|
|
17
|
+
licenseId: id,
|
|
18
|
+
plan: id,
|
|
19
|
+
entitlements: z.record(z.string().min(1).max(64), z.union([z.number().finite(), z.string(), z.boolean()])),
|
|
20
|
+
issuedTo: z.string(),
|
|
21
|
+
subject: z.object({ kind: z.enum(["installation", "service"]), id }).strict(),
|
|
22
|
+
offlineGraceUntil: date,
|
|
23
|
+
status: z.enum(["active", "revoked", "expired"]),
|
|
24
|
+
})
|
|
25
|
+
.strict()
|
|
26
|
+
.refine((p) => p.subject.id === p.installationId);
|
|
27
|
+
export const trialSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
...common,
|
|
30
|
+
v: z.literal(2),
|
|
31
|
+
kind: z.literal("trial"),
|
|
32
|
+
verdict: z.enum(["fresh", "spent"]),
|
|
33
|
+
allowance: z.number().int().nonnegative().nullable(),
|
|
34
|
+
supportReference: z.string().nullable(),
|
|
35
|
+
})
|
|
36
|
+
.strict();
|
|
37
|
+
export class TokenError extends Error {
|
|
38
|
+
code;
|
|
39
|
+
constructor(code) {
|
|
40
|
+
super(`KeyForge token rejected (${code}).`);
|
|
41
|
+
this.code = code;
|
|
42
|
+
this.name = "TokenError";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function encodeBase64url(bytes) {
|
|
46
|
+
return btoa(Array.from(bytes, (n) => String.fromCharCode(n)).join(""))
|
|
47
|
+
.replace(/=/g, "")
|
|
48
|
+
.replace(/\+/g, "-")
|
|
49
|
+
.replace(/\//g, "_");
|
|
50
|
+
}
|
|
51
|
+
function decodeBase64url(encoded) {
|
|
52
|
+
if (!/^[A-Za-z0-9_-]+$/.test(encoded))
|
|
53
|
+
throw new TokenError("malformed_token");
|
|
54
|
+
let bytes;
|
|
55
|
+
try {
|
|
56
|
+
bytes = Uint8Array.from(atob(encoded.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw new TokenError("malformed_token");
|
|
60
|
+
}
|
|
61
|
+
if (encodeBase64url(bytes) !== encoded)
|
|
62
|
+
throw new TokenError("malformed_token");
|
|
63
|
+
return bytes;
|
|
64
|
+
}
|
|
65
|
+
/** Authenticates a token, including its context. Expiry/status are evaluated separately
|
|
66
|
+
* so signed negative grants can replace a previously active cached grant. */
|
|
67
|
+
export async function verifySignedToken(token, context) {
|
|
68
|
+
if (typeof token !== "string" || token.length > 65536)
|
|
69
|
+
throw new TokenError("malformed_token");
|
|
70
|
+
const parts = token.split(".");
|
|
71
|
+
if (parts.length !== 2)
|
|
72
|
+
throw new TokenError("malformed_token");
|
|
73
|
+
const bytes = decodeBase64url(parts[0]), signature = decodeBase64url(parts[1]);
|
|
74
|
+
if (signature.length !== 64)
|
|
75
|
+
throw new TokenError("malformed_token");
|
|
76
|
+
let input;
|
|
77
|
+
try {
|
|
78
|
+
input = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
throw new TokenError("malformed_token");
|
|
82
|
+
}
|
|
83
|
+
const parsed = z.union([licenseSchema, trialSchema]).safeParse(input);
|
|
84
|
+
if (!parsed.success)
|
|
85
|
+
throw new TokenError("invalid_payload");
|
|
86
|
+
const p = parsed.data;
|
|
87
|
+
if (p.productId !== context.productId ||
|
|
88
|
+
p.installationId !== context.installationId ||
|
|
89
|
+
(p.kind === "license" && p.subject.kind !== (context.subjectKind ?? "installation")))
|
|
90
|
+
throw new TokenError("context_mismatch");
|
|
91
|
+
const pem = Object.hasOwn(context.publicKeys, p.kid) ? context.publicKeys[p.kid] : undefined;
|
|
92
|
+
if (!pem)
|
|
93
|
+
throw new TokenError("unknown_key");
|
|
94
|
+
try {
|
|
95
|
+
if (!/^-----BEGIN PUBLIC KEY-----\s+[A-Za-z0-9+/=\s]+-----END PUBLIC KEY-----\s*$/.test(pem))
|
|
96
|
+
throw new Error("Invalid public key");
|
|
97
|
+
const der = Uint8Array.from(atob(pem.replace(/-----[^-]+-----/g, "").replace(/\s/g, "")), (c) => c.charCodeAt(0));
|
|
98
|
+
const key = await crypto.subtle.importKey("spki", der, { name: "Ed25519" }, false, ["verify"]);
|
|
99
|
+
// Current v4/v2 server contract signs decoded JSON bytes, not the base64url segment.
|
|
100
|
+
if (!(await crypto.subtle.verify("Ed25519", key, signature, bytes)))
|
|
101
|
+
throw new Error("Invalid signature");
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
throw new TokenError("invalid_signature");
|
|
105
|
+
}
|
|
106
|
+
const now = context.now ?? Date.now(), tolerance = context.clockToleranceMs ?? 300000;
|
|
107
|
+
if (!Number.isFinite(now) || !Number.isFinite(tolerance) || tolerance < 0)
|
|
108
|
+
throw new TokenError("invalid_clock");
|
|
109
|
+
if (Date.parse(p.issuedAt) > now + tolerance)
|
|
110
|
+
throw new TokenError("future_issuance");
|
|
111
|
+
return p;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACtC,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AACnD,MAAM,MAAM,GAAG;IACb,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IACzB,SAAS,EAAE,EAAE;IACb,GAAG,EAAE,EAAE;IACP,cAAc,EAAE,EAAE;IAClB,QAAQ,EAAE,IAAI;IACd,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE;CAC3B,CAAC;AACF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC;KAC3B,MAAM,CAAC;IACN,GAAG,MAAM;IACT,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACf,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IAC1B,SAAS,EAAE,EAAE;IACb,IAAI,EAAE,EAAE;IACR,YAAY,EAAE,CAAC,CAAC,MAAM,CACpB,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EACzB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CACxD;IACD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IAC7E,iBAAiB,EAAE,IAAI;IACvB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;CACjD,CAAC;KACD,MAAM,EAAE;KACR,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,cAAc,CAAC,CAAC;AACpD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC;KACzB,MAAM,CAAC;IACN,GAAG,MAAM;IACT,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACf,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACxB,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACnC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IACpD,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACxC,CAAC;KACD,MAAM,EAAE,CAAC;AAKZ,MAAM,OAAO,UAAW,SAAQ,KAAK;IACP,IAAI;IAAhC,YAA4B,IAAY;QACtC,KAAK,CAAC,4BAA4B,IAAI,IAAI,CAAC,CAAC;oBADlB,IAAI;QAE9B,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AASD,MAAM,UAAU,eAAe,CAAC,KAAiB;IAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SACnE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;SACjB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACzB,CAAC;AACD,SAAS,eAAe,CAAC,OAAe;IACtC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC/E,IAAI,KAA8B,CAAC;IACnC,IAAI,CAAC;QACH,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CACjF,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAChB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,eAAe,CAAC,KAAK,CAAC,KAAK,OAAO;QAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAChF,OAAO,KAAK,CAAC;AACf,CAAC;AAED;6EAC6E;AAC7E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAa,EACb,OAA4B;IAE5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK;QAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC/F,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EACrC,SAAS,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE;QAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,CAAC,CAAC;IACrE,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9E,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACtE,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC7D,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;IACtB,IACE,CAAC,CAAC,SAAS,KAAK,OAAO,CAAC,SAAS;QACjC,CAAC,CAAC,cAAc,KAAK,OAAO,CAAC,cAAc;QAC3C,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,IAAI,cAAc,CAAC,CAAC;QAEpF,MAAM,IAAI,UAAU,CAAC,kBAAkB,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7F,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,UAAU,CAAC,aAAa,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,IAAI,CAAC,6EAA6E,CAAC,IAAI,CAAC,GAAG,CAAC;YAC1F,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACxC,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAC9F,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAChB,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC/F,qFAAqF;QACrF,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,UAAU,CAAC,mBAAmB,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EACnC,SAAS,GAAG,OAAO,CAAC,gBAAgB,IAAI,MAAM,CAAC;IACjD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,GAAG,CAAC;QACvE,MAAM,IAAI,UAAU,CAAC,eAAe,CAAC,CAAC;IACxC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,GAAG,GAAG,SAAS;QAAE,MAAM,IAAI,UAAU,CAAC,iBAAiB,CAAC,CAAC;IACtF,OAAO,CAAC,CAAC;AACX,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { LicenseToken, TrialToken } from "./tokens.js";
|
|
2
|
+
export declare const DEVICE_SIGNAL_KINDS: readonly ["machine-guid", "smbios-uuid", "volume-serial", "linux-machine-id", "macos-platform-uuid", "root-volume-uuid"];
|
|
3
|
+
export type DeviceSignalKind = (typeof DEVICE_SIGNAL_KINDS)[number];
|
|
4
|
+
export interface DeviceSignal {
|
|
5
|
+
kind: DeviceSignalKind;
|
|
6
|
+
hash: string;
|
|
7
|
+
}
|
|
8
|
+
export interface DeviceSignalsReport {
|
|
9
|
+
signals: DeviceSignal[];
|
|
10
|
+
diagnostics: {
|
|
11
|
+
kind: DeviceSignalKind;
|
|
12
|
+
status: "available" | "unavailable" | "invalid" | "timeout" | "permission_denied" | "unsupported" | "query_failed";
|
|
13
|
+
}[];
|
|
14
|
+
}
|
|
15
|
+
export type DeviceSignalsProvider = (context: {
|
|
16
|
+
serverUrl: string;
|
|
17
|
+
productId: string;
|
|
18
|
+
}) => Promise<DeviceSignalsReport>;
|
|
19
|
+
export interface RegistrationMetadata {
|
|
20
|
+
appVersion?: string;
|
|
21
|
+
platform?: string;
|
|
22
|
+
userName?: string;
|
|
23
|
+
userEmail?: string;
|
|
24
|
+
machineSignals?: DeviceSignal[];
|
|
25
|
+
}
|
|
26
|
+
export interface ClientState {
|
|
27
|
+
version: 1;
|
|
28
|
+
serverUrl: string;
|
|
29
|
+
productId: string;
|
|
30
|
+
subjectKind: "installation" | "service";
|
|
31
|
+
installationId: string;
|
|
32
|
+
credential: string;
|
|
33
|
+
registration: RegistrationMetadata & {
|
|
34
|
+
installationId: string;
|
|
35
|
+
requestId: string;
|
|
36
|
+
};
|
|
37
|
+
registered: boolean;
|
|
38
|
+
trialStarted: boolean;
|
|
39
|
+
trialConsumed: number;
|
|
40
|
+
trialToken: string | null;
|
|
41
|
+
licenseToken: string | null;
|
|
42
|
+
denial: string | null;
|
|
43
|
+
lastObservedTime: number;
|
|
44
|
+
deviceSignals?: DeviceSignalsReport;
|
|
45
|
+
}
|
|
46
|
+
/** One owner per installation. load returns a snapshot; save atomically replaces it.
|
|
47
|
+
* Production implementations must protect credentials using platform secure storage. */
|
|
48
|
+
export interface SecureStorage {
|
|
49
|
+
load(): Promise<ClientState | null>;
|
|
50
|
+
save(state: ClientState): Promise<void>;
|
|
51
|
+
}
|
|
52
|
+
export type Authorization = {
|
|
53
|
+
state: "unlicensed";
|
|
54
|
+
reason: string;
|
|
55
|
+
} | {
|
|
56
|
+
state: "trial";
|
|
57
|
+
token: TrialToken;
|
|
58
|
+
remaining: number | null;
|
|
59
|
+
} | {
|
|
60
|
+
state: "licensed";
|
|
61
|
+
token: LicenseToken;
|
|
62
|
+
entitlements: LicenseToken["entitlements"];
|
|
63
|
+
deadline: string;
|
|
64
|
+
} | {
|
|
65
|
+
state: "reconnect_required" | "expired" | "revoked";
|
|
66
|
+
reason: string;
|
|
67
|
+
};
|
|
68
|
+
export interface NotificationPreferences {
|
|
69
|
+
messages: boolean;
|
|
70
|
+
expirations: boolean;
|
|
71
|
+
}
|
|
72
|
+
export type CustomerNotification = {
|
|
73
|
+
id: string;
|
|
74
|
+
title: string;
|
|
75
|
+
date: string;
|
|
76
|
+
read: boolean;
|
|
77
|
+
} & ({
|
|
78
|
+
kind: "reply";
|
|
79
|
+
ticketId: string;
|
|
80
|
+
} | {
|
|
81
|
+
kind: "expiration";
|
|
82
|
+
licenseId: string;
|
|
83
|
+
} | {
|
|
84
|
+
kind: "license";
|
|
85
|
+
licenseId: string;
|
|
86
|
+
deliveryStatus: "available" | "retrieved" | "failed" | "manual";
|
|
87
|
+
collectPath: string;
|
|
88
|
+
});
|
|
89
|
+
export interface CustomerThread {
|
|
90
|
+
id: string;
|
|
91
|
+
revision: number;
|
|
92
|
+
licenseId: string;
|
|
93
|
+
installationId: string;
|
|
94
|
+
clientRequestId: string;
|
|
95
|
+
category: SupportRequest["category"];
|
|
96
|
+
urgency: SupportRequest["urgency"];
|
|
97
|
+
subject: string;
|
|
98
|
+
message: string;
|
|
99
|
+
status: "queued" | "in_progress" | "waiting_customer" | "resolved" | "closed";
|
|
100
|
+
receivedAt: string;
|
|
101
|
+
updatedAt: string;
|
|
102
|
+
messages: {
|
|
103
|
+
id: string;
|
|
104
|
+
author: "customer" | "support";
|
|
105
|
+
internal: false;
|
|
106
|
+
body: string;
|
|
107
|
+
createdAt: string;
|
|
108
|
+
}[];
|
|
109
|
+
}
|
|
110
|
+
export interface SupportRequest {
|
|
111
|
+
requestId: string;
|
|
112
|
+
licenseId: string;
|
|
113
|
+
category: "technical" | "licensing" | "billing" | "feature_request" | "other";
|
|
114
|
+
urgency: "low" | "normal" | "high" | "critical";
|
|
115
|
+
subject: string;
|
|
116
|
+
message: string;
|
|
117
|
+
createdAt: string;
|
|
118
|
+
reporter?: {
|
|
119
|
+
name?: string;
|
|
120
|
+
};
|
|
121
|
+
app?: {
|
|
122
|
+
version?: string;
|
|
123
|
+
platform?: string;
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
export interface ValidationResult {
|
|
127
|
+
valid: true;
|
|
128
|
+
id: string;
|
|
129
|
+
plan: string;
|
|
130
|
+
issuedTo: string;
|
|
131
|
+
expiresAt: string | null;
|
|
132
|
+
entitlements: Record<string, string | number | boolean>;
|
|
133
|
+
seatsInUse: number;
|
|
134
|
+
seatsAvailable: number;
|
|
135
|
+
serverTime: string;
|
|
136
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,cAAc;IACd,aAAa;IACb,eAAe;IACf,kBAAkB;IAClB,qBAAqB;IACrB,kBAAkB;CACV,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DeviceSignalKind, DeviceSignalsProvider } from "./types.js";
|
|
2
|
+
export { DeviceSignalQueryError as WindowsQueryError, hashDeviceIdentifier as hashWindowsIdentifier, normalizeDeviceIdentifier as normalizeWindowsIdentifier, } from "./device-signals-node.js";
|
|
3
|
+
export interface WindowsDeviceSignalsOptions {
|
|
4
|
+
/** Test seam: return one identifier, never command output or errors containing it. */
|
|
5
|
+
query?: (kind: DeviceSignalKind) => Promise<string>;
|
|
6
|
+
platform?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function createWindowsDeviceSignalsProvider(options?: WindowsDeviceSignalsOptions): DeviceSignalsProvider;
|