@moonbase.sh/licensing 2.0.1 → 3.0.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/dist/index.js CHANGED
@@ -1,6 +1,13 @@
1
+ // src/index.ts
2
+ import { Buffer as Buffer2 } from "buffer";
3
+ import process3 from "process";
4
+
1
5
  // src/client.ts
2
6
  import fetch from "cross-fetch";
3
7
 
8
+ // src/schemas.ts
9
+ import { z } from "zod";
10
+
4
11
  // src/types.ts
5
12
  var ActivationMethod = /* @__PURE__ */ ((ActivationMethod2) => {
6
13
  ActivationMethod2["Online"] = "Online";
@@ -9,7 +16,6 @@ var ActivationMethod = /* @__PURE__ */ ((ActivationMethod2) => {
9
16
  })(ActivationMethod || {});
10
17
 
11
18
  // src/schemas.ts
12
- import { z } from "zod";
13
19
  var activationRequestResponseSchema = z.object({
14
20
  id: z.string(),
15
21
  request: z.string(),
@@ -63,7 +69,7 @@ var LicenseClient = class {
63
69
  deviceName: await this.deviceIdResolver.resolveDeviceName(),
64
70
  deviceSignature: await this.deviceIdResolver.resolveDeviceId()
65
71
  };
66
- const response = await fetch(this.configuration.endpoint + `/api/client/activations/${this.configuration.productId}/request${this.buildQueryString()}`, {
72
+ const response = await fetch(`${this.configuration.endpoint}/api/client/activations/${this.configuration.productId}/request${this.buildQueryString()}`, {
67
73
  ...defaultFetchOptions,
68
74
  method: "POST",
69
75
  body: JSON.stringify(content)
@@ -85,7 +91,8 @@ var LicenseClient = class {
85
91
  }
86
92
  async getRequestedActivation(request) {
87
93
  const response = await fetch(request.request, defaultFetchOptions);
88
- if (response.status === 204 || response.status === 404) return null;
94
+ if (response.status === 204 || response.status === 404)
95
+ return null;
89
96
  return await this.handleLicenseResponse(response);
90
97
  }
91
98
  async requestTrial() {
@@ -93,7 +100,7 @@ var LicenseClient = class {
93
100
  deviceName: await this.deviceIdResolver.resolveDeviceName(),
94
101
  deviceSignature: await this.deviceIdResolver.resolveDeviceId()
95
102
  };
96
- const response = await fetch(this.configuration.endpoint + `/api/client/trials/${this.configuration.productId}/request${this.buildQueryString()}`, {
103
+ const response = await fetch(`${this.configuration.endpoint}/api/client/trials/${this.configuration.productId}/request${this.buildQueryString()}`, {
97
104
  ...defaultFetchOptions,
98
105
  method: "POST",
99
106
  headers: {
@@ -105,7 +112,7 @@ var LicenseClient = class {
105
112
  return await this.handleLicenseResponse(response);
106
113
  }
107
114
  async validateLicense(license) {
108
- const response = await fetch(this.configuration.endpoint + `/api/client/licenses/${this.configuration.productId}/validate${this.buildQueryString()}`, {
115
+ const response = await fetch(`${this.configuration.endpoint}/api/client/licenses/${this.configuration.productId}/validate${this.buildQueryString()}`, {
109
116
  ...defaultFetchOptions,
110
117
  method: "POST",
111
118
  headers: {
@@ -118,11 +125,12 @@ var LicenseClient = class {
118
125
  }
119
126
  async validateRawLicense(rawLicense) {
120
127
  const license = await this.licenseValidator.validateLicense(rawLicense.toString("utf8"));
121
- if (license.activationMethod === "Offline" /* Offline */) return license;
128
+ if (license.activationMethod === "Offline" /* Offline */)
129
+ return license;
122
130
  return await this.validateLicense(license);
123
131
  }
124
132
  async revokeLicense(license) {
125
- const response = await fetch(this.configuration.endpoint + `/api/client/licenses/${this.configuration.productId}/revoke?format=JWT`, {
133
+ const response = await fetch(`${this.configuration.endpoint}/api/client/licenses/${this.configuration.productId}/revoke?format=JWT`, {
126
134
  ...defaultFetchOptions,
127
135
  method: "POST",
128
136
  headers: {
@@ -144,11 +152,14 @@ var LicenseClient = class {
144
152
  buildQueryString() {
145
153
  const parts = ["format=JWT"];
146
154
  const { platform, appVersion, metadata } = this.configuration;
147
- if (platform) parts.push(`platform=${encodeURIComponent(platform)}`);
148
- if (appVersion) parts.push(`appVersion=${encodeURIComponent(appVersion)}`);
155
+ if (platform)
156
+ parts.push(`platform=${encodeURIComponent(platform)}`);
157
+ if (appVersion)
158
+ parts.push(`appVersion=${encodeURIComponent(appVersion)}`);
149
159
  if (metadata) {
150
160
  for (const [key, value] of Object.entries(metadata)) {
151
- if (value === null || value === void 0 || value === "") continue;
161
+ if (value === null || value === void 0 || value === "")
162
+ continue;
152
163
  parts.push(`meta[${encodeURIComponent(key)}]=${encodeURIComponent(value)}`);
153
164
  }
154
165
  }
@@ -157,32 +168,426 @@ var LicenseClient = class {
157
168
  };
158
169
 
159
170
  // src/deviceIdResolver.ts
171
+ import cp2 from "child_process";
172
+ import { createHash as createHash2 } from "crypto";
173
+ import os2 from "os";
174
+ import process2 from "process";
160
175
  import si from "systeminformation";
161
- import os from "os";
176
+
177
+ // src/errors.ts
178
+ var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
179
+ ErrorType2["None"] = "None";
180
+ ErrorType2["ApiError"] = "ApiError";
181
+ ErrorType2["NoEligibleLicense"] = "NoEligibleLicense";
182
+ ErrorType2["LicenseInvalid"] = "LicenseInvalid";
183
+ ErrorType2["LicenseRevoked"] = "LicenseRevoked";
184
+ ErrorType2["LicenseActivationRevoked"] = "LicenseActivationRevoked";
185
+ ErrorType2["LicenseExpired"] = "LicenseExpired";
186
+ ErrorType2["LicenseDeviceMismatch"] = "LicenseDeviceMismatch";
187
+ ErrorType2["DeviceIdentityUnavailable"] = "DeviceIdentityUnavailable";
188
+ return ErrorType2;
189
+ })(ErrorType || {});
190
+ var MoonbaseError = class extends Error {
191
+ constructor(title, detail, type, inner) {
192
+ super();
193
+ this.title = title;
194
+ this.detail = detail;
195
+ this.type = type;
196
+ this.inner = inner;
197
+ this.name = "MoonbaseError";
198
+ this.message = detail != null ? detail : title;
199
+ }
200
+ };
201
+ var InsufficientDeviceIdentityError = class extends MoonbaseError {
202
+ constructor(platform, reason = "no identity parameter could be read") {
203
+ super(
204
+ "No device identity",
205
+ `Could not identify this device (platform: ${platform}): ${reason}`,
206
+ "DeviceIdentityUnavailable" /* DeviceIdentityUnavailable */
207
+ );
208
+ this.platform = platform;
209
+ this.name = "InsufficientDeviceIdentityError";
210
+ }
211
+ };
212
+
213
+ // src/fingerprint.ts
214
+ import { Buffer } from "buffer";
162
215
  import cp from "child_process";
163
216
  import { createHash } from "crypto";
164
- var DefaultDeviceIdResolver = class {
217
+ import fs from "fs";
218
+ import os from "os";
219
+ import process from "process";
220
+ var FINGERPRINT_PREFIX = "moonbase:fingerprint:v2";
221
+ var FINGERPRINT_VERSION = 2;
222
+ var MAX_VALUE_LENGTH = 128;
223
+ var PRINTABLE_ASCII_MIN = 32;
224
+ var PRINTABLE_ASCII_MAX = 126;
225
+ var STAMP_PATTERN = /^mbd(\d+)(n?)_([0-9a-f]{64})$/;
226
+ function canonicalizeValue(value) {
227
+ var _a;
228
+ let printable = "";
229
+ for (const char of value.normalize("NFC")) {
230
+ const code = (_a = char.codePointAt(0)) != null ? _a : 0;
231
+ if (code >= PRINTABLE_ASCII_MIN && code <= PRINTABLE_ASCII_MAX)
232
+ printable += char;
233
+ }
234
+ return printable.slice(0, MAX_VALUE_LENGTH).replace(/^ +| +$/g, "");
235
+ }
236
+ function platformTag(platform = process.platform) {
237
+ switch (platform) {
238
+ case "darwin":
239
+ return "mac";
240
+ case "win32":
241
+ return "windows";
242
+ case "android":
243
+ return "android";
244
+ case "linux":
245
+ return "linux";
246
+ case "freebsd":
247
+ case "openbsd":
248
+ case "netbsd":
249
+ return "bsd";
250
+ default:
251
+ return "unknown";
252
+ }
253
+ }
254
+ var IDENTIFYING_PARAMS = /* @__PURE__ */ new Set([
255
+ "ioPlatformUuid",
256
+ "machineId",
257
+ "systemUuid",
258
+ "baseboardSerialNumber",
259
+ "deviceName"
260
+ ]);
261
+ var IDENTIFYING_PARAM_NAMES = Object.freeze([...IDENTIFYING_PARAMS]);
262
+ var NOT_PROGRAMMED_VALUES = /* @__PURE__ */ new Set([
263
+ "to be filled by o.e.m.",
264
+ // The same filler without the dots, which plenty of firmware writes instead.
265
+ "to be filled by oem",
266
+ "default string",
267
+ "system serial number",
268
+ "base board serial number",
269
+ "chassis serial number",
270
+ "not specified",
271
+ "not applicable",
272
+ "not available",
273
+ "none",
274
+ "unknown",
275
+ "invalid",
276
+ "n/a",
277
+ "0123456789",
278
+ // `machine-id(5)`: the literal marker systemd writes to say "no id yet",
279
+ // e.g. in an initrd or a golden image awaiting first boot. Every machine
280
+ // deployed from such an image reads it, so it is the opposite of an identifier.
281
+ "uninitialized"
282
+ ]);
283
+ function isNotProgrammed(value) {
284
+ return NOT_PROGRAMMED_VALUES.has(value.toLowerCase()) || /^0+$/.test(value) || /^f+$/i.test(value);
285
+ }
286
+ function canonicalizeParams(params) {
287
+ const kept = [];
288
+ const seen = /* @__PURE__ */ new Set();
289
+ for (const [name, rawValue] of params) {
290
+ const value = canonicalizeValue(rawValue);
291
+ if (value.length === 0)
292
+ continue;
293
+ if (IDENTIFYING_PARAMS.has(name) && isNotProgrammed(value))
294
+ continue;
295
+ if (seen.has(name))
296
+ throw new Error(`Duplicate fingerprint parameter name: ${name}`);
297
+ seen.add(name);
298
+ kept.push([name, value]);
299
+ }
300
+ return kept;
301
+ }
302
+ function buildFingerprintMaterial(platform, params) {
303
+ const kept = canonicalizeParams(params);
304
+ if (kept.length === 0)
305
+ throw new InsufficientDeviceIdentityError(platform, "no identity parameter could be read");
306
+ if (!kept.some(([name]) => IDENTIFYING_PARAMS.has(name))) {
307
+ throw new InsufficientDeviceIdentityError(
308
+ platform,
309
+ `only model-level parameters could be read (${kept.map(([name]) => name).join(", ")}), none of which identify this individual machine`
310
+ );
311
+ }
312
+ const lines = [FINGERPRINT_PREFIX, `platform=${platform}`];
313
+ for (const [name, value] of kept)
314
+ lines.push(`${name}=${value}`);
315
+ return lines.join("\n");
316
+ }
317
+ function fingerprintDigest(material) {
318
+ return createHash("sha256").update(material, "utf8").digest("hex");
319
+ }
320
+ function stampDeviceId(digest, source = "identity") {
321
+ return `mbd${FINGERPRINT_VERSION}${source === "deviceName" ? "n" : ""}_${digest}`;
322
+ }
323
+ function fingerprintDeviceId(material, source = "identity") {
324
+ return stampDeviceId(fingerprintDigest(material), source);
325
+ }
326
+ function parseDeviceIdStamp(deviceId) {
327
+ const match = STAMP_PATTERN.exec(deviceId);
328
+ if (!match)
329
+ return null;
330
+ return {
331
+ version: Number(match[1]),
332
+ source: match[2] === "n" ? "deviceName" : "identity",
333
+ digest: match[3]
334
+ };
335
+ }
336
+ function commandOutput(command) {
337
+ try {
338
+ return cp.execSync(command, { encoding: "utf8" });
339
+ } catch (e) {
340
+ return "";
341
+ }
342
+ }
343
+ function readSysFile(path2) {
344
+ try {
345
+ return fs.readFileSync(path2, "utf8");
346
+ } catch (e) {
347
+ return "";
348
+ }
349
+ }
350
+ function parseIoregPlatformUuid(ioregOutput) {
351
+ const match = ioregOutput.match(/"IOPlatformUUID"\s*=\s*"([^"]+)"/);
352
+ return match ? match[1].replaceAll("-", "").toUpperCase() : "";
353
+ }
354
+ function readMacIdentity() {
355
+ const uuid = parseIoregPlatformUuid(commandOutput("ioreg -rd1 -c IOPlatformExpertDevice"));
356
+ const params = [["ioPlatformUuid", uuid]];
357
+ return { params, deviceName: os.hostname().replace(/\.local$/i, "") };
358
+ }
359
+ function selectMachineId(...sources) {
360
+ var _a;
361
+ return (_a = sources.map(canonicalizeValue).find((value) => /^[0-9a-f]{32}$/.test(value) && !isNotProgrammed(value))) != null ? _a : "";
362
+ }
363
+ function readMachineId() {
364
+ return selectMachineId(
365
+ readSysFile("/etc/machine-id"),
366
+ readSysFile("/var/lib/dbus/machine-id")
367
+ );
368
+ }
369
+ function readLinuxIdentity() {
370
+ const params = [
371
+ ["machineId", readMachineId()],
372
+ ["sysVendor", readSysFile("/sys/class/dmi/id/sys_vendor")],
373
+ ["productName", readSysFile("/sys/class/dmi/id/product_name")],
374
+ ["boardVendor", readSysFile("/sys/class/dmi/id/board_vendor")],
375
+ ["boardName", readSysFile("/sys/class/dmi/id/board_name")]
376
+ ];
377
+ return { params, deviceName: os.hostname() };
378
+ }
379
+ function parseSmbiosStructures(data) {
380
+ const structures = [];
381
+ let offset = 0;
382
+ while (offset + 4 <= data.length) {
383
+ const type = data[offset];
384
+ const length = data[offset + 1];
385
+ if (length < 4 || offset + length > data.length)
386
+ break;
387
+ const formatted = data.subarray(offset, offset + length);
388
+ const strings = [];
389
+ let p = offset + length;
390
+ if (p + 1 < data.length && data[p] === 0 && data[p + 1] === 0) {
391
+ p += 2;
392
+ } else {
393
+ while (p < data.length) {
394
+ let end = p;
395
+ while (end < data.length && data[end] !== 0)
396
+ end++;
397
+ strings.push(data.toString("latin1", p, end));
398
+ p = end + 1;
399
+ if (p < data.length && data[p] === 0) {
400
+ p += 1;
401
+ break;
402
+ }
403
+ }
404
+ }
405
+ structures.push({ type, formatted, strings });
406
+ if (type === 127)
407
+ break;
408
+ offset = p;
409
+ }
410
+ return structures;
411
+ }
412
+ function resolveSmbiosString(structure, fieldOffset) {
413
+ if (fieldOffset >= structure.formatted.length)
414
+ return "";
415
+ const index = structure.formatted[fieldOffset];
416
+ if (index === 0 || index > structure.strings.length)
417
+ return "";
418
+ return structure.strings[index - 1];
419
+ }
420
+ function formatSmbiosUuid(structure, fieldOffset) {
421
+ if (fieldOffset + 16 > structure.formatted.length)
422
+ return "";
423
+ const bytes = structure.formatted.subarray(fieldOffset, fieldOffset + 16);
424
+ if (bytes.every((byte) => byte === 0) || bytes.every((byte) => byte === 255))
425
+ return "";
426
+ let hex = "";
427
+ for (const byte of bytes)
428
+ hex += byte.toString(16).padStart(2, "0").toUpperCase();
429
+ return hex;
430
+ }
431
+ function parseSmbiosParams(smbiosData) {
432
+ const structures = parseSmbiosStructures(smbiosData);
433
+ const params = [];
434
+ const system = structures.find((structure) => structure.type === 1);
435
+ if (system) {
436
+ params.push(["systemManufacturer", resolveSmbiosString(system, 4)]);
437
+ params.push(["systemProductName", resolveSmbiosString(system, 5)]);
438
+ params.push(["systemUuid", formatSmbiosUuid(system, 8)]);
439
+ }
440
+ const baseboard = structures.find((structure) => structure.type === 2);
441
+ if (baseboard) {
442
+ params.push(["baseboardManufacturer", resolveSmbiosString(baseboard, 4)]);
443
+ params.push(["baseboardProduct", resolveSmbiosString(baseboard, 5)]);
444
+ params.push(["baseboardSerialNumber", resolveSmbiosString(baseboard, 7)]);
445
+ }
446
+ return params;
447
+ }
448
+ function readWindowsSmbios() {
449
+ const script = "[Convert]::ToBase64String((Get-CimInstance -Namespace root/wmi -ClassName MSSmBios_RawSMBiosTables).SMBiosData)";
450
+ const output = commandOutput(`powershell -NoProfile -NonInteractive -Command "${script}"`);
451
+ try {
452
+ return Buffer.from(output.trim(), "base64");
453
+ } catch (e) {
454
+ return Buffer.alloc(0);
455
+ }
456
+ }
457
+ function readWindowsIdentity() {
458
+ return { params: parseSmbiosParams(readWindowsSmbios()), deviceName: os.hostname() };
459
+ }
460
+ function defaultDeviceIdentityReader(platform = process.platform) {
461
+ return {
462
+ read() {
463
+ switch (platform) {
464
+ case "darwin":
465
+ return readMacIdentity();
466
+ case "linux":
467
+ return readLinuxIdentity();
468
+ case "win32":
469
+ return readWindowsIdentity();
470
+ // android, bsd and anything else define no identity params: the spec
471
+ // has no stable hardware source for them, so they resolve to an
472
+ // insufficient-identity error unless the deviceName fallback is enabled.
473
+ default:
474
+ return { params: [], deviceName: os.hostname() };
475
+ }
476
+ }
477
+ };
478
+ }
479
+
480
+ // src/deviceIdResolver.ts
481
+ var MoonbaseDeviceIdResolver = class {
482
+ constructor(options) {
483
+ var _a, _b, _c;
484
+ const platform = (_a = options == null ? void 0 : options.platform) != null ? _a : process2.platform;
485
+ this.platform = platformTag(platform);
486
+ this.reader = (_b = options == null ? void 0 : options.reader) != null ? _b : defaultDeviceIdentityReader(platform);
487
+ this.fallback = (_c = options == null ? void 0 : options.fallback) != null ? _c : "none";
488
+ }
489
+ async resolveDeviceName() {
490
+ return this.readIdentity().deviceName;
491
+ }
492
+ async resolveDeviceId() {
493
+ return this.compute().deviceId;
494
+ }
495
+ /**
496
+ * A fresh copy each call. The device binding is what activation sends and what
497
+ * validation compares, so handing out the resolver's own object would let a
498
+ * consumer that edits a diagnostic — or logs it through something that
499
+ * normalizes in place — silently change the id every later call returns.
500
+ */
501
+ async describeDevice() {
502
+ const described = this.compute();
503
+ return { ...described, paramNames: [...described.paramNames] };
504
+ }
505
+ compute() {
506
+ var _a;
507
+ (_a = this.described) != null ? _a : this.described = this.computeDescription();
508
+ return this.described;
509
+ }
510
+ /**
511
+ * Read identity at most once. Both halves of an activation request ask for it —
512
+ * the name and then the id — and a read can mean spawning `ioreg` or
513
+ * PowerShell, so reading per call would double the cost of every request and
514
+ * let the name and the id come from two different reads of the machine.
515
+ */
516
+ readIdentity() {
517
+ var _a;
518
+ (_a = this.identity) != null ? _a : this.identity = this.reader.read();
519
+ return this.identity;
520
+ }
521
+ computeDescription() {
522
+ const { params, deviceName } = this.readIdentity();
523
+ try {
524
+ return this.describe(params, "identity");
525
+ } catch (err) {
526
+ if (this.fallback !== "deviceName" || !(err instanceof InsufficientDeviceIdentityError))
527
+ throw err;
528
+ return this.describe([["deviceName", deviceName]], "deviceName");
529
+ }
530
+ }
531
+ describe(params, source) {
532
+ return {
533
+ deviceId: fingerprintDeviceId(buildFingerprintMaterial(this.platform, params), source),
534
+ version: FINGERPRINT_VERSION,
535
+ platform: this.platform,
536
+ source,
537
+ paramNames: canonicalizeParams(params).map(([name]) => name)
538
+ };
539
+ }
540
+ };
541
+ var MigratingDeviceIdResolver = class {
542
+ constructor(current, ...previous) {
543
+ this.current = current;
544
+ this.previous = previous;
545
+ const describe = current.describeDevice;
546
+ if (typeof describe === "function")
547
+ this.describeDevice = () => describe.call(current);
548
+ }
549
+ async resolveDeviceName() {
550
+ return this.current.resolveDeviceName();
551
+ }
552
+ async resolveDeviceId() {
553
+ return this.current.resolveDeviceId();
554
+ }
555
+ async acceptsDeviceId(deviceId) {
556
+ if (!this.previousIds) {
557
+ this.previousIds = Promise.all(this.previous.map(async (resolver) => {
558
+ try {
559
+ return await resolver.resolveDeviceId();
560
+ } catch (e) {
561
+ return "";
562
+ }
563
+ }));
564
+ }
565
+ return (await this.previousIds).some((previous) => previous.length > 0 && previous === deviceId);
566
+ }
567
+ };
568
+ var LegacyDeviceIdResolver = class {
165
569
  async resolveDeviceName() {
166
- switch (process.platform) {
570
+ switch (process2.platform) {
167
571
  case "darwin":
168
572
  try {
169
- return cp.execSync("scutil --get ComputerName").toString().trim();
573
+ return cp2.execSync("scutil --get ComputerName").toString().trim();
170
574
  } catch (e) {
171
- return os.hostname();
575
+ return os2.hostname();
172
576
  }
173
577
  case "win32":
174
- return process.env.COMPUTERNAME || os.hostname();
175
- case "linux":
176
- const prettyname = cp.execSync("hostnamectl --pretty").toString().trim();
177
- return prettyname || os.hostname();
578
+ return process2.env.COMPUTERNAME || os2.hostname();
579
+ case "linux": {
580
+ const prettyname = cp2.execSync("hostnamectl --pretty").toString().trim();
581
+ return prettyname || os2.hostname();
582
+ }
178
583
  default:
179
- return os.hostname();
584
+ return os2.hostname();
180
585
  }
181
586
  }
182
587
  async resolveDeviceId() {
183
588
  const [cpu, hw] = await Promise.all([si.cpu(), si.system()]);
184
589
  const parts = [
185
- os.hostname(),
590
+ os2.hostname(),
186
591
  hw.manufacturer,
187
592
  hw.model,
188
593
  hw.serial,
@@ -194,40 +599,15 @@ var DefaultDeviceIdResolver = class {
194
599
  cpu.family,
195
600
  cpu.model
196
601
  ];
197
- const hash = createHash("sha256").update(parts.join("")).digest();
602
+ const hash = createHash2("sha256").update(parts.join("")).digest();
198
603
  return hash.toString("base64").replaceAll("=", "");
199
604
  }
200
605
  };
201
606
 
202
607
  // src/store.ts
203
608
  import fsSync from "fs";
204
- import fs from "fs/promises";
609
+ import fs2 from "fs/promises";
205
610
  import path from "path";
206
-
207
- // src/errors.ts
208
- var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
209
- ErrorType2["None"] = "None";
210
- ErrorType2["ApiError"] = "ApiError";
211
- ErrorType2["NoEligibleLicense"] = "NoEligibleLicense";
212
- ErrorType2["LicenseInvalid"] = "LicenseInvalid";
213
- ErrorType2["LicenseRevoked"] = "LicenseRevoked";
214
- ErrorType2["LicenseActivationRevoked"] = "LicenseActivationRevoked";
215
- ErrorType2["LicenseExpired"] = "LicenseExpired";
216
- return ErrorType2;
217
- })(ErrorType || {});
218
- var MoonbaseError = class extends Error {
219
- constructor(title, detail, type, inner) {
220
- super();
221
- this.title = title;
222
- this.detail = detail;
223
- this.type = type;
224
- this.inner = inner;
225
- this.name = "MoonbaseError";
226
- this.message = detail != null ? detail : title;
227
- }
228
- };
229
-
230
- // src/store.ts
231
611
  var InMemoryLicenseStore = class {
232
612
  async loadLocalLicense() {
233
613
  var _a;
@@ -245,9 +625,10 @@ var FileLicenseStore = class {
245
625
  this.options = options;
246
626
  }
247
627
  async loadLocalLicense() {
248
- if (!fsSync.existsSync(this.path)) return null;
628
+ if (!fsSync.existsSync(this.path))
629
+ return null;
249
630
  try {
250
- const file = await fs.readFile(this.path, { encoding: "utf-8" });
631
+ const file = await fs2.readFile(this.path, { encoding: "utf-8" });
251
632
  const license = licenseSchema.parse(JSON.parse(file));
252
633
  return license;
253
634
  } catch (err) {
@@ -255,11 +636,12 @@ var FileLicenseStore = class {
255
636
  }
256
637
  }
257
638
  async storeLocalLicense(license) {
258
- await fs.writeFile(this.path, JSON.stringify(license), { encoding: "utf-8" });
639
+ await fs2.writeFile(this.path, JSON.stringify(license), { encoding: "utf-8" });
259
640
  }
260
641
  async deleteLocalLicense() {
261
- if (!fsSync.existsSync(this.path)) return;
262
- await fs.rm(this.path);
642
+ if (!fsSync.existsSync(this.path))
643
+ return;
644
+ await fs2.rm(this.path);
263
645
  }
264
646
  get path() {
265
647
  var _a, _b, _c, _d;
@@ -268,8 +650,8 @@ var FileLicenseStore = class {
268
650
  };
269
651
 
270
652
  // src/validator.ts
271
- import { z as z2 } from "zod";
272
653
  import jwt from "jsonwebtoken";
654
+ import { z as z2 } from "zod";
273
655
  var licenseClaimsSchema = z2.object({
274
656
  ["l:id" /* LicenseId */]: z2.string(),
275
657
  ["trial" /* Trial */]: z2.string().or(z2.boolean()).transform((v) => v === true || v === "true").pipe(z2.boolean()),
@@ -306,15 +688,20 @@ var LicenseValidator = class {
306
688
  );
307
689
  }
308
690
  const expectedSignature = await this.deviceIdResolver.resolveDeviceId();
309
- if (expectedSignature !== claims["sig" /* ComputerSignature */]) {
310
- throw new MoonbaseError(
311
- "License invalide",
312
- "This license is not for this device",
313
- "LicenseExpired" /* LicenseExpired */
314
- );
315
- }
691
+ const boundSignature = claims["sig" /* ComputerSignature */];
692
+ if (expectedSignature !== boundSignature && !await this.acceptsHistoricalDeviceId(boundSignature))
693
+ throw deviceMismatchError(expectedSignature, boundSignature);
316
694
  return license;
317
695
  }
696
+ /**
697
+ * Give a {@link IMigratingDeviceIdResolver} the chance to vouch for a device id
698
+ * this machine used to have. Only consulted after the fast path fails, so
699
+ * apps that have not opted into a migration pay nothing.
700
+ */
701
+ async acceptsHistoricalDeviceId(boundSignature) {
702
+ const accepts = this.deviceIdResolver.acceptsDeviceId;
703
+ return typeof accepts === "function" && await accepts.call(this.deviceIdResolver, boundSignature);
704
+ }
318
705
  parseLicenseToken(token) {
319
706
  return new Promise((resolve, reject) => {
320
707
  jwt.verify(token, this.configuration.publicKey, {
@@ -379,11 +766,34 @@ var LicenseValidator = class {
379
766
  });
380
767
  }
381
768
  };
769
+ function deviceMismatchError(expected, bound) {
770
+ const detail = "This license is not for this device";
771
+ const versionNote = describeVersionDifference(expected, bound);
772
+ return new MoonbaseError(
773
+ "License is for another device",
774
+ versionNote ? `${detail}. ${versionNote}` : detail,
775
+ "LicenseDeviceMismatch" /* LicenseDeviceMismatch */
776
+ );
777
+ }
778
+ function describeVersionDifference(expected, bound) {
779
+ const expectedStamp = parseDeviceIdStamp(expected);
780
+ if (!expectedStamp)
781
+ return null;
782
+ const boundStamp = parseDeviceIdStamp(bound);
783
+ if (boundStamp && boundStamp.version === expectedStamp.version)
784
+ return null;
785
+ if (boundStamp && boundStamp.version > expectedStamp.version) {
786
+ return `The binding was created by device fingerprint v${boundStamp.version}, which is newer than the v${expectedStamp.version} this SDK computes \u2014 update the SDK rather than re-activating, which would rebind the device to the older algorithm.`;
787
+ }
788
+ const boundVersion = boundStamp ? `device fingerprint v${boundStamp.version}` : "an SDK predating versioned device fingerprints";
789
+ return `The binding was created by ${boundVersion}, while this SDK computes v${expectedStamp.version}, so this may instead be the same machine bound under the older algorithm \u2014 re-activate to find out, or configure a MigratingDeviceIdResolver to keep accepting the previous id.`;
790
+ }
382
791
 
383
792
  // src/index.ts
384
793
  function detectPlatform() {
385
- if (typeof process === "undefined") return void 0;
386
- switch (process.platform) {
794
+ if (typeof process3 === "undefined")
795
+ return void 0;
796
+ switch (process3.platform) {
387
797
  case "darwin":
388
798
  return "Mac";
389
799
  case "win32":
@@ -403,7 +813,7 @@ var MoonbaseLicensing = class {
403
813
  platform: configuration.platform === void 0 ? detectPlatform() : configuration.platform
404
814
  };
405
815
  this.store = (_a = configuration.licenseStore) != null ? _a : new InMemoryLicenseStore();
406
- this.deviceIdResolver = (_b = configuration.deivceIdResolver) != null ? _b : new DefaultDeviceIdResolver();
816
+ this.deviceIdResolver = (_b = configuration.deviceIdResolver) != null ? _b : new MoonbaseDeviceIdResolver();
407
817
  this.validator = new LicenseValidator(this.configuration, this.deviceIdResolver);
408
818
  this.client = new LicenseClient(this.configuration, this.deviceIdResolver, this.validator);
409
819
  }
@@ -415,7 +825,7 @@ var MoonbaseLicensing = class {
415
825
  format: "JWT"
416
826
  };
417
827
  const json = JSON.stringify(token);
418
- return Buffer.from(Buffer.from(json).toString("base64"));
828
+ return Buffer2.from(Buffer2.from(json).toString("base64"));
419
829
  }
420
830
  async readRawLicense(license) {
421
831
  return await this.client.validateRawLicense(license);
@@ -423,12 +833,31 @@ var MoonbaseLicensing = class {
423
833
  };
424
834
  export {
425
835
  ActivationMethod,
426
- DefaultDeviceIdResolver,
427
836
  ErrorType,
837
+ FINGERPRINT_PREFIX,
838
+ FINGERPRINT_VERSION,
428
839
  FileLicenseStore,
840
+ IDENTIFYING_PARAM_NAMES,
429
841
  InMemoryLicenseStore,
842
+ InsufficientDeviceIdentityError,
843
+ LegacyDeviceIdResolver,
430
844
  LicenseClient,
431
845
  LicenseValidator,
846
+ MAX_VALUE_LENGTH,
847
+ MigratingDeviceIdResolver,
848
+ MoonbaseDeviceIdResolver,
432
849
  MoonbaseError,
433
- MoonbaseLicensing
850
+ MoonbaseLicensing,
851
+ buildFingerprintMaterial,
852
+ canonicalizeParams,
853
+ canonicalizeValue,
854
+ defaultDeviceIdentityReader,
855
+ fingerprintDeviceId,
856
+ fingerprintDigest,
857
+ parseDeviceIdStamp,
858
+ parseIoregPlatformUuid,
859
+ parseSmbiosParams,
860
+ platformTag,
861
+ selectMachineId,
862
+ stampDeviceId
434
863
  };