@carchalabs/seal-electron 0.6.0 → 0.6.2

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 CHANGED
@@ -1,109 +1,12 @@
1
- Carcha Seal SDK License
2
- Version 1.0, 7 November 2026
1
+ Carcha Seal SDK
2
+ Copyright (c) 2026 Bugra Omer Aydemir (Carcha Labs). All rights reserved.
3
3
 
4
- Copyright (c) 2026 Bugra Omer Aydemir (Carcha Labs) ("we", "us").
5
- All rights not expressly granted below are reserved.
4
+ This software is proprietary. You may use, copy and distribute it only as section 5 (the SDK license) of the
5
+ Carcha Seal Vendor Terms allows: https://seal.carchalabs.com/terms/. You accept those terms by creating a Carcha
6
+ Seal account or by using this software.
6
7
 
7
- This license covers the software in the carcha-seal-sdk repository and the packages
8
- built from it (the "SDK"). The source code is published so that you can review it;
9
- publishing it does not make it open source. Versions of the SDK published before
10
- 7 November 2026 were released under the MIT License, which still applies to those
11
- versions.
8
+ Open-source components included in this software are licensed under their own licenses, reproduced in
9
+ THIRD-PARTY-NOTICES.txt where a package contains any.
12
10
 
13
- 1. Definitions
14
-
15
- "Carcha Seal Service" means a license server operated by us, or a license server you
16
- run under a written agreement with us.
17
-
18
- "Your Application" means software that you develop and provide to your own customers,
19
- that uses the SDK to obtain and check licenses from the Carcha Seal Service, and whose
20
- main purpose is not licensing, license management, copy protection or software
21
- protection.
22
-
23
- "End Users" means the people and organizations that receive Your Application from you.
24
-
25
- 2. What you may do
26
-
27
- As long as you comply with this license, we grant you a non-exclusive, worldwide,
28
- royalty-free, non-transferable license, which you may not sublicense except as
29
- section 2(c) allows, to:
30
-
31
- (a) use, copy and modify the SDK to integrate Your Application with the Carcha Seal
32
- Service;
33
-
34
- (b) read and study the SDK's source code, for example to evaluate the SDK or to review
35
- its security; and
36
-
37
- (c) distribute the SDK, unmodified or modified under (a), only as part of Your
38
- Application, in object code or source code form, and let your End Users use it
39
- only as part of Your Application.
40
-
41
- 3. What you may not do
42
-
43
- You may not, and may not allow anyone else to:
44
-
45
- (a) sell, license, rent, lend or otherwise distribute the SDK, or any part or modified
46
- version of it, on its own or as part of a software development kit, library,
47
- framework or other product for developers;
48
-
49
- (b) use the SDK, or any part or modified version of it, with a license server or
50
- service other than the Carcha Seal Service, except a test server you run only to
51
- test Your Application;
52
-
53
- (c) use the SDK, or any part, modified version or translation of it, in a product or
54
- service that substitutes for the Carcha Seal Service or the SDK, or that offers the
55
- same or substantially similar functionality;
56
-
57
- (d) reverse engineer, decompile or disassemble the compiled parts of the SDK (such as
58
- its native libraries), or otherwise try to derive source code we have not
59
- published, except to the extent applicable law permits it despite this
60
- restriction;
61
-
62
- (e) disable, bypass or tamper with the SDK's license checks, signature verification,
63
- encryption or device binding, or help anyone else do so, in any application that
64
- uses the Carcha Seal Service, except in Your Application while you test it;
65
-
66
- (f) remove or change this license or any copyright or other notice in the SDK; or
67
-
68
- (g) use our names, logos or trademarks, including "Carcha Seal" and "Carcha Labs",
69
- except to state truthfully that Your Application uses Carcha Seal.
70
-
71
- 4. Your End Users
72
-
73
- Your terms for Your Application must not give your End Users more rights in the SDK
74
- than to use it as part of Your Application. You are responsible for your End Users'
75
- use of the SDK as part of Your Application.
76
-
77
- 5. Contributions
78
-
79
- If you send us changes or suggestions for the SDK, you grant us a perpetual,
80
- irrevocable, worldwide, royalty-free license to use, modify and distribute them for
81
- any purpose.
82
-
83
- 6. Termination
84
-
85
- Your rights under this license end automatically if you breach it. If you end the
86
- breach within 30 days after we notify you of it, your rights are restored, unless you
87
- have breached this license before. When your rights end, you must stop using and
88
- distributing the SDK; your End Users may keep using copies of Your Application they
89
- received before then. Sections 3, 5, 7 and 8 continue to apply after termination.
90
-
91
- 7. No warranty
92
-
93
- To the extent the law allows, the SDK is provided "as is", without warranty of any
94
- kind, express or implied, including warranties of merchantability, fitness for a
95
- particular purpose and non-infringement. If you have a separate written agreement with
96
- us for the Carcha Seal Service, its terms on warranty and liability apply to the SDK
97
- instead of sections 7 and 8.
98
-
99
- 8. Limitation of liability
100
-
101
- To the extent the law allows, we are not liable for any damages arising from the SDK
102
- or this license. Nothing in this license limits or excludes liability that cannot be
103
- limited or excluded under applicable law, including liability for intent or gross
104
- negligence, for death or personal injury, or under product liability law.
105
-
106
- 9. New versions of this license
107
-
108
- We may publish new versions of this license. Each version of the SDK stays under the
109
- license it was published with.
11
+ Earlier versions keep the license they were published with: versions published before 7 November 2026 are under
12
+ the MIT License; versions published on 7 November 2026 are under the Carcha Seal SDK License 1.0.
package/README.md CHANGED
@@ -33,4 +33,4 @@ The SDK sends the license key, a per-product SHA-256 hash of the operating syste
33
33
 
34
34
  **Hardware components.** When `@carchalabs/seal-hwid` is installed, the SDK also sends one keyed hash per hardware part (motherboard, disk, network card, OS install, CPU and graphics models) and whether the computer is a virtual machine. The license server then recognises the computer after a new disk, network card or operating system install, and refuses a copied disk or system image on other hardware. Raw serial numbers never leave the computer. Without the package, or on a platform it has no module for, nothing extra is sent. `hardware: false` turns it off. Bundlers must leave the package to Node (mark it external); electron-builder unpacks its native module from the asar archive.
35
35
 
36
- Integration guide (activate once, check at start, put feature code behind `decrypt`, ship the native module, harden the app): [seal.carchalabs.com/docs/#integration](https://seal.carchalabs.com/docs/#integration). Full reference: [seal.carchalabs.com/docs](https://seal.carchalabs.com/docs/#sdk). Requires Node 22.13 or later. [Carcha Seal SDK License](LICENSE): for apps that use Carcha Seal; versions before 7 November 2026 are MIT.
36
+ Integration guide (activate once, check at start, put feature code behind `decrypt`, ship the native module, harden the app): [seal.carchalabs.com/docs/#integration](https://seal.carchalabs.com/docs/#integration). Full reference: [seal.carchalabs.com/docs](https://seal.carchalabs.com/docs/#sdk). Requires Node 22.13 or later. Proprietary: use under the [Carcha Seal Vendor Terms](https://seal.carchalabs.com/terms/) ([LICENSE](LICENSE)).
@@ -94,4 +94,3 @@ function fallbackTraits() {
94
94
  .sort();
95
95
  return [(0, node_os_1.hostname)(), (0, node_os_1.cpus)()[0]?.model ?? '', macs[0] ?? ''].join('|');
96
96
  }
97
- //# sourceMappingURL=fingerprint.js.map
package/dist/index.d.ts CHANGED
@@ -80,6 +80,8 @@ export declare class Seal {
80
80
  /** The native lease verifier, when it trusts every key this app was given (undefined = not looked up yet). */
81
81
  private nativeLease?;
82
82
  private deviceKeyCache?;
83
+ /** The end of the operations waiting to run; see serial(). */
84
+ private queue;
83
85
  constructor(opts: SealOptions);
84
86
  private get fetch();
85
87
  private nowSec;
@@ -89,10 +91,17 @@ export declare class Seal {
89
91
  private hardware;
90
92
  /** The saved record; null when there is none, or it cannot be read or is not a record (as no license). */
91
93
  private load;
92
- /** Replaces license.dat whole: written to license.dat.tmp, then renamed over it, so a crash or full disk mid-write
93
- * leaves the previous record. */
94
+ /** Replaces license.dat whole: written to a temporary file of this save, then renamed over it, so a crash or full disk
95
+ * mid-write leaves the previous record. */
94
96
  private save;
95
97
  private clear;
98
+ /**
99
+ * Runs the operations that change license.dat one at a time, in the order they were called, as the native SDKs' lock
100
+ * does. Node.js calls writing one file from calls that overlap unsafe, and the answer to an earlier call (a slow
101
+ * check-in for the old key) must not replace what a later one saved (an activation with a new key). Reads
102
+ * (decrypt, requireEncrypted) do not wait: the file is replaced whole, so a read sees one record or the other.
103
+ */
104
+ private serial;
96
105
  private post;
97
106
  private emptyState;
98
107
  /**
@@ -115,7 +124,9 @@ export declare class Seal {
115
124
  private stateFromLease;
116
125
  /** machineName: the name to show the vendor for this device. Nothing is sent when the app gives none (host names often hold a person's name). */
117
126
  activate(licenseKey: string, machineName?: string): Promise<LicenseState>;
127
+ private activateNow;
118
128
  check(): Promise<LicenseState>;
129
+ private checkNow;
119
130
  /** The state from the saved record when the server gave no usable answer; a usable lease moves lastSeen forward. */
120
131
  private offlineCheck;
121
132
  /**
@@ -158,13 +169,16 @@ export declare class Seal {
158
169
  * LicenseError: `invalid_file`, `wrong_product`, or a lease failure reason such as `wrong_device`.
159
170
  */
160
171
  activateOffline(licenseFile: string): Promise<LicenseState>;
172
+ private activateOfflineNow;
161
173
  /**
162
174
  * Gives an offline machine's seat back: removes the license from this device and returns the
163
175
  * deactivation file (JSON text) for the vendor, who frees the seat by uploading it in the console.
164
176
  * Throws `unlicensed` when there is no license to remove.
165
177
  */
166
178
  deactivateOffline(): Promise<string>;
179
+ private deactivateOfflineNow;
167
180
  deactivate(): Promise<void>;
181
+ private deactivateNow;
168
182
  static hasFeature(state: LicenseState, feature: string): boolean;
169
183
  }
170
184
  /** The SDK class under its earlier name (LicenseKit). Same class; use Seal in new code. */
package/dist/index.js CHANGED
@@ -35,11 +35,44 @@ function loadHwid() {
35
35
  }
36
36
  return hwidModule;
37
37
  }
38
+ /**
39
+ * The largest answer read, as in the native SDKs: a lease and its notices are a few kilobytes. A longer one is read as no
40
+ * answer, so a broken or hostile server cannot make the app hold and parse hundreds of megabytes.
41
+ */
42
+ const MAX_ANSWER_BYTES = 1 << 20;
43
+ /** The answer's body as text; null when it is longer than MAX_ANSWER_BYTES or could not be read to its end. */
44
+ async function readLimited(res) {
45
+ const declared = Number(res.headers.get('content-length') ?? NaN);
46
+ if (declared > MAX_ANSWER_BYTES || !res.body) {
47
+ await res.body?.cancel().catch(() => { });
48
+ return res.body ? null : '';
49
+ }
50
+ const reader = res.body.getReader();
51
+ const chunks = [];
52
+ let length = 0;
53
+ try {
54
+ for (;;) {
55
+ const { done, value } = await reader.read();
56
+ if (done)
57
+ break;
58
+ length += value.byteLength;
59
+ if (length > MAX_ANSWER_BYTES) {
60
+ await reader.cancel().catch(() => { });
61
+ return null;
62
+ }
63
+ chunks.push(value);
64
+ }
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ // UTF-8 as response.json() decodes it (a byte order mark dropped).
70
+ return new TextDecoder().decode(Buffer.concat(chunks));
71
+ }
72
+ /** Numbers this process's temporary files (see Seal.save). */
73
+ let tempCounter = 0;
38
74
  /** The server accepts at most this many components. */
39
75
  const MAX_COMPONENTS = 32;
40
- /** The license itself is gone: forget the key too. The other refusals can be undone on the server (resume, renew,
41
- * re-activate), so the key is kept and the next successful online check restores the license on its own. */
42
- const FORGET_KEY = new Set(['invalid_key', 'license_revoked']);
43
76
  const CLOCK_TOLERANCE_SECONDS = 24 * 3600;
44
77
  /**
45
78
  * A check-in answered 2xx whose lease fails for one of these reasons did not come from this app's license server for
@@ -128,6 +161,8 @@ class Seal {
128
161
  /** The native lease verifier, when it trusts every key this app was given (undefined = not looked up yet). */
129
162
  nativeLease;
130
163
  deviceKeyCache;
164
+ /** The end of the operations waiting to run; see serial(). */
165
+ queue = Promise.resolve();
131
166
  constructor(opts) {
132
167
  this.opts = opts;
133
168
  checkServerUrl(opts.serverUrl);
@@ -191,24 +226,53 @@ class Seal {
191
226
  return null;
192
227
  }
193
228
  }
194
- /** Replaces license.dat whole: written to license.dat.tmp, then renamed over it, so a crash or full disk mid-write
195
- * leaves the previous record. */
229
+ /** Replaces license.dat whole: written to a temporary file of this save, then renamed over it, so a crash or full disk
230
+ * mid-write leaves the previous record. */
196
231
  async save(stored) {
197
232
  await (0, promises_1.mkdir)(this.opts.storageDir, { recursive: true });
198
233
  const text = JSON.stringify(stored);
199
- const temp = this.file + '.tmp';
200
- try {
201
- await (0, promises_1.writeFile)(temp, this.opts.secureStore ? await this.opts.secureStore.encrypt(text) : text, { mode: 0o600, flush: true });
202
- await (0, promises_1.rename)(temp, this.file);
203
- }
204
- catch (e) {
205
- await (0, promises_1.rm)(temp, { force: true }).catch(() => { });
206
- throw e;
234
+ const data = this.opts.secureStore ? await this.opts.secureStore.encrypt(text) : text;
235
+ // license.dat.<pid>.<n>.tmp, created only if it does not exist (flag wx; SEI CERT FIO21-C: a unique name, opened
236
+ // exclusively, owner-only), so two app instances saving at the same time each write and rename their own file.
237
+ // A name left by a process that crashed is skipped.
238
+ for (let attempt = 0;; attempt++) {
239
+ const temp = `${this.file}.${process.pid}.${tempCounter++}.tmp`;
240
+ try {
241
+ await (0, promises_1.writeFile)(temp, data, { mode: 0o600, flush: true, flag: 'wx' });
242
+ }
243
+ catch (e) {
244
+ if (e.code === 'EEXIST') {
245
+ if (attempt < 100)
246
+ continue; // another file's name: not ours to remove
247
+ throw e;
248
+ }
249
+ await (0, promises_1.rm)(temp, { force: true }).catch(() => { }); // ours, cut off mid-write
250
+ throw e;
251
+ }
252
+ try {
253
+ await (0, promises_1.rename)(temp, this.file);
254
+ return;
255
+ }
256
+ catch (e) {
257
+ await (0, promises_1.rm)(temp, { force: true }).catch(() => { });
258
+ throw e;
259
+ }
207
260
  }
208
261
  }
209
262
  async clear() {
210
263
  await (0, promises_1.rm)(this.file, { force: true });
211
264
  }
265
+ /**
266
+ * Runs the operations that change license.dat one at a time, in the order they were called, as the native SDKs' lock
267
+ * does. Node.js calls writing one file from calls that overlap unsafe, and the answer to an earlier call (a slow
268
+ * check-in for the old key) must not replace what a later one saved (an activation with a new key). Reads
269
+ * (decrypt, requireEncrypted) do not wait: the file is replaced whole, so a read sees one record or the other.
270
+ */
271
+ serial(operation) {
272
+ const run = this.queue.then(operation);
273
+ this.queue = run.catch(() => undefined);
274
+ return run;
275
+ }
212
276
  async post(path, body) {
213
277
  let res;
214
278
  try {
@@ -225,7 +289,19 @@ class Seal {
225
289
  catch {
226
290
  throw new LicenseError('network', 'Could not reach the license server.');
227
291
  }
228
- const json = await res.json().catch(() => ({}));
292
+ const text = await readLimited(res);
293
+ // Longer than the limit, or cut off (the timeout, a broken connection): no answer, as in the native SDKs.
294
+ if (text === null)
295
+ throw new LicenseError('network', 'Could not reach the license server.');
296
+ let json;
297
+ try {
298
+ json = JSON.parse(text);
299
+ }
300
+ catch {
301
+ json = {};
302
+ }
303
+ if (typeof json !== 'object' || json === null)
304
+ json = {};
229
305
  if (!res.ok)
230
306
  throw new LicenseError(json.error ?? 'server_error', json.message ?? `License server error (${res.status})`, res.status);
231
307
  return json;
@@ -334,7 +410,10 @@ class Seal {
334
410
  return this.emptyState('invalid', offline, { reason: strict.reason, message: REASON_TEXT[strict.reason], keyHint });
335
411
  }
336
412
  /** machineName: the name to show the vendor for this device. Nothing is sent when the app gives none (host names often hold a person's name). */
337
- async activate(licenseKey, machineName) {
413
+ activate(licenseKey, machineName) {
414
+ return this.serial(() => this.activateNow(licenseKey, machineName));
415
+ }
416
+ async activateNow(licenseKey, machineName) {
338
417
  const fingerprint = await this.fingerprint();
339
418
  const key = licenseKey.trim().toUpperCase();
340
419
  const response = await this.post('/v1/activate', {
@@ -355,7 +434,10 @@ class Seal {
355
434
  await this.save(stored);
356
435
  return state;
357
436
  }
358
- async check() {
437
+ check() {
438
+ return this.serial(() => this.checkNow());
439
+ }
440
+ async checkNow() {
359
441
  try {
360
442
  await this.fingerprint();
361
443
  }
@@ -390,11 +472,11 @@ class Seal {
390
472
  }
391
473
  catch (e) {
392
474
  if (e instanceof LicenseError && DEFINITIVE.has(e.code)) {
393
- // Persist the refusal: drop the signed lease so going offline cannot bring the license back.
394
- if (FORGET_KEY.has(e.code))
395
- await this.clear();
396
- else
397
- await this.save({ licenseKey: stored.licenseKey, lastSeen: stored.lastSeen, refused: { code: e.code, message: e.message, at: this.nowSec() } });
475
+ // Persist the refusal: drop the signed lease so going offline cannot bring the license back. The key is kept, also
476
+ // for invalid_key and license_revoked: a refusal is not signed, so anything that answers on the connection (a
477
+ // TLS-inspecting proxy) could send one, and the next check-in the server answers with a lease restores the
478
+ // license. A refusal that is real stays one: the server refuses the kept key again.
479
+ await this.save({ licenseKey: stored.licenseKey, lastSeen: stored.lastSeen, refused: { code: e.code, message: e.message, at: this.nowSec() } });
398
480
  const keyHint = `${stored.licenseKey.slice(0, 7)}…${stored.licenseKey.slice(-4)}`;
399
481
  return this.emptyState('invalid', false, { reason: e.code, message: e.message, keyHint });
400
482
  }
@@ -539,7 +621,10 @@ class Seal {
539
621
  * check() works without the server until the lease's renewal date plus the offline grace. Throws a
540
622
  * LicenseError: `invalid_file`, `wrong_product`, or a lease failure reason such as `wrong_device`.
541
623
  */
542
- async activateOffline(licenseFile) {
624
+ activateOffline(licenseFile) {
625
+ return this.serial(() => this.activateOfflineNow(licenseFile));
626
+ }
627
+ async activateOfflineNow(licenseFile) {
543
628
  await this.fingerprint();
544
629
  let file;
545
630
  try {
@@ -566,14 +651,20 @@ class Seal {
566
651
  * deactivation file (JSON text) for the vendor, who frees the seat by uploading it in the console.
567
652
  * Throws `unlicensed` when there is no license to remove.
568
653
  */
569
- async deactivateOffline() {
654
+ deactivateOffline() {
655
+ return this.serial(() => this.deactivateOfflineNow());
656
+ }
657
+ async deactivateOfflineNow() {
570
658
  const stored = await this.load();
571
659
  if (!stored?.token)
572
660
  throw new LicenseError('unlicensed', 'This device has no license.');
573
661
  await this.clear();
574
662
  return JSON.stringify({ format: OFFLINE_DEACTIVATION_FORMAT, version: 1, product: this.opts.product, token: stored.token }, null, 2);
575
663
  }
576
- async deactivate() {
664
+ deactivate() {
665
+ return this.serial(() => this.deactivateNow());
666
+ }
667
+ async deactivateNow() {
577
668
  const stored = await this.load();
578
669
  if (!stored)
579
670
  return;
@@ -597,4 +688,3 @@ class Seal {
597
688
  }
598
689
  exports.Seal = Seal;
599
690
  exports.LicenseKit = Seal;
600
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,24 +1,24 @@
1
1
  {
2
2
  "name": "@carchalabs/seal-electron",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Carcha Seal (formerly LicenseKit) SDK for the Electron main process and Node: activation, offline verification, grace period",
5
5
  "keywords": ["electron", "licensing", "license-key", "software-licensing", "offline-licensing", "node-locked", "ed25519", "jws", "carcha-seal"],
6
6
  "homepage": "https://seal.carchalabs.com/docs/",
7
7
  "repository": { "type": "git", "url": "git+https://github.com/carcha-labs/carcha-seal-sdk.git", "directory": "packages/sdk-electron" },
8
- "bugs": { "url": "https://github.com/carcha-labs/carcha-seal-sdk/issues" },
8
+ "bugs": { "email": "bugra@carchalabs.com" },
9
9
  "main": "dist/index.js",
10
10
  "types": "dist/index.d.ts",
11
- "files": ["dist", "src", "!dist/**/*.test.*", "!src/**/*.test.ts"],
11
+ "files": ["dist", "!dist/**/*.test.*", "!dist/**/*.map"],
12
12
  "scripts": {
13
13
  "build": "tsc -p tsconfig.json",
14
14
  "prepublishOnly": "npm run build",
15
15
  "test": "node --no-warnings=ExperimentalWarning --test dist/*.test.js"
16
16
  },
17
17
  "dependencies": {
18
- "@carchalabs/seal-core": "0.5.0"
18
+ "@carchalabs/seal-core": "0.5.1"
19
19
  },
20
20
  "optionalDependencies": {
21
- "@carchalabs/seal-hwid": "0.4.0"
21
+ "@carchalabs/seal-hwid": "0.4.1"
22
22
  },
23
23
  "engines": { "node": ">=22.13" },
24
24
  "publishConfig": { "access": "public" },
@@ -1 +0,0 @@
1
- {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"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"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,103 +0,0 @@
1
- import { execFile } from 'node:child_process';
2
- import { readFile } from 'node:fs/promises';
3
- import { cpus, hostname, networkInterfaces, platform } from 'node:os';
4
- import { win32 } from 'node:path';
5
- import { promisify } from 'node:util';
6
-
7
- const execFileAsync = promisify(execFile);
8
-
9
- /**
10
- * The OS tools are run by absolute path, never looked up through PATH: an app started from a terminal inherits the
11
- * user's PATH, and a fake `ioreg` or `reg` placed first in it could report another computer's id.
12
- */
13
- export const IOREG = '/usr/sbin/ioreg';
14
- export const REG_EXE = [
15
- 'C:\\Windows\\System32\\reg.exe',
16
- win32.join(process.env.SystemRoot || 'C:\\Windows', 'System32', 'reg.exe'),
17
- ].filter((file, index, all) => all.indexOf(file) === index);
18
- export const LINUX_ID_FILES = ['/etc/machine-id', '/var/lib/dbus/machine-id'];
19
-
20
- export interface MachineIdDeps {
21
- platform?: NodeJS.Platform;
22
- /** Attempts to read the OS id before giving up (default 3). */
23
- attempts?: number;
24
- /** Pause between attempts (default 250 ms, doubled each time). */
25
- delayMs?: number;
26
- /**
27
- * Use hostname + CPU + MAC when the OS id cannot be read. Off by default: that value differs from the OS id, so the
28
- * same computer would look like a new device and take another seat.
29
- */
30
- allowFallback?: boolean;
31
- run?: (file: string, args: string[], options: { timeout: number; windowsHide: boolean }) => Promise<{ stdout: string }>;
32
- readText?: (file: string) => Promise<string>;
33
- }
34
-
35
- /** The OS id could not be read; licensing on this computer cannot continue until it can. */
36
- export class MachineIdUnavailableError extends Error {
37
- readonly code = 'machine_id_unavailable';
38
- constructor() {
39
- super('This computer\'s id could not be read. Try again; if it keeps failing, contact the app\'s support.');
40
- this.name = 'MachineIdUnavailableError';
41
- }
42
- }
43
-
44
- /** Reads a stable, OS-provided machine id, retrying a few times. Throws MachineIdUnavailableError unless allowFallback. */
45
- export async function readMachineId(deps: MachineIdDeps = {}): Promise<string> {
46
- const attempts = Math.max(1, deps.attempts ?? 3);
47
- let delay = deps.delayMs ?? 250;
48
- for (let attempt = 1; attempt <= attempts; attempt++) {
49
- const id = await readOsMachineId(deps);
50
- if (id) return id;
51
- if (attempt < attempts) {
52
- await new Promise((resolve) => setTimeout(resolve, delay));
53
- delay *= 2;
54
- }
55
- }
56
- if (deps.allowFallback) return `fallback:${fallbackTraits()}`;
57
- throw new MachineIdUnavailableError();
58
- }
59
-
60
- /** One attempt; null when the OS id is not available. */
61
- async function readOsMachineId(deps: MachineIdDeps): Promise<string | null> {
62
- const os = deps.platform ?? platform();
63
- const run = deps.run ?? ((file, args, options) => execFileAsync(file, args, options));
64
- const readText = deps.readText ?? ((file) => readFile(file, 'utf8'));
65
- try {
66
- if (os === 'darwin') {
67
- const { stdout } = await run(IOREG, ['-rd1', '-c', 'IOPlatformExpertDevice'], { timeout: 3000, windowsHide: true });
68
- const m = stdout.match(/"IOPlatformUUID"\s*=\s*"([^"]+)"/);
69
- if (m) return `mac:${m[1]}`;
70
- } else if (os === 'win32') {
71
- for (const reg of REG_EXE) {
72
- try {
73
- // /reg:64 reads the 64-bit registry view, so a 32-bit build sees the same MachineGuid.
74
- const { stdout } = await run(reg, ['query', 'HKLM\\SOFTWARE\\Microsoft\\Cryptography', '/v', 'MachineGuid', '/reg:64'], {
75
- timeout: 3000,
76
- windowsHide: true,
77
- });
78
- const m = stdout.match(/MachineGuid\s+REG_SZ\s+([\w-]+)/i);
79
- if (m) return `win:${m[1]}`;
80
- } catch {
81
- /* try the next location */
82
- }
83
- }
84
- } else {
85
- for (const f of LINUX_ID_FILES) {
86
- const id = (await readText(f).catch(() => '')).trim();
87
- if (id) return `linux:${id}`;
88
- }
89
- }
90
- } catch {
91
- /* fall through */
92
- }
93
- return null;
94
- }
95
-
96
- function fallbackTraits(): string {
97
- const macs = Object.values(networkInterfaces())
98
- .flat()
99
- .filter((i) => i && !i.internal && i.mac && i.mac !== '00:00:00:00:00:00')
100
- .map((i) => i!.mac)
101
- .sort();
102
- return [hostname(), cpus()[0]?.model ?? '', macs[0] ?? ''].join('|');
103
- }
package/src/index.ts DELETED
@@ -1,692 +0,0 @@
1
- import { KeyObject } from 'node:crypto';
2
- import { existsSync, readFileSync } from 'node:fs';
3
- import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
4
- import { createRequire } from 'node:module';
5
- import { platform } from 'node:os';
6
- import { dirname, join, resolve } from 'node:path';
7
- import { compileFunction } from 'node:vm';
8
- import { decodeLease, decryptFeature, hashFingerprint, keySet, LeaseClaims, LeaseFailure, LeaseVerifyOptions, LeaseVerifyResult, verifyLease } from '@carchalabs/seal-core';
9
- import { MachineIdUnavailableError, readMachineId } from './fingerprint';
10
-
11
- export { MachineIdUnavailableError, readMachineId };
12
-
13
- /** This SDK's version, sent to the server so vendors can see (and require) which SDK each device runs. */
14
- // eslint-disable-next-line @typescript-eslint/no-require-imports
15
- export const SDK_VERSION: string = require('../package.json').version;
16
-
17
- export type LicenseStatus = 'valid' | 'grace' | 'invalid' | 'unlicensed' | 'clock_suspect';
18
-
19
- /**
20
- * Something the server asks the app to act on: sdk_update_recommended (update the Carcha Seal SDK in the app) or
21
- * app_update_recommended (the vendor's minimum app version), each with minimum and requiredFrom.
22
- */
23
- export interface LicenseNotice {
24
- code: string;
25
- minimum?: string;
26
- /** ISO date from which an older SDK is refused; null when the update is only recommended. */
27
- requiredFrom?: string | null;
28
- }
29
-
30
- export interface LicenseState {
31
- status: LicenseStatus;
32
- offline: boolean;
33
- storageProtected: boolean;
34
- reason?: string;
35
- message?: string;
36
- customer?: string;
37
- features: string[];
38
- expiresAt: string | null;
39
- maintenanceUntil?: string | null;
40
- revalidateBy?: string;
41
- keyHint?: string;
42
- /** From the last successful check-in; kept while offline. The app decides how to show them. */
43
- notices?: LicenseNotice[];
44
- /** True when the license came from an offline license file (activateOffline); renew it with a new file. */
45
- offlineActivated?: boolean;
46
- }
47
-
48
- /** Hashed hardware components (see @carchalabs/seal-hwid); the server matches a device by them. */
49
- export interface HardwareReport {
50
- components: { kind: string; hash: string }[];
51
- /** True when the device runs as a virtual machine. */
52
- vm: boolean;
53
- }
54
-
55
- export interface SecureStore {
56
- encrypt(plain: string): Buffer | Promise<Buffer>;
57
- decrypt(cipher: Buffer): string | Promise<string>;
58
- isProtected?(): boolean;
59
- }
60
-
61
- export interface SealOptions {
62
- /** The license server: https://, or http:// on this computer only (localhost, 127.x.x.x, [::1]). */
63
- serverUrl: string;
64
- product: string;
65
- publicKey: string | string[];
66
- storageDir: string;
67
- appVersion?: string;
68
- graceDays?: number;
69
- secureStore?: SecureStore;
70
- requestTimeoutMs?: number;
71
- fetchImpl?: typeof fetch;
72
- machineId?: () => Promise<string>;
73
- /** Use hostname + CPU + MAC when the OS machine id cannot be read (default false; see readMachineId). */
74
- allowFallbackFingerprint?: boolean;
75
- /**
76
- * Hardware components sent with each request, so the device keeps its seat after a new disk, network
77
- * card or OS install. Default: read with @carchalabs/seal-hwid when it is installed; nothing is
78
- * sent when it is not (or cannot load on this platform). false: never send them. A function: your own.
79
- */
80
- hardware?: false | (() => HardwareReport | null | Promise<HardwareReport | null>);
81
- now?: () => number;
82
- }
83
-
84
- interface Stored {
85
- licenseKey: string;
86
- /** Signed lease. Absent after the server refused this device: nothing is left to verify offline. */
87
- token?: string;
88
- lastSeen?: number;
89
- /** The server's last definitive refusal, kept so an offline check reports it instead of an old lease. */
90
- refused?: { code: string; message: string; at: number };
91
- notices?: LicenseNotice[];
92
- /** Activated from an offline license file: check() never calls the server; a new file renews it. */
93
- offline?: boolean;
94
- }
95
-
96
- type Leased = Stored & { token: string };
97
-
98
- /** File formats of offline activation, shared with the license server. */
99
- const OFFLINE_REQUEST_FORMAT = 'licensekit-offline-request';
100
- const OFFLINE_LICENSE_FORMAT = 'licensekit-offline-license';
101
- const OFFLINE_DEACTIVATION_FORMAT = 'licensekit-offline-deactivation';
102
-
103
- const DEFINITIVE = new Set(['invalid_key', 'not_activated', 'license_suspended', 'license_revoked', 'license_expired', 'sdk_update_required', 'app_update_required', 'vm_not_allowed']);
104
- /** The native hardware module. A non-literal require: bundlers leave it to Node, which must load the .node file from disk. */
105
- const HWID_PACKAGE = '@carchalabs/seal-hwid';
106
- /** The native module's lease verifier (@carchalabs/seal-hwid 0.2+): its keys are compiled in. */
107
- interface NativeLease {
108
- verifyLease(token: string, check: { product: string; fingerprintHash: string; now: number; graceSeconds?: number }): { ok: boolean; reason?: string };
109
- leaseKeyIds(): string[];
110
- /** This machine's X25519 public key from its hardware (base64url), or null. */
111
- devicePublicKey?(key: string): string | null;
112
- /** @carchalabs/seal-hwid 0.2+ with feature keys. */
113
- decryptFeature?(
114
- token: string,
115
- check: { product: string; fingerprintHash: string; now: number; graceSeconds?: number },
116
- licenseKey: string,
117
- feature: string,
118
- data: Buffer,
119
- ): { ok: boolean; data?: Buffer; reason?: string };
120
- }
121
-
122
- /** Loads the native module once per process; null when it is not installed or has no build for this platform. */
123
- let hwidModule: any;
124
- function loadHwid(): any {
125
- if (hwidModule === undefined) {
126
- try {
127
- // eslint-disable-next-line @typescript-eslint/no-require-imports
128
- hwidModule = require(HWID_PACKAGE);
129
- } catch {
130
- hwidModule = null;
131
- }
132
- }
133
- return hwidModule;
134
- }
135
-
136
- /** The server accepts at most this many components. */
137
- const MAX_COMPONENTS = 32;
138
- /** The license itself is gone: forget the key too. The other refusals can be undone on the server (resume, renew,
139
- * re-activate), so the key is kept and the next successful online check restores the license on its own. */
140
- const FORGET_KEY = new Set(['invalid_key', 'license_revoked']);
141
- const CLOCK_TOLERANCE_SECONDS = 24 * 3600;
142
- /**
143
- * A check-in answered 2xx whose lease fails for one of these reasons did not come from this app's license server for
144
- * this device (a TLS-inspecting proxy's or captive portal's page, say): it is treated as no answer, and the saved lease
145
- * is kept. A lease that fails only on time (not_yet_valid, expired, revalidation_required) is the server's, and is used.
146
- */
147
- const NOT_A_LEASE_FOR_THIS_DEVICE = new Set(['malformed', 'unsupported_algorithm', 'wrong_type', 'unknown_key', 'bad_signature', 'wrong_issuer', 'wrong_product', 'wrong_device']);
148
- const DEFAULT_GRACE_DAYS = 7;
149
- const CLOCK_MESSAGE = 'The date and time on this computer look wrong. Correct them, then connect to the internet.';
150
-
151
- export class LicenseError extends Error {
152
- constructor(
153
- public readonly code: string,
154
- message: string,
155
- public readonly status?: number,
156
- ) {
157
- super(message);
158
- this.name = 'LicenseError';
159
- }
160
- }
161
-
162
- /**
163
- * Refuses a server address that would send requests in plain text (OWASP ASVS 4.1.2, 12.2.1): every request
164
- * carries the license key and the device's fingerprint. http:// is accepted for this computer only, where a server
165
- * under development runs; `localhost` and the loopback addresses do not leave the machine.
166
- */
167
- function checkServerUrl(serverUrl: string): void {
168
- let url: URL;
169
- try {
170
- url = new URL(serverUrl);
171
- } catch {
172
- throw new LicenseError('invalid_server_url', 'serverUrl is not a valid URL.');
173
- }
174
- if (url.protocol === 'https:') return;
175
- const loopback = url.hostname === 'localhost' || url.hostname === '[::1]' || /^127(\.\d{1,3}){3}$/.test(url.hostname);
176
- if (url.protocol === 'http:' && loopback) return;
177
- throw new LicenseError('insecure_server_url', 'serverUrl must start with https:// (http:// only for localhost).');
178
- }
179
-
180
- const REASON_TEXT: Record<LeaseFailure, string> = {
181
- malformed: 'The saved license is damaged. Please activate again.',
182
- bad_signature: 'The saved license was modified. Please activate again.',
183
- unsupported_algorithm: 'Please update the app.',
184
- wrong_type: 'Please update the app.',
185
- unknown_key: 'Please update the app.',
186
- wrong_issuer: 'This license was issued by a different license server.',
187
- not_yet_valid: CLOCK_MESSAGE,
188
- wrong_product: 'This license is for a different product.',
189
- wrong_device: 'This license is activated on another device.',
190
- expired: 'Your license has expired.',
191
- revalidation_required: 'Connect to the internet to confirm your license.',
192
- };
193
-
194
- const toIso = (seconds: number) => new Date(seconds * 1000).toISOString();
195
-
196
- /** A saved record of the shape save() writes, keeping only its known fields; null for anything else. */
197
- function parseStored(value: unknown): Stored | null {
198
- if (typeof value !== 'object' || value === null || Array.isArray(value)) return null;
199
- const v = value as Record<string, unknown>;
200
- if (typeof v.licenseKey !== 'string') return null;
201
- const stored: Stored = { licenseKey: v.licenseKey };
202
- if (typeof v.token === 'string') stored.token = v.token;
203
- if (typeof v.lastSeen === 'number' && Number.isFinite(v.lastSeen)) stored.lastSeen = v.lastSeen;
204
- const r = v.refused as Record<string, unknown> | undefined;
205
- if (r && typeof r.code === 'string' && typeof r.message === 'string' && typeof r.at === 'number') stored.refused = { code: r.code, message: r.message, at: r.at };
206
- if (Array.isArray(v.notices)) stored.notices = v.notices.filter((n): n is LicenseNotice => !!n && typeof n.code === 'string');
207
- if (v.offline === true) stored.offline = true;
208
- return stored;
209
- }
210
-
211
- function noticesFrom(response: any): { notices?: LicenseNotice[] } {
212
- const list = Array.isArray(response?.notices) ? response.notices.filter((n: any) => n && typeof n.code === 'string') : [];
213
- return list.length ? { notices: list } : {};
214
- }
215
-
216
- export class Seal {
217
- private readonly file: string;
218
- private readonly keys: Map<string, KeyObject>;
219
- private fingerprintCache?: string;
220
- private hardwareCache?: Promise<HardwareReport | null>;
221
- /** The native lease verifier, when it trusts every key this app was given (undefined = not looked up yet). */
222
- private nativeLease?: NativeLease | null;
223
- private deviceKeyCache?: string | null;
224
-
225
- constructor(private readonly opts: SealOptions) {
226
- checkServerUrl(opts.serverUrl);
227
- this.file = join(opts.storageDir, 'license.dat');
228
- this.keys = keySet(Array.isArray(opts.publicKey) ? opts.publicKey : [opts.publicKey]);
229
- }
230
-
231
- private get fetch() {
232
- return this.opts.fetchImpl ?? fetch;
233
- }
234
-
235
- private nowSec() {
236
- return Math.floor((this.opts.now?.() ?? Date.now()) / 1000);
237
- }
238
-
239
- private get storageProtected(): boolean {
240
- const store = this.opts.secureStore;
241
- return store !== undefined && (store.isProtected?.() ?? true);
242
- }
243
-
244
- async fingerprint(): Promise<string> {
245
- if (!this.fingerprintCache) {
246
- let raw: string;
247
- try {
248
- raw = await (this.opts.machineId ?? (() => readMachineId({ allowFallback: this.opts.allowFallbackFingerprint })))();
249
- } catch (e) {
250
- if (e instanceof MachineIdUnavailableError) throw new LicenseError(e.code, e.message);
251
- throw e;
252
- }
253
- this.fingerprintCache = hashFingerprint(raw, this.opts.product);
254
- }
255
- return this.fingerprintCache;
256
- }
257
-
258
- /** Read once per instance: hardware does not change while the app runs. Never throws. */
259
- private hardware(): Promise<{ components?: HardwareReport['components']; vm?: boolean }> {
260
- this.hardwareCache ??= (async () => {
261
- const source = this.opts.hardware;
262
- if (source === false) return null;
263
- try {
264
- if (source) return await source();
265
- const hwid = loadHwid();
266
- if (!hwid) return null;
267
- const { components, vm } = hwid.collect(`licensekit:${this.opts.product}`);
268
- return { components, vm };
269
- } catch {
270
- return null; // not installed, or no module for this platform: send nothing, as before
271
- }
272
- })();
273
- return this.hardwareCache.then((report) =>
274
- report && report.components.length ? { components: report.components.slice(0, MAX_COMPONENTS), vm: report.vm === true } : {},
275
- );
276
- }
277
-
278
- /** The saved record; null when there is none, or it cannot be read or is not a record (as no license). */
279
- private async load(): Promise<Stored | null> {
280
- try {
281
- const buf = await readFile(this.file);
282
- const text = this.opts.secureStore ? await this.opts.secureStore.decrypt(buf) : buf.toString('utf8');
283
- return parseStored(JSON.parse(text));
284
- } catch {
285
- return null;
286
- }
287
- }
288
-
289
- /** Replaces license.dat whole: written to license.dat.tmp, then renamed over it, so a crash or full disk mid-write
290
- * leaves the previous record. */
291
- private async save(stored: Stored) {
292
- await mkdir(this.opts.storageDir, { recursive: true });
293
- const text = JSON.stringify(stored);
294
- const temp = this.file + '.tmp';
295
- try {
296
- await writeFile(temp, this.opts.secureStore ? await this.opts.secureStore.encrypt(text) : text, { mode: 0o600, flush: true });
297
- await rename(temp, this.file);
298
- } catch (e) {
299
- await rm(temp, { force: true }).catch(() => {});
300
- throw e;
301
- }
302
- }
303
-
304
- private async clear() {
305
- await rm(this.file, { force: true });
306
- }
307
-
308
- private async post(path: string, body: Record<string, unknown>): Promise<any> {
309
- let res: Response;
310
- try {
311
- res = await this.fetch(this.opts.serverUrl.replace(/\/+$/, '') + path, {
312
- method: 'POST',
313
- headers: { 'Content-Type': 'application/json' },
314
- body: JSON.stringify(body),
315
- // A redirect is refused, not followed: it could take the request, license key included, to another
316
- // address or to http:// (ASVS 4.1.2). The server answers its API at the configured address.
317
- redirect: 'error',
318
- signal: AbortSignal.timeout(this.opts.requestTimeoutMs ?? 8000),
319
- });
320
- } catch {
321
- throw new LicenseError('network', 'Could not reach the license server.');
322
- }
323
- const json: any = await res.json().catch(() => ({}));
324
- if (!res.ok) throw new LicenseError(json.error ?? 'server_error', json.message ?? `License server error (${res.status})`, res.status);
325
- return json;
326
- }
327
-
328
- private emptyState(status: LicenseStatus, offline: boolean, extra: Partial<LicenseState> = {}): LicenseState {
329
- return { status, offline, storageProtected: this.storageProtected, features: [], expiresAt: null, ...extra };
330
- }
331
-
332
- /**
333
- * The device's public key, sent with activation and check-ins so the server wraps feature keys for
334
- * this machine only. Only when the native module verifies for this app (it then also decrypts, with
335
- * the matching secret it derives itself) and hardware is not turned off. Never throws.
336
- */
337
- private deviceKey(): { devicePublicKey?: string } {
338
- if (this.deviceKeyCache === undefined) {
339
- let key: string | null = null;
340
- try {
341
- const native = this.opts.hardware === false ? null : this.native();
342
- if (native && typeof native.devicePublicKey === 'function' && typeof native.decryptFeature === 'function') {
343
- key = native.devicePublicKey(`licensekit:${this.opts.product}`);
344
- }
345
- } catch {
346
- key = null;
347
- }
348
- this.deviceKeyCache = key;
349
- }
350
- return this.deviceKeyCache ? { devicePublicKey: this.deviceKeyCache } : {};
351
- }
352
-
353
- /**
354
- * The native verifier, used only when its compiled-in keys include every key this app was given:
355
- * an app that trusts other keys (a self-hosted server) is checked by the JavaScript verifier alone.
356
- */
357
- private native(): NativeLease | null {
358
- if (this.nativeLease === undefined) {
359
- const hwid = loadHwid();
360
- let native: NativeLease | null = null;
361
- if (hwid && typeof hwid.verifyLease === 'function' && typeof hwid.leaseKeyIds === 'function') {
362
- const trusted = new Set<string>(hwid.leaseKeyIds());
363
- if ([...this.keys.keys()].every((kid) => trusted.has(kid))) native = hwid;
364
- }
365
- this.nativeLease = native;
366
- }
367
- return this.nativeLease;
368
- }
369
-
370
- /**
371
- * Verifies a lease twice, in JavaScript and in the native module, when the native verifier applies.
372
- * Both follow the same rules, so a different answer means one of them was tampered with: the lease
373
- * is then treated as modified.
374
- */
375
- private verify(token: string, options: LeaseVerifyOptions): LeaseVerifyResult {
376
- const result = verifyLease(token, options);
377
- const native = this.native();
378
- if (!native) return result;
379
- const check = native.verifyLease(token, {
380
- product: options.product,
381
- fingerprintHash: options.fingerprintHash,
382
- now: options.now ?? Math.floor(Date.now() / 1000),
383
- ...(options.graceSeconds !== undefined ? { graceSeconds: options.graceSeconds } : {}),
384
- });
385
- const agree = check.ok === result.ok && (result.ok || check.reason === result.reason);
386
- return agree ? result : { ok: false, reason: 'bad_signature' };
387
- }
388
-
389
- private stateFromLease(stored: Leased, offline: boolean): LicenseState {
390
- const fingerprintHash = this.fingerprintCache!;
391
- const now = this.nowSec();
392
- const keyHint = `${stored.licenseKey.slice(0, 7)}…${stored.licenseKey.slice(-4)}`;
393
- if (offline && stored.lastSeen !== undefined && now < stored.lastSeen - CLOCK_TOLERANCE_SECONDS) {
394
- return this.emptyState('clock_suspect', offline, { reason: 'clock_rollback', message: CLOCK_MESSAGE, keyHint });
395
- }
396
- const verifyOptions = { keys: this.keys, product: this.opts.product, fingerprintHash, now };
397
- const strict = this.verify(stored.token, verifyOptions);
398
- const fromClaims = (claims: LeaseClaims) => ({
399
- customer: claims.cus,
400
- features: claims.feat,
401
- expiresAt: claims.exp === undefined ? null : toIso(claims.exp),
402
- maintenanceUntil: claims.mnt === undefined ? null : toIso(claims.mnt),
403
- storageProtected: this.storageProtected,
404
- keyHint,
405
- ...(stored.notices ? { notices: stored.notices } : {}),
406
- ...(stored.offline ? { offlineActivated: true } : {}),
407
- });
408
- if (strict.ok) {
409
- return { status: 'valid', offline, ...fromClaims(strict.claims), revalidateBy: toIso(strict.claims.rev) };
410
- }
411
- if (strict.reason === 'not_yet_valid') {
412
- return this.emptyState('clock_suspect', offline, { reason: 'lease_from_future', message: CLOCK_MESSAGE, keyHint });
413
- }
414
- if (strict.reason === 'revalidation_required' && strict.claims) {
415
- const grace = strict.claims.grc ?? (this.opts.graceDays ?? DEFAULT_GRACE_DAYS) * 86400;
416
- const lenient = this.verify(stored.token, { ...verifyOptions, graceSeconds: grace });
417
- if (lenient.ok) {
418
- return {
419
- status: 'grace',
420
- offline,
421
- reason: 'offline_grace',
422
- message: stored.offline
423
- ? 'This offline license is past its renewal date. Load a new offline license file soon to keep using the app.'
424
- : 'Working offline. Connect to the internet soon to keep using the app.',
425
- ...fromClaims(lenient.claims),
426
- revalidateBy: toIso(Math.min(lenient.claims.rev + grace, lenient.claims.exp ?? Infinity)),
427
- };
428
- }
429
- }
430
- return this.emptyState('invalid', offline, { reason: strict.reason, message: REASON_TEXT[strict.reason], keyHint });
431
- }
432
-
433
- /** machineName: the name to show the vendor for this device. Nothing is sent when the app gives none (host names often hold a person's name). */
434
- async activate(licenseKey: string, machineName?: string): Promise<LicenseState> {
435
- const fingerprint = await this.fingerprint();
436
- const key = licenseKey.trim().toUpperCase();
437
- const response = await this.post('/v1/activate', {
438
- licenseKey: key,
439
- product: this.opts.product,
440
- fingerprint,
441
- machineName: machineName?.slice(0, 80),
442
- platform: platform(),
443
- appVersion: this.opts.appVersion,
444
- sdkVersion: SDK_VERSION,
445
- ...(await this.hardware()),
446
- ...this.deviceKey(),
447
- });
448
- const stored: Leased = { licenseKey: key, token: response.token, lastSeen: this.nowSec(), ...noticesFrom(response) };
449
- const state = this.stateFromLease(stored, false);
450
- if (state.status !== 'valid') throw new LicenseError(state.status === 'clock_suspect' ? 'clock_suspect' : state.reason ?? 'invalid', state.message ?? 'Server returned an unusable license');
451
- await this.save(stored);
452
- return state;
453
- }
454
-
455
- async check(): Promise<LicenseState> {
456
- try {
457
- await this.fingerprint();
458
- } catch (e) {
459
- // Nothing is changed on disk: the next check tries to read the id again.
460
- if (e instanceof LicenseError && e.code === 'machine_id_unavailable') return this.emptyState('invalid', false, { reason: e.code, message: e.message });
461
- throw e;
462
- }
463
- const stored = await this.load();
464
- if (!stored) return this.emptyState('unlicensed', false);
465
- if (stored.offline && stored.token) {
466
- // Activated from an offline license file: the machine is not expected to reach the server.
467
- const state = this.stateFromLease({ ...stored, token: stored.token }, true);
468
- if (state.status === 'valid' || state.status === 'grace') {
469
- await this.save({ ...stored, lastSeen: Math.max(stored.lastSeen ?? 0, this.nowSec()) });
470
- }
471
- return state;
472
- }
473
- let response: any;
474
- try {
475
- response = await this.post('/v1/validate', {
476
- licenseKey: stored.licenseKey,
477
- product: this.opts.product,
478
- fingerprint: this.fingerprintCache,
479
- appVersion: this.opts.appVersion,
480
- sdkVersion: SDK_VERSION,
481
- ...(await this.hardware()),
482
- ...this.deviceKey(),
483
- });
484
- } catch (e) {
485
- if (e instanceof LicenseError && DEFINITIVE.has(e.code)) {
486
- // Persist the refusal: drop the signed lease so going offline cannot bring the license back.
487
- if (FORGET_KEY.has(e.code)) await this.clear();
488
- else await this.save({ licenseKey: stored.licenseKey, lastSeen: stored.lastSeen, refused: { code: e.code, message: e.message, at: this.nowSec() } });
489
- const keyHint = `${stored.licenseKey.slice(0, 7)}…${stored.licenseKey.slice(-4)}`;
490
- return this.emptyState('invalid', false, { reason: e.code, message: e.message, keyHint });
491
- }
492
- return this.offlineCheck(stored);
493
- }
494
- if (typeof response?.token === 'string') {
495
- const fresh: Leased = { licenseKey: stored.licenseKey, token: response.token, lastSeen: this.nowSec(), ...noticesFrom(response) };
496
- const state = this.stateFromLease(fresh, false);
497
- if (!(state.status === 'invalid' && NOT_A_LEASE_FOR_THIS_DEVICE.has(state.reason ?? ''))) {
498
- await this.save(fresh);
499
- return state;
500
- }
501
- }
502
- // A 2xx without a lease from this server for this device: as no answer.
503
- return this.offlineCheck(stored);
504
- }
505
-
506
- /** The state from the saved record when the server gave no usable answer; a usable lease moves lastSeen forward. */
507
- private async offlineCheck(stored: Stored): Promise<LicenseState> {
508
- if (!stored.token) {
509
- const keyHint = `${stored.licenseKey.slice(0, 7)}…${stored.licenseKey.slice(-4)}`;
510
- const refused = stored.refused ?? { code: 'not_activated', message: 'This device is not activated for this license' };
511
- return this.emptyState('invalid', true, { reason: refused.code, message: refused.message, keyHint });
512
- }
513
- const state = this.stateFromLease({ ...stored, token: stored.token }, true);
514
- if (state.status === 'valid' || state.status === 'grace') {
515
- await this.save({ ...stored, lastSeen: Math.max(stored.lastSeen ?? 0, this.nowSec()) });
516
- }
517
- return state;
518
- }
519
-
520
- /**
521
- * Decrypts data you encrypted for a feature (encryptForFeature in @carchalabs/seal-core, with the
522
- * feature's content key from the console). Works offline: it uses the saved lease, which must be valid
523
- * (or in its offline grace period), grant the feature and carry its key, and the saved license key.
524
- * The native module does the work when it trusts this app's keys, so the content key never reaches
525
- * JavaScript; without it the JavaScript implementation is used. Throws a LicenseError:
526
- * `unlicensed`, a lease failure reason, `clock_suspect`, `feature_not_licensed` or `decrypt_failed`.
527
- */
528
- async decrypt(feature: string, data: Uint8Array): Promise<Buffer> {
529
- return (await this.opener(feature))(data);
530
- }
531
-
532
- /**
533
- * Envelope: loads a CommonJS module you encrypted for a feature (seal-encrypt, one file or a
534
- * folder) and returns its exports, like require(). The code is decrypted with the lease's feature key
535
- * (see decrypt) and compiled from memory; it never exists as a plain file. Relative requires inside
536
- * it load encrypted neighbours (`./x` finds `x.lke`, `x.js.lke` or `x/index.js.lke`), anything else
537
- * goes to Node as usual. Loaded once per process, like require(). Throws the same LicenseErrors as
538
- * decrypt. A licensed user can still read the code from memory: this keeps an app with the license
539
- * check removed from having the feature, it does not hide the code from its licensed users.
540
- */
541
- async requireEncrypted(feature: string, file: string): Promise<any> {
542
- const open = await this.opener(feature);
543
- return this.loadEncrypted(resolve(file), feature, open);
544
- }
545
-
546
- private readonly encryptedModules = new Map<string, { exports: any; filename: string; id: string; loaded: boolean }>();
547
-
548
- private loadEncrypted(file: string, feature: string, open: (data: Uint8Array) => Buffer): any {
549
- const cacheKey = `${feature}\0${file}`;
550
- const cached = this.encryptedModules.get(cacheKey);
551
- if (cached) return cached.exports;
552
- const source = open(readFileSync(file)).toString('utf8');
553
- const filename = file.replace(/\.lke$/, '');
554
- const mod = { exports: {} as any, filename, id: filename, loaded: false };
555
- // Registered before it runs, so a require cycle gets the partial exports, as in Node.
556
- this.encryptedModules.set(cacheKey, mod);
557
- const nodeRequire = createRequire(filename);
558
- const localRequire = ((request: string) => {
559
- if (request.startsWith('./') || request.startsWith('../')) {
560
- const base = resolve(dirname(filename), request);
561
- const encrypted = [`${base}.lke`, `${base}.js.lke`, join(base, 'index.js.lke')].find((candidate) => existsSync(candidate));
562
- if (encrypted) return this.loadEncrypted(encrypted, feature, open);
563
- }
564
- return nodeRequire(request);
565
- }) as NodeJS.Require;
566
- Object.assign(localRequire, { resolve: nodeRequire.resolve, cache: nodeRequire.cache, main: nodeRequire.main, extensions: nodeRequire.extensions });
567
- try {
568
- const run = compileFunction(source, ['exports', 'require', 'module', '__filename', '__dirname'], { filename });
569
- run.call(mod.exports, mod.exports, localRequire, mod, filename, dirname(filename));
570
- } catch (e) {
571
- this.encryptedModules.delete(cacheKey);
572
- throw e;
573
- }
574
- mod.loaded = true;
575
- return mod.exports;
576
- }
577
-
578
- /**
579
- * Checks the saved lease once for a feature and returns a synchronous decrypter bound to it: decrypt
580
- * uses it once, requireEncrypted for a module and the encrypted modules it requires.
581
- */
582
- private async opener(feature: string): Promise<(data: Uint8Array) => Buffer> {
583
- const fingerprintHash = await this.fingerprint();
584
- const stored = await this.load();
585
- if (!stored?.token) throw new LicenseError('unlicensed', 'This device has no license.');
586
- const leased: Leased = { ...stored, token: stored.token };
587
- const state = this.stateFromLease(leased, true);
588
- if (state.status !== 'valid' && state.status !== 'grace') {
589
- throw new LicenseError(state.status === 'clock_suspect' ? 'clock_suspect' : (state.reason ?? 'invalid'), state.message ?? 'The license is not valid.');
590
- }
591
- const claims = decodeLease(leased.token)?.claims;
592
- const graceSeconds = state.status === 'grace' ? (claims?.grc ?? (this.opts.graceDays ?? DEFAULT_GRACE_DAYS) * 86400) : 0;
593
- const check = { product: this.opts.product, fingerprintHash, now: this.nowSec(), ...(graceSeconds ? { graceSeconds } : {}) };
594
- const native = this.native();
595
- return (data: Uint8Array) => {
596
- const result: { ok: boolean; data?: Buffer; reason?: string } =
597
- native && typeof native.decryptFeature === 'function'
598
- ? native.decryptFeature(leased.token, check, leased.licenseKey, feature, Buffer.from(data))
599
- : decryptFeature(leased.token, { keys: this.keys, ...check }, leased.licenseKey, feature, Buffer.from(data));
600
- if (result.ok && result.data) return Buffer.from(result.data);
601
- if (result.reason === 'not_licensed') throw new LicenseError('feature_not_licensed', `This license does not include "${feature}".`);
602
- if (result.reason === 'decrypt_failed') throw new LicenseError('decrypt_failed', 'The data could not be decrypted with this license.');
603
- throw new LicenseError(result.reason ?? 'invalid', REASON_TEXT[result.reason as LeaseFailure] ?? 'The license is not valid.');
604
- };
605
- }
606
-
607
- /**
608
- * Offline activation, step 1 on a machine that cannot reach the server: the request file (JSON text)
609
- * the user takes to a connected device. The license server turns it into a license file at
610
- * POST /v1/offline/activate (or its offline activation page). It holds what activate() would send:
611
- * the license key, this device's fingerprint and hashed hardware parts, never raw serial numbers.
612
- */
613
- async offlineRequest(licenseKey: string, machineName?: string): Promise<string> {
614
- const fingerprint = await this.fingerprint();
615
- const activation = {
616
- licenseKey: licenseKey.trim().toUpperCase(),
617
- product: this.opts.product,
618
- fingerprint,
619
- machineName: machineName?.slice(0, 80),
620
- platform: platform(),
621
- appVersion: this.opts.appVersion,
622
- sdkVersion: SDK_VERSION,
623
- ...(await this.hardware()),
624
- ...this.deviceKey(),
625
- };
626
- return JSON.stringify({ format: OFFLINE_REQUEST_FORMAT, version: 1, activation }, null, 2);
627
- }
628
-
629
- /**
630
- * Offline activation, step 2: loads the license file the server issued for this machine's request.
631
- * It is verified like an online lease (signature, product, this device) and then saved; from then on
632
- * check() works without the server until the lease's renewal date plus the offline grace. Throws a
633
- * LicenseError: `invalid_file`, `wrong_product`, or a lease failure reason such as `wrong_device`.
634
- */
635
- async activateOffline(licenseFile: string): Promise<LicenseState> {
636
- await this.fingerprint();
637
- let file: any;
638
- try {
639
- file = JSON.parse(licenseFile);
640
- } catch {
641
- throw new LicenseError('invalid_file', 'This is not a Carcha Seal offline license file.');
642
- }
643
- if (!file || file.format !== OFFLINE_LICENSE_FORMAT || file.version !== 1 || typeof file.token !== 'string' || typeof file.licenseKey !== 'string') {
644
- throw new LicenseError('invalid_file', 'This is not a Carcha Seal offline license file.');
645
- }
646
- if (file.product !== this.opts.product) throw new LicenseError('wrong_product', 'This offline license file is for another product.');
647
- const stored: Leased = { licenseKey: file.licenseKey.trim().toUpperCase(), token: file.token, lastSeen: this.nowSec(), offline: true };
648
- const state = this.stateFromLease(stored, true);
649
- if (state.status !== 'valid') {
650
- throw new LicenseError(state.status === 'clock_suspect' ? 'clock_suspect' : state.reason ?? 'invalid', state.message ?? 'This offline license file cannot be used on this computer.');
651
- }
652
- await this.save(stored);
653
- return state;
654
- }
655
-
656
- /**
657
- * Gives an offline machine's seat back: removes the license from this device and returns the
658
- * deactivation file (JSON text) for the vendor, who frees the seat by uploading it in the console.
659
- * Throws `unlicensed` when there is no license to remove.
660
- */
661
- async deactivateOffline(): Promise<string> {
662
- const stored = await this.load();
663
- if (!stored?.token) throw new LicenseError('unlicensed', 'This device has no license.');
664
- await this.clear();
665
- return JSON.stringify({ format: OFFLINE_DEACTIVATION_FORMAT, version: 1, product: this.opts.product, token: stored.token }, null, 2);
666
- }
667
-
668
- async deactivate(): Promise<void> {
669
- const stored = await this.load();
670
- if (!stored) return;
671
- try {
672
- await this.post('/v1/deactivate', {
673
- licenseKey: stored.licenseKey,
674
- product: this.opts.product,
675
- fingerprint: await this.fingerprint(),
676
- ...(await this.hardware()),
677
- });
678
- } catch (e) {
679
- if (!(e instanceof LicenseError && (e.code === 'not_activated' || e.code === 'invalid_key'))) throw e;
680
- }
681
- await this.clear();
682
- }
683
-
684
- static hasFeature(state: LicenseState, feature: string): boolean {
685
- return (state.status === 'valid' || state.status === 'grace') && state.features.includes(feature);
686
- }
687
- }
688
-
689
- /** The SDK class under its earlier name (LicenseKit). Same class; use Seal in new code. */
690
- export { Seal as LicenseKit };
691
- /** @deprecated The options under the class's earlier name; use SealOptions. */
692
- export type LicenseKitOptions = SealOptions;