@moonbase.sh/licensing 0.3.37

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.cjs ADDED
@@ -0,0 +1,424 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ ActivationMethod: () => ActivationMethod,
34
+ DefaultDeviceIdResolver: () => DefaultDeviceIdResolver,
35
+ ErrorType: () => ErrorType,
36
+ FileLicenseStore: () => FileLicenseStore,
37
+ InMemoryLicenseStore: () => InMemoryLicenseStore,
38
+ LicenseClient: () => LicenseClient,
39
+ LicenseValidator: () => LicenseValidator,
40
+ MoonbaseError: () => MoonbaseError,
41
+ MoonbaseLicensing: () => MoonbaseLicensing
42
+ });
43
+ module.exports = __toCommonJS(src_exports);
44
+
45
+ // src/client.ts
46
+ var import_cross_fetch = __toESM(require("cross-fetch"), 1);
47
+
48
+ // src/types.ts
49
+ var ActivationMethod = /* @__PURE__ */ ((ActivationMethod2) => {
50
+ ActivationMethod2["Online"] = "Online";
51
+ ActivationMethod2["Offline"] = "Offline";
52
+ return ActivationMethod2;
53
+ })(ActivationMethod || {});
54
+
55
+ // src/schemas.ts
56
+ var import_zod = require("zod");
57
+ var activationRequestResponseSchema = import_zod.z.object({
58
+ id: import_zod.z.string(),
59
+ request: import_zod.z.string(),
60
+ browser: import_zod.z.string()
61
+ });
62
+ var productSchema = import_zod.z.object({
63
+ id: import_zod.z.string(),
64
+ name: import_zod.z.string(),
65
+ currentReleaseVersion: import_zod.z.string().nullish()
66
+ });
67
+ var userSchema = import_zod.z.object({
68
+ id: import_zod.z.string(),
69
+ name: import_zod.z.string(),
70
+ email: import_zod.z.string()
71
+ });
72
+ var licenseSchema = import_zod.z.object({
73
+ id: import_zod.z.string(),
74
+ trial: import_zod.z.boolean(),
75
+ activationMethod: import_zod.z.nativeEnum(ActivationMethod),
76
+ product: productSchema,
77
+ issuedAt: import_zod.z.coerce.date(),
78
+ issuedTo: userSchema,
79
+ expiresAt: import_zod.z.coerce.date().nullish(),
80
+ validatedAt: import_zod.z.coerce.date(),
81
+ token: import_zod.z.string()
82
+ });
83
+
84
+ // src/client.ts
85
+ var defaultFetchOptions = {
86
+ method: "GET",
87
+ mode: "cors",
88
+ headers: {
89
+ "Accept": "application/json",
90
+ "Content-Type": "application/json",
91
+ "x-mb-client": `moonbase.js`
92
+ }
93
+ };
94
+ var LicenseClient = class {
95
+ constructor(configuration, deviceIdResolver, licenseValidator) {
96
+ this.configuration = configuration;
97
+ this.deviceIdResolver = deviceIdResolver;
98
+ this.licenseValidator = licenseValidator;
99
+ }
100
+ async requestActivation() {
101
+ const content = {
102
+ deviceName: await this.deviceIdResolver.resolveDeviceName(),
103
+ deviceSignature: await this.deviceIdResolver.resolveDeviceId()
104
+ };
105
+ const response = await (0, import_cross_fetch.default)(this.configuration.endpoint + `/api/client/activations/${this.configuration.productId}/request?format=JWT`, {
106
+ ...defaultFetchOptions,
107
+ method: "POST",
108
+ body: JSON.stringify(content)
109
+ });
110
+ if (response.status >= 400) {
111
+ throw new MoonbaseError("Request not successful", `The API responded with a ${response.status} ${response.statusText} response`, "ApiError" /* ApiError */);
112
+ }
113
+ try {
114
+ return activationRequestResponseSchema.parse(await response.json());
115
+ } catch (err) {
116
+ const error = err;
117
+ throw new MoonbaseError(
118
+ "Could not request activation",
119
+ error.message,
120
+ "ApiError" /* ApiError */,
121
+ error
122
+ );
123
+ }
124
+ }
125
+ async getRequestedActivation(request) {
126
+ const response = await (0, import_cross_fetch.default)(request.request, defaultFetchOptions);
127
+ if (response.status === 204 || response.status === 404)
128
+ return null;
129
+ return await this.handleLicenseResponse(response);
130
+ }
131
+ async validateLicense(license) {
132
+ const response = await (0, import_cross_fetch.default)(this.configuration.endpoint + `/api/client/licenses/${this.configuration.productId}/validate?format=JWT`, {
133
+ ...defaultFetchOptions,
134
+ method: "POST",
135
+ headers: {
136
+ ...defaultFetchOptions.headers,
137
+ "Content-Type": "text/plain"
138
+ },
139
+ body: license.token
140
+ });
141
+ return await this.handleLicenseResponse(response);
142
+ }
143
+ async validateRawLicense(rawLicense) {
144
+ const license = await this.licenseValidator.validateLicense(rawLicense.toString("utf8"));
145
+ if (license.activationMethod === "Offline" /* Offline */)
146
+ return license;
147
+ return await this.validateLicense(license);
148
+ }
149
+ async revokeLicense(license) {
150
+ const response = await (0, import_cross_fetch.default)(this.configuration.endpoint + `/api/client/licenses/${this.configuration.productId}/revoke?format=JWT`, {
151
+ ...defaultFetchOptions,
152
+ method: "POST",
153
+ headers: {
154
+ ...defaultFetchOptions.headers,
155
+ "Content-Type": "text/plain"
156
+ },
157
+ body: license.token
158
+ });
159
+ if (response.status >= 400) {
160
+ throw new MoonbaseError("Request not successful", `The API responded with a ${response.status} ${response.statusText} response`, "ApiError" /* ApiError */);
161
+ }
162
+ }
163
+ async handleLicenseResponse(response) {
164
+ if (response.status >= 400) {
165
+ throw new MoonbaseError("Request not successful", `The API responded with a ${response.status} ${response.statusText} response`, "ApiError" /* ApiError */);
166
+ }
167
+ return await this.licenseValidator.validateLicense(await response.text());
168
+ }
169
+ };
170
+
171
+ // src/deviceIdResolver.ts
172
+ var import_systeminformation = __toESM(require("systeminformation"), 1);
173
+ var import_node_os = __toESM(require("os"), 1);
174
+ var import_node_child_process = __toESM(require("child_process"), 1);
175
+ var import_node_crypto = require("crypto");
176
+ var DefaultDeviceIdResolver = class {
177
+ async resolveDeviceName() {
178
+ switch (process.platform) {
179
+ case "darwin":
180
+ try {
181
+ return import_node_child_process.default.execSync("scutil --get ComputerName").toString().trim();
182
+ } catch (e) {
183
+ return import_node_os.default.hostname();
184
+ }
185
+ case "win32":
186
+ return process.env.COMPUTERNAME || import_node_os.default.hostname();
187
+ case "linux":
188
+ const prettyname = import_node_child_process.default.execSync("hostnamectl --pretty").toString().trim();
189
+ return prettyname || import_node_os.default.hostname();
190
+ default:
191
+ return import_node_os.default.hostname();
192
+ }
193
+ }
194
+ async resolveDeviceId() {
195
+ const [cpu, hw] = await Promise.all([import_systeminformation.default.cpu(), import_systeminformation.default.system()]);
196
+ const parts = [
197
+ import_node_os.default.hostname(),
198
+ hw.manufacturer,
199
+ hw.model,
200
+ hw.serial,
201
+ hw.uuid,
202
+ hw.sku,
203
+ cpu.manufacturer,
204
+ cpu.brand,
205
+ cpu.vendor,
206
+ cpu.family,
207
+ cpu.model
208
+ ];
209
+ const hash = (0, import_node_crypto.createHash)("sha256").update(parts.join("")).digest();
210
+ return hash.toString("base64").replaceAll("=", "");
211
+ }
212
+ };
213
+
214
+ // src/store.ts
215
+ var import_node_fs = __toESM(require("fs"), 1);
216
+ var import_promises = __toESM(require("fs/promises"), 1);
217
+ var import_node_path = __toESM(require("path"), 1);
218
+
219
+ // src/errors.ts
220
+ var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
221
+ ErrorType2["None"] = "None";
222
+ ErrorType2["ApiError"] = "ApiError";
223
+ ErrorType2["NoEligibleLicense"] = "NoEligibleLicense";
224
+ ErrorType2["LicenseInvalid"] = "LicenseInvalid";
225
+ ErrorType2["LicenseRevoked"] = "LicenseRevoked";
226
+ ErrorType2["LicenseActivationRevoked"] = "LicenseActivationRevoked";
227
+ ErrorType2["LicenseExpired"] = "LicenseExpired";
228
+ return ErrorType2;
229
+ })(ErrorType || {});
230
+ var MoonbaseError = class extends Error {
231
+ constructor(title, detail, type, inner) {
232
+ super();
233
+ this.title = title;
234
+ this.detail = detail;
235
+ this.type = type;
236
+ this.inner = inner;
237
+ this.name = "MoonbaseError";
238
+ this.message = detail != null ? detail : title;
239
+ }
240
+ };
241
+
242
+ // src/store.ts
243
+ var InMemoryLicenseStore = class {
244
+ async loadLocalLicense() {
245
+ var _a;
246
+ return (_a = this.license) != null ? _a : null;
247
+ }
248
+ async storeLocalLicense(license) {
249
+ this.license = license;
250
+ }
251
+ async deleteLocalLicense() {
252
+ this.license = void 0;
253
+ }
254
+ };
255
+ var FileLicenseStore = class {
256
+ constructor(options) {
257
+ this.options = options;
258
+ }
259
+ async loadLocalLicense() {
260
+ if (!import_node_fs.default.existsSync(this.path))
261
+ return null;
262
+ try {
263
+ const file = await import_promises.default.readFile(this.path, { encoding: "utf-8" });
264
+ const license = licenseSchema.parse(JSON.parse(file));
265
+ return license;
266
+ } catch (err) {
267
+ throw new MoonbaseError("File error", "Could not load local license", "LicenseInvalid" /* LicenseInvalid */, err);
268
+ }
269
+ }
270
+ async storeLocalLicense(license) {
271
+ await import_promises.default.writeFile(this.path, JSON.stringify(license), { encoding: "utf-8" });
272
+ }
273
+ async deleteLocalLicense() {
274
+ if (!import_node_fs.default.existsSync(this.path))
275
+ return;
276
+ await import_promises.default.rm(this.path);
277
+ }
278
+ get path() {
279
+ var _a, _b, _c, _d;
280
+ return import_node_path.default.resolve((_b = (_a = this.options) == null ? void 0 : _a.dir) != null ? _b : import_node_path.default.resolve(), (_d = (_c = this.options) == null ? void 0 : _c.licenseFileName) != null ? _d : "license.mb");
281
+ }
282
+ };
283
+
284
+ // src/validator.ts
285
+ var import_zod2 = require("zod");
286
+ var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
287
+ var licenseClaimsSchema = import_zod2.z.object({
288
+ ["l:id" /* LicenseId */]: import_zod2.z.string(),
289
+ ["trial" /* Trial */]: import_zod2.z.string().or(import_zod2.z.boolean()).transform((v) => v === true || v === "true").pipe(import_zod2.z.boolean()),
290
+ ["method" /* ActivationMethod */]: import_zod2.z.nativeEnum(ActivationMethod),
291
+ ["sig" /* ComputerSignature */]: import_zod2.z.string(),
292
+ ["iat" /* IssuedAt */]: import_zod2.z.number().transform((v) => new Date(v * 1e3)).pipe(import_zod2.z.date()),
293
+ ["exp" /* ExpiresAt */]: import_zod2.z.number().nullish().transform((v) => v ? new Date(v * 1e3) : void 0).pipe(import_zod2.z.date().nullish()),
294
+ ["validated" /* ValidatedAt */]: import_zod2.z.number().transform((v) => new Date(v * 1e3)).pipe(import_zod2.z.date()),
295
+ ["p:id" /* ProductId */]: import_zod2.z.string(),
296
+ ["p:name" /* ProductName */]: import_zod2.z.string(),
297
+ ["p:rel" /* ProductReleaseVersion */]: import_zod2.z.string().nullish(),
298
+ ["u:id" /* UserId */]: import_zod2.z.string(),
299
+ ["u:name" /* UserName */]: import_zod2.z.string(),
300
+ ["u:email" /* UserEmail */]: import_zod2.z.string()
301
+ });
302
+ var LicenseValidator = class {
303
+ constructor(configuration, deviceIdResolver) {
304
+ this.configuration = configuration;
305
+ this.deviceIdResolver = deviceIdResolver;
306
+ }
307
+ async validateLicense(token) {
308
+ const [license, claims] = await this.parseLicenseToken(token);
309
+ if (license.expiresAt && license.expiresAt < /* @__PURE__ */ new Date()) {
310
+ throw new MoonbaseError(
311
+ "License expired",
312
+ "This license has expired",
313
+ "LicenseExpired" /* LicenseExpired */
314
+ );
315
+ }
316
+ const expectedSignature = await this.deviceIdResolver.resolveDeviceId();
317
+ if (expectedSignature !== claims["sig" /* ComputerSignature */]) {
318
+ throw new MoonbaseError(
319
+ "License invalide",
320
+ "This license is not for this device",
321
+ "LicenseExpired" /* LicenseExpired */
322
+ );
323
+ }
324
+ return license;
325
+ }
326
+ parseLicenseToken(token) {
327
+ return new Promise((resolve, reject) => {
328
+ import_jsonwebtoken.default.verify(token, this.configuration.publicKey, {
329
+ ignoreExpiration: true,
330
+ issuer: this.configuration.accountId,
331
+ audience: this.configuration.productId
332
+ }, (err, decoded) => {
333
+ var _a;
334
+ if (err) {
335
+ reject(new MoonbaseError(
336
+ "Could not validate license",
337
+ err.message,
338
+ "LicenseInvalid" /* LicenseInvalid */,
339
+ err
340
+ ));
341
+ return;
342
+ }
343
+ if (typeof decoded === "string") {
344
+ reject(new MoonbaseError(
345
+ "Could not validate license",
346
+ "The given license token could not be parsed",
347
+ "LicenseInvalid" /* LicenseInvalid */
348
+ ));
349
+ return;
350
+ }
351
+ try {
352
+ const claims = licenseClaimsSchema.parse(decoded);
353
+ resolve([{
354
+ id: claims["l:id" /* LicenseId */],
355
+ trial: claims["trial" /* Trial */],
356
+ activationMethod: claims["method" /* ActivationMethod */],
357
+ product: {
358
+ id: claims["p:id" /* ProductId */],
359
+ name: claims["p:name" /* ProductName */],
360
+ currentReleaseVersion: (_a = claims["p:rel" /* ProductReleaseVersion */]) != null ? _a : void 0
361
+ },
362
+ issuedTo: {
363
+ id: claims["u:id" /* UserId */],
364
+ name: claims["u:name" /* UserName */],
365
+ email: claims["u:email" /* UserEmail */]
366
+ },
367
+ expiresAt: claims["exp" /* ExpiresAt */] || void 0,
368
+ issuedAt: claims["iat" /* IssuedAt */],
369
+ validatedAt: claims["validated" /* ValidatedAt */],
370
+ token
371
+ }, claims]);
372
+ } catch (err2) {
373
+ const error = err2;
374
+ reject(new MoonbaseError(
375
+ "Could not validate license",
376
+ error.message,
377
+ "LicenseInvalid" /* LicenseInvalid */,
378
+ error
379
+ ));
380
+ }
381
+ });
382
+ });
383
+ }
384
+ };
385
+
386
+ // src/index.ts
387
+ var MoonbaseLicensing = class {
388
+ constructor(configuration) {
389
+ var _a, _b;
390
+ this.configuration = {
391
+ ...configuration,
392
+ endpoint: configuration.endpoint.replace(/\/$/, "")
393
+ };
394
+ this.store = (_a = configuration.licenseStore) != null ? _a : new InMemoryLicenseStore();
395
+ this.deviceIdResolver = (_b = configuration.deivceIdResolver) != null ? _b : new DefaultDeviceIdResolver();
396
+ this.validator = new LicenseValidator(this.configuration, this.deviceIdResolver);
397
+ this.client = new LicenseClient(this.configuration, this.deviceIdResolver, this.validator);
398
+ }
399
+ async generateDeviceToken() {
400
+ const token = {
401
+ id: await this.deviceIdResolver.resolveDeviceId(),
402
+ name: await this.deviceIdResolver.resolveDeviceName(),
403
+ productId: this.configuration.productId,
404
+ format: "JWT"
405
+ };
406
+ const json = JSON.stringify(token);
407
+ return Buffer.from(Buffer.from(json).toString("base64"));
408
+ }
409
+ async readRawLicense(license) {
410
+ return await this.client.validateRawLicense(license);
411
+ }
412
+ };
413
+ // Annotate the CommonJS export names for ESM import in node:
414
+ 0 && (module.exports = {
415
+ ActivationMethod,
416
+ DefaultDeviceIdResolver,
417
+ ErrorType,
418
+ FileLicenseStore,
419
+ InMemoryLicenseStore,
420
+ LicenseClient,
421
+ LicenseValidator,
422
+ MoonbaseError,
423
+ MoonbaseLicensing
424
+ });
@@ -0,0 +1,273 @@
1
+ import { z } from 'zod';
2
+
3
+ interface IDeviceIdResolver {
4
+ resolveDeviceName(): Promise<string>;
5
+ resolveDeviceId(): Promise<string>;
6
+ }
7
+ declare class DefaultDeviceIdResolver implements IDeviceIdResolver {
8
+ resolveDeviceName(): Promise<string>;
9
+ resolveDeviceId(): Promise<string>;
10
+ }
11
+
12
+ declare const activationRequestResponseSchema: z.ZodObject<{
13
+ id: z.ZodString;
14
+ request: z.ZodString;
15
+ browser: z.ZodString;
16
+ }, "strip", z.ZodTypeAny, {
17
+ id: string;
18
+ request: string;
19
+ browser: string;
20
+ }, {
21
+ id: string;
22
+ request: string;
23
+ browser: string;
24
+ }>;
25
+ declare const productSchema: z.ZodObject<{
26
+ id: z.ZodString;
27
+ name: z.ZodString;
28
+ currentReleaseVersion: z.ZodOptional<z.ZodNullable<z.ZodString>>;
29
+ }, "strip", z.ZodTypeAny, {
30
+ id: string;
31
+ name: string;
32
+ currentReleaseVersion?: string | null | undefined;
33
+ }, {
34
+ id: string;
35
+ name: string;
36
+ currentReleaseVersion?: string | null | undefined;
37
+ }>;
38
+ declare const userSchema: z.ZodObject<{
39
+ id: z.ZodString;
40
+ name: z.ZodString;
41
+ email: z.ZodString;
42
+ }, "strip", z.ZodTypeAny, {
43
+ id: string;
44
+ name: string;
45
+ email: string;
46
+ }, {
47
+ id: string;
48
+ name: string;
49
+ email: string;
50
+ }>;
51
+ declare const licenseSchema: z.ZodObject<{
52
+ id: z.ZodString;
53
+ trial: z.ZodBoolean;
54
+ activationMethod: z.ZodNativeEnum<typeof ActivationMethod>;
55
+ product: z.ZodObject<{
56
+ id: z.ZodString;
57
+ name: z.ZodString;
58
+ currentReleaseVersion: z.ZodOptional<z.ZodNullable<z.ZodString>>;
59
+ }, "strip", z.ZodTypeAny, {
60
+ id: string;
61
+ name: string;
62
+ currentReleaseVersion?: string | null | undefined;
63
+ }, {
64
+ id: string;
65
+ name: string;
66
+ currentReleaseVersion?: string | null | undefined;
67
+ }>;
68
+ issuedAt: z.ZodDate;
69
+ issuedTo: z.ZodObject<{
70
+ id: z.ZodString;
71
+ name: z.ZodString;
72
+ email: z.ZodString;
73
+ }, "strip", z.ZodTypeAny, {
74
+ id: string;
75
+ name: string;
76
+ email: string;
77
+ }, {
78
+ id: string;
79
+ name: string;
80
+ email: string;
81
+ }>;
82
+ expiresAt: z.ZodOptional<z.ZodNullable<z.ZodDate>>;
83
+ validatedAt: z.ZodDate;
84
+ token: z.ZodString;
85
+ }, "strip", z.ZodTypeAny, {
86
+ id: string;
87
+ trial: boolean;
88
+ activationMethod: ActivationMethod;
89
+ product: {
90
+ id: string;
91
+ name: string;
92
+ currentReleaseVersion?: string | null | undefined;
93
+ };
94
+ issuedAt: Date;
95
+ issuedTo: {
96
+ id: string;
97
+ name: string;
98
+ email: string;
99
+ };
100
+ validatedAt: Date;
101
+ token: string;
102
+ expiresAt?: Date | null | undefined;
103
+ }, {
104
+ id: string;
105
+ trial: boolean;
106
+ activationMethod: ActivationMethod;
107
+ product: {
108
+ id: string;
109
+ name: string;
110
+ currentReleaseVersion?: string | null | undefined;
111
+ };
112
+ issuedAt: Date;
113
+ issuedTo: {
114
+ id: string;
115
+ name: string;
116
+ email: string;
117
+ };
118
+ validatedAt: Date;
119
+ token: string;
120
+ expiresAt?: Date | null | undefined;
121
+ }>;
122
+
123
+ declare enum ActivationMethod {
124
+ Online = "Online",
125
+ Offline = "Offline"
126
+ }
127
+ type License = z.infer<typeof licenseSchema>;
128
+ type Product = z.infer<typeof productSchema>;
129
+ type User = z.infer<typeof userSchema>;
130
+ interface DeviceToken {
131
+ id: string;
132
+ name: string;
133
+ productId: string;
134
+ format: 'JWT';
135
+ }
136
+ type ActivationRequestResponse = z.infer<typeof activationRequestResponseSchema>;
137
+
138
+ interface ILicenseClient {
139
+ /**
140
+ * Create a new request to have this product activated, which
141
+ * means the user will be able to open a browser to respond
142
+ * to the activation request.
143
+ * This can be used as an alternative way to authenticate
144
+ * license fulfillment without having to take in user credentials
145
+ * in the app. After requesting activation, open a browser with
146
+ * the returned browser URL, and start polling {@link getRequestedActivation}
147
+ * for a completed request with license.
148
+ *
149
+ * @returns Details about the requested activation with url to open in the browser
150
+ */
151
+ requestActivation(): Promise<ActivationRequestResponse>;
152
+ /**
153
+ * Takes in a activation request created through {@link requestActivation}
154
+ * and checks if the request has been fulfilled yet.
155
+ * The returned license will be either a trial or a full license
156
+ * depending on what the user chooses in the browser session.
157
+ *
158
+ * @param request The activation request to poll
159
+ * @returns A license if the request has been fulfilled, else null
160
+ */
161
+ getRequestedActivation(request: ActivationRequestResponse): Promise<License | null>;
162
+ /**
163
+ * Checks if the given license is still valid, not revoked
164
+ * and returns an updated license if still active.
165
+ * This method is a good way to ensure the user still has
166
+ * rights to use the product, and should be called regularly
167
+ * unless activated offline.
168
+ *
169
+ * @param license The license to validate
170
+ * @returns An updated license
171
+ */
172
+ validateLicense(license: License): Promise<License>;
173
+ /**
174
+ * Contrary to {@linkvalidateLicense }, this method takes
175
+ * in raw bytes of the license, which can be useful if you're
176
+ * reading the license from a file for offline activations.
177
+ *
178
+ * @param license The license to validate
179
+ * @returns An updated license
180
+ */
181
+ validateRawLicense(rawLicense: Buffer): Promise<License>;
182
+ /**
183
+ * Given a license, this method will try to revoke the license activation,
184
+ * freeing up a seat for other devices to activate the license.
185
+ * This will not work for offline-activated devices.
186
+ * @param license The license to revoke
187
+ */
188
+ revokeLicense(license: License): Promise<void>;
189
+ }
190
+ declare class LicenseClient implements ILicenseClient {
191
+ private readonly configuration;
192
+ private readonly deviceIdResolver;
193
+ private readonly licenseValidator;
194
+ constructor(configuration: MoonbaseConfiguration, deviceIdResolver: IDeviceIdResolver, licenseValidator: ILicenseValidator);
195
+ requestActivation(): Promise<ActivationRequestResponse>;
196
+ getRequestedActivation(request: ActivationRequestResponse): Promise<License | null>;
197
+ validateLicense(license: License): Promise<License>;
198
+ validateRawLicense(rawLicense: Buffer): Promise<License>;
199
+ revokeLicense(license: License): Promise<void>;
200
+ private handleLicenseResponse;
201
+ }
202
+
203
+ interface ILicenseStore {
204
+ loadLocalLicense(): Promise<License | null>;
205
+ storeLocalLicense(license: License): Promise<void>;
206
+ deleteLocalLicense(): Promise<void>;
207
+ }
208
+ declare class InMemoryLicenseStore implements ILicenseStore {
209
+ private license?;
210
+ loadLocalLicense(): Promise<License | null>;
211
+ storeLocalLicense(license: License): Promise<void>;
212
+ deleteLocalLicense(): Promise<void>;
213
+ }
214
+ declare class FileLicenseStore implements ILicenseStore {
215
+ private readonly options?;
216
+ constructor(options?: {
217
+ dir?: string | undefined;
218
+ licenseFileName?: string | undefined;
219
+ } | undefined);
220
+ loadLocalLicense(): Promise<License | null>;
221
+ storeLocalLicense(license: License): Promise<void>;
222
+ deleteLocalLicense(): Promise<void>;
223
+ private get path();
224
+ }
225
+
226
+ interface ILicenseValidator {
227
+ validateLicense(token: string): Promise<License>;
228
+ }
229
+ declare class LicenseValidator implements ILicenseValidator {
230
+ private readonly configuration;
231
+ private readonly deviceIdResolver;
232
+ constructor(configuration: MoonbaseConfiguration, deviceIdResolver: IDeviceIdResolver);
233
+ validateLicense(token: string): Promise<License>;
234
+ private parseLicenseToken;
235
+ }
236
+
237
+ declare enum ErrorType {
238
+ None = "None",
239
+ ApiError = "ApiError",
240
+ NoEligibleLicense = "NoEligibleLicense",
241
+ LicenseInvalid = "LicenseInvalid",
242
+ LicenseRevoked = "LicenseRevoked",
243
+ LicenseActivationRevoked = "LicenseActivationRevoked",
244
+ LicenseExpired = "LicenseExpired"
245
+ }
246
+ declare class MoonbaseError extends Error {
247
+ readonly title: string;
248
+ readonly detail: string | undefined;
249
+ readonly type?: ErrorType | undefined;
250
+ readonly inner?: Error | undefined;
251
+ constructor(title: string, detail: string | undefined, type?: ErrorType | undefined, inner?: Error | undefined);
252
+ }
253
+
254
+ interface MoonbaseConfiguration {
255
+ endpoint: string;
256
+ publicKey: string;
257
+ productId: string;
258
+ accountId?: string;
259
+ licenseStore?: ILicenseStore;
260
+ deivceIdResolver?: IDeviceIdResolver;
261
+ }
262
+ declare class MoonbaseLicensing {
263
+ private readonly configuration;
264
+ readonly store: ILicenseStore;
265
+ readonly deviceIdResolver: IDeviceIdResolver;
266
+ readonly client: ILicenseClient;
267
+ readonly validator: ILicenseValidator;
268
+ constructor(configuration: MoonbaseConfiguration);
269
+ generateDeviceToken(): Promise<Buffer>;
270
+ readRawLicense(license: Buffer): Promise<License>;
271
+ }
272
+
273
+ export { ActivationMethod, type ActivationRequestResponse, DefaultDeviceIdResolver, type DeviceToken, ErrorType, FileLicenseStore, type IDeviceIdResolver, type ILicenseClient, type ILicenseStore, type ILicenseValidator, InMemoryLicenseStore, type License, LicenseClient, LicenseValidator, type MoonbaseConfiguration, MoonbaseError, MoonbaseLicensing, type Product, type User };
@@ -0,0 +1,273 @@
1
+ import { z } from 'zod';
2
+
3
+ interface IDeviceIdResolver {
4
+ resolveDeviceName(): Promise<string>;
5
+ resolveDeviceId(): Promise<string>;
6
+ }
7
+ declare class DefaultDeviceIdResolver implements IDeviceIdResolver {
8
+ resolveDeviceName(): Promise<string>;
9
+ resolveDeviceId(): Promise<string>;
10
+ }
11
+
12
+ declare const activationRequestResponseSchema: z.ZodObject<{
13
+ id: z.ZodString;
14
+ request: z.ZodString;
15
+ browser: z.ZodString;
16
+ }, "strip", z.ZodTypeAny, {
17
+ id: string;
18
+ request: string;
19
+ browser: string;
20
+ }, {
21
+ id: string;
22
+ request: string;
23
+ browser: string;
24
+ }>;
25
+ declare const productSchema: z.ZodObject<{
26
+ id: z.ZodString;
27
+ name: z.ZodString;
28
+ currentReleaseVersion: z.ZodOptional<z.ZodNullable<z.ZodString>>;
29
+ }, "strip", z.ZodTypeAny, {
30
+ id: string;
31
+ name: string;
32
+ currentReleaseVersion?: string | null | undefined;
33
+ }, {
34
+ id: string;
35
+ name: string;
36
+ currentReleaseVersion?: string | null | undefined;
37
+ }>;
38
+ declare const userSchema: z.ZodObject<{
39
+ id: z.ZodString;
40
+ name: z.ZodString;
41
+ email: z.ZodString;
42
+ }, "strip", z.ZodTypeAny, {
43
+ id: string;
44
+ name: string;
45
+ email: string;
46
+ }, {
47
+ id: string;
48
+ name: string;
49
+ email: string;
50
+ }>;
51
+ declare const licenseSchema: z.ZodObject<{
52
+ id: z.ZodString;
53
+ trial: z.ZodBoolean;
54
+ activationMethod: z.ZodNativeEnum<typeof ActivationMethod>;
55
+ product: z.ZodObject<{
56
+ id: z.ZodString;
57
+ name: z.ZodString;
58
+ currentReleaseVersion: z.ZodOptional<z.ZodNullable<z.ZodString>>;
59
+ }, "strip", z.ZodTypeAny, {
60
+ id: string;
61
+ name: string;
62
+ currentReleaseVersion?: string | null | undefined;
63
+ }, {
64
+ id: string;
65
+ name: string;
66
+ currentReleaseVersion?: string | null | undefined;
67
+ }>;
68
+ issuedAt: z.ZodDate;
69
+ issuedTo: z.ZodObject<{
70
+ id: z.ZodString;
71
+ name: z.ZodString;
72
+ email: z.ZodString;
73
+ }, "strip", z.ZodTypeAny, {
74
+ id: string;
75
+ name: string;
76
+ email: string;
77
+ }, {
78
+ id: string;
79
+ name: string;
80
+ email: string;
81
+ }>;
82
+ expiresAt: z.ZodOptional<z.ZodNullable<z.ZodDate>>;
83
+ validatedAt: z.ZodDate;
84
+ token: z.ZodString;
85
+ }, "strip", z.ZodTypeAny, {
86
+ id: string;
87
+ trial: boolean;
88
+ activationMethod: ActivationMethod;
89
+ product: {
90
+ id: string;
91
+ name: string;
92
+ currentReleaseVersion?: string | null | undefined;
93
+ };
94
+ issuedAt: Date;
95
+ issuedTo: {
96
+ id: string;
97
+ name: string;
98
+ email: string;
99
+ };
100
+ validatedAt: Date;
101
+ token: string;
102
+ expiresAt?: Date | null | undefined;
103
+ }, {
104
+ id: string;
105
+ trial: boolean;
106
+ activationMethod: ActivationMethod;
107
+ product: {
108
+ id: string;
109
+ name: string;
110
+ currentReleaseVersion?: string | null | undefined;
111
+ };
112
+ issuedAt: Date;
113
+ issuedTo: {
114
+ id: string;
115
+ name: string;
116
+ email: string;
117
+ };
118
+ validatedAt: Date;
119
+ token: string;
120
+ expiresAt?: Date | null | undefined;
121
+ }>;
122
+
123
+ declare enum ActivationMethod {
124
+ Online = "Online",
125
+ Offline = "Offline"
126
+ }
127
+ type License = z.infer<typeof licenseSchema>;
128
+ type Product = z.infer<typeof productSchema>;
129
+ type User = z.infer<typeof userSchema>;
130
+ interface DeviceToken {
131
+ id: string;
132
+ name: string;
133
+ productId: string;
134
+ format: 'JWT';
135
+ }
136
+ type ActivationRequestResponse = z.infer<typeof activationRequestResponseSchema>;
137
+
138
+ interface ILicenseClient {
139
+ /**
140
+ * Create a new request to have this product activated, which
141
+ * means the user will be able to open a browser to respond
142
+ * to the activation request.
143
+ * This can be used as an alternative way to authenticate
144
+ * license fulfillment without having to take in user credentials
145
+ * in the app. After requesting activation, open a browser with
146
+ * the returned browser URL, and start polling {@link getRequestedActivation}
147
+ * for a completed request with license.
148
+ *
149
+ * @returns Details about the requested activation with url to open in the browser
150
+ */
151
+ requestActivation(): Promise<ActivationRequestResponse>;
152
+ /**
153
+ * Takes in a activation request created through {@link requestActivation}
154
+ * and checks if the request has been fulfilled yet.
155
+ * The returned license will be either a trial or a full license
156
+ * depending on what the user chooses in the browser session.
157
+ *
158
+ * @param request The activation request to poll
159
+ * @returns A license if the request has been fulfilled, else null
160
+ */
161
+ getRequestedActivation(request: ActivationRequestResponse): Promise<License | null>;
162
+ /**
163
+ * Checks if the given license is still valid, not revoked
164
+ * and returns an updated license if still active.
165
+ * This method is a good way to ensure the user still has
166
+ * rights to use the product, and should be called regularly
167
+ * unless activated offline.
168
+ *
169
+ * @param license The license to validate
170
+ * @returns An updated license
171
+ */
172
+ validateLicense(license: License): Promise<License>;
173
+ /**
174
+ * Contrary to {@linkvalidateLicense }, this method takes
175
+ * in raw bytes of the license, which can be useful if you're
176
+ * reading the license from a file for offline activations.
177
+ *
178
+ * @param license The license to validate
179
+ * @returns An updated license
180
+ */
181
+ validateRawLicense(rawLicense: Buffer): Promise<License>;
182
+ /**
183
+ * Given a license, this method will try to revoke the license activation,
184
+ * freeing up a seat for other devices to activate the license.
185
+ * This will not work for offline-activated devices.
186
+ * @param license The license to revoke
187
+ */
188
+ revokeLicense(license: License): Promise<void>;
189
+ }
190
+ declare class LicenseClient implements ILicenseClient {
191
+ private readonly configuration;
192
+ private readonly deviceIdResolver;
193
+ private readonly licenseValidator;
194
+ constructor(configuration: MoonbaseConfiguration, deviceIdResolver: IDeviceIdResolver, licenseValidator: ILicenseValidator);
195
+ requestActivation(): Promise<ActivationRequestResponse>;
196
+ getRequestedActivation(request: ActivationRequestResponse): Promise<License | null>;
197
+ validateLicense(license: License): Promise<License>;
198
+ validateRawLicense(rawLicense: Buffer): Promise<License>;
199
+ revokeLicense(license: License): Promise<void>;
200
+ private handleLicenseResponse;
201
+ }
202
+
203
+ interface ILicenseStore {
204
+ loadLocalLicense(): Promise<License | null>;
205
+ storeLocalLicense(license: License): Promise<void>;
206
+ deleteLocalLicense(): Promise<void>;
207
+ }
208
+ declare class InMemoryLicenseStore implements ILicenseStore {
209
+ private license?;
210
+ loadLocalLicense(): Promise<License | null>;
211
+ storeLocalLicense(license: License): Promise<void>;
212
+ deleteLocalLicense(): Promise<void>;
213
+ }
214
+ declare class FileLicenseStore implements ILicenseStore {
215
+ private readonly options?;
216
+ constructor(options?: {
217
+ dir?: string | undefined;
218
+ licenseFileName?: string | undefined;
219
+ } | undefined);
220
+ loadLocalLicense(): Promise<License | null>;
221
+ storeLocalLicense(license: License): Promise<void>;
222
+ deleteLocalLicense(): Promise<void>;
223
+ private get path();
224
+ }
225
+
226
+ interface ILicenseValidator {
227
+ validateLicense(token: string): Promise<License>;
228
+ }
229
+ declare class LicenseValidator implements ILicenseValidator {
230
+ private readonly configuration;
231
+ private readonly deviceIdResolver;
232
+ constructor(configuration: MoonbaseConfiguration, deviceIdResolver: IDeviceIdResolver);
233
+ validateLicense(token: string): Promise<License>;
234
+ private parseLicenseToken;
235
+ }
236
+
237
+ declare enum ErrorType {
238
+ None = "None",
239
+ ApiError = "ApiError",
240
+ NoEligibleLicense = "NoEligibleLicense",
241
+ LicenseInvalid = "LicenseInvalid",
242
+ LicenseRevoked = "LicenseRevoked",
243
+ LicenseActivationRevoked = "LicenseActivationRevoked",
244
+ LicenseExpired = "LicenseExpired"
245
+ }
246
+ declare class MoonbaseError extends Error {
247
+ readonly title: string;
248
+ readonly detail: string | undefined;
249
+ readonly type?: ErrorType | undefined;
250
+ readonly inner?: Error | undefined;
251
+ constructor(title: string, detail: string | undefined, type?: ErrorType | undefined, inner?: Error | undefined);
252
+ }
253
+
254
+ interface MoonbaseConfiguration {
255
+ endpoint: string;
256
+ publicKey: string;
257
+ productId: string;
258
+ accountId?: string;
259
+ licenseStore?: ILicenseStore;
260
+ deivceIdResolver?: IDeviceIdResolver;
261
+ }
262
+ declare class MoonbaseLicensing {
263
+ private readonly configuration;
264
+ readonly store: ILicenseStore;
265
+ readonly deviceIdResolver: IDeviceIdResolver;
266
+ readonly client: ILicenseClient;
267
+ readonly validator: ILicenseValidator;
268
+ constructor(configuration: MoonbaseConfiguration);
269
+ generateDeviceToken(): Promise<Buffer>;
270
+ readRawLicense(license: Buffer): Promise<License>;
271
+ }
272
+
273
+ export { ActivationMethod, type ActivationRequestResponse, DefaultDeviceIdResolver, type DeviceToken, ErrorType, FileLicenseStore, type IDeviceIdResolver, type ILicenseClient, type ILicenseStore, type ILicenseValidator, InMemoryLicenseStore, type License, LicenseClient, LicenseValidator, type MoonbaseConfiguration, MoonbaseError, MoonbaseLicensing, type Product, type User };
package/dist/index.js ADDED
@@ -0,0 +1,379 @@
1
+ // src/client.ts
2
+ import fetch from "cross-fetch";
3
+
4
+ // src/types.ts
5
+ var ActivationMethod = /* @__PURE__ */ ((ActivationMethod2) => {
6
+ ActivationMethod2["Online"] = "Online";
7
+ ActivationMethod2["Offline"] = "Offline";
8
+ return ActivationMethod2;
9
+ })(ActivationMethod || {});
10
+
11
+ // src/schemas.ts
12
+ import { z } from "zod";
13
+ var activationRequestResponseSchema = z.object({
14
+ id: z.string(),
15
+ request: z.string(),
16
+ browser: z.string()
17
+ });
18
+ var productSchema = z.object({
19
+ id: z.string(),
20
+ name: z.string(),
21
+ currentReleaseVersion: z.string().nullish()
22
+ });
23
+ var userSchema = z.object({
24
+ id: z.string(),
25
+ name: z.string(),
26
+ email: z.string()
27
+ });
28
+ var licenseSchema = z.object({
29
+ id: z.string(),
30
+ trial: z.boolean(),
31
+ activationMethod: z.nativeEnum(ActivationMethod),
32
+ product: productSchema,
33
+ issuedAt: z.coerce.date(),
34
+ issuedTo: userSchema,
35
+ expiresAt: z.coerce.date().nullish(),
36
+ validatedAt: z.coerce.date(),
37
+ token: z.string()
38
+ });
39
+
40
+ // src/client.ts
41
+ var defaultFetchOptions = {
42
+ method: "GET",
43
+ mode: "cors",
44
+ headers: {
45
+ "Accept": "application/json",
46
+ "Content-Type": "application/json",
47
+ "x-mb-client": `moonbase.js`
48
+ }
49
+ };
50
+ var LicenseClient = class {
51
+ constructor(configuration, deviceIdResolver, licenseValidator) {
52
+ this.configuration = configuration;
53
+ this.deviceIdResolver = deviceIdResolver;
54
+ this.licenseValidator = licenseValidator;
55
+ }
56
+ async requestActivation() {
57
+ const content = {
58
+ deviceName: await this.deviceIdResolver.resolveDeviceName(),
59
+ deviceSignature: await this.deviceIdResolver.resolveDeviceId()
60
+ };
61
+ const response = await fetch(this.configuration.endpoint + `/api/client/activations/${this.configuration.productId}/request?format=JWT`, {
62
+ ...defaultFetchOptions,
63
+ method: "POST",
64
+ body: JSON.stringify(content)
65
+ });
66
+ if (response.status >= 400) {
67
+ throw new MoonbaseError("Request not successful", `The API responded with a ${response.status} ${response.statusText} response`, "ApiError" /* ApiError */);
68
+ }
69
+ try {
70
+ return activationRequestResponseSchema.parse(await response.json());
71
+ } catch (err) {
72
+ const error = err;
73
+ throw new MoonbaseError(
74
+ "Could not request activation",
75
+ error.message,
76
+ "ApiError" /* ApiError */,
77
+ error
78
+ );
79
+ }
80
+ }
81
+ async getRequestedActivation(request) {
82
+ const response = await fetch(request.request, defaultFetchOptions);
83
+ if (response.status === 204 || response.status === 404)
84
+ return null;
85
+ return await this.handleLicenseResponse(response);
86
+ }
87
+ async validateLicense(license) {
88
+ const response = await fetch(this.configuration.endpoint + `/api/client/licenses/${this.configuration.productId}/validate?format=JWT`, {
89
+ ...defaultFetchOptions,
90
+ method: "POST",
91
+ headers: {
92
+ ...defaultFetchOptions.headers,
93
+ "Content-Type": "text/plain"
94
+ },
95
+ body: license.token
96
+ });
97
+ return await this.handleLicenseResponse(response);
98
+ }
99
+ async validateRawLicense(rawLicense) {
100
+ const license = await this.licenseValidator.validateLicense(rawLicense.toString("utf8"));
101
+ if (license.activationMethod === "Offline" /* Offline */)
102
+ return license;
103
+ return await this.validateLicense(license);
104
+ }
105
+ async revokeLicense(license) {
106
+ const response = await fetch(this.configuration.endpoint + `/api/client/licenses/${this.configuration.productId}/revoke?format=JWT`, {
107
+ ...defaultFetchOptions,
108
+ method: "POST",
109
+ headers: {
110
+ ...defaultFetchOptions.headers,
111
+ "Content-Type": "text/plain"
112
+ },
113
+ body: license.token
114
+ });
115
+ if (response.status >= 400) {
116
+ throw new MoonbaseError("Request not successful", `The API responded with a ${response.status} ${response.statusText} response`, "ApiError" /* ApiError */);
117
+ }
118
+ }
119
+ async handleLicenseResponse(response) {
120
+ if (response.status >= 400) {
121
+ throw new MoonbaseError("Request not successful", `The API responded with a ${response.status} ${response.statusText} response`, "ApiError" /* ApiError */);
122
+ }
123
+ return await this.licenseValidator.validateLicense(await response.text());
124
+ }
125
+ };
126
+
127
+ // src/deviceIdResolver.ts
128
+ import si from "systeminformation";
129
+ import os from "os";
130
+ import cp from "child_process";
131
+ import { createHash } from "crypto";
132
+ var DefaultDeviceIdResolver = class {
133
+ async resolveDeviceName() {
134
+ switch (process.platform) {
135
+ case "darwin":
136
+ try {
137
+ return cp.execSync("scutil --get ComputerName").toString().trim();
138
+ } catch (e) {
139
+ return os.hostname();
140
+ }
141
+ case "win32":
142
+ return process.env.COMPUTERNAME || os.hostname();
143
+ case "linux":
144
+ const prettyname = cp.execSync("hostnamectl --pretty").toString().trim();
145
+ return prettyname || os.hostname();
146
+ default:
147
+ return os.hostname();
148
+ }
149
+ }
150
+ async resolveDeviceId() {
151
+ const [cpu, hw] = await Promise.all([si.cpu(), si.system()]);
152
+ const parts = [
153
+ os.hostname(),
154
+ hw.manufacturer,
155
+ hw.model,
156
+ hw.serial,
157
+ hw.uuid,
158
+ hw.sku,
159
+ cpu.manufacturer,
160
+ cpu.brand,
161
+ cpu.vendor,
162
+ cpu.family,
163
+ cpu.model
164
+ ];
165
+ const hash = createHash("sha256").update(parts.join("")).digest();
166
+ return hash.toString("base64").replaceAll("=", "");
167
+ }
168
+ };
169
+
170
+ // src/store.ts
171
+ import fsSync from "fs";
172
+ import fs from "fs/promises";
173
+ import path from "path";
174
+
175
+ // src/errors.ts
176
+ var ErrorType = /* @__PURE__ */ ((ErrorType2) => {
177
+ ErrorType2["None"] = "None";
178
+ ErrorType2["ApiError"] = "ApiError";
179
+ ErrorType2["NoEligibleLicense"] = "NoEligibleLicense";
180
+ ErrorType2["LicenseInvalid"] = "LicenseInvalid";
181
+ ErrorType2["LicenseRevoked"] = "LicenseRevoked";
182
+ ErrorType2["LicenseActivationRevoked"] = "LicenseActivationRevoked";
183
+ ErrorType2["LicenseExpired"] = "LicenseExpired";
184
+ return ErrorType2;
185
+ })(ErrorType || {});
186
+ var MoonbaseError = class extends Error {
187
+ constructor(title, detail, type, inner) {
188
+ super();
189
+ this.title = title;
190
+ this.detail = detail;
191
+ this.type = type;
192
+ this.inner = inner;
193
+ this.name = "MoonbaseError";
194
+ this.message = detail != null ? detail : title;
195
+ }
196
+ };
197
+
198
+ // src/store.ts
199
+ var InMemoryLicenseStore = class {
200
+ async loadLocalLicense() {
201
+ var _a;
202
+ return (_a = this.license) != null ? _a : null;
203
+ }
204
+ async storeLocalLicense(license) {
205
+ this.license = license;
206
+ }
207
+ async deleteLocalLicense() {
208
+ this.license = void 0;
209
+ }
210
+ };
211
+ var FileLicenseStore = class {
212
+ constructor(options) {
213
+ this.options = options;
214
+ }
215
+ async loadLocalLicense() {
216
+ if (!fsSync.existsSync(this.path))
217
+ return null;
218
+ try {
219
+ const file = await fs.readFile(this.path, { encoding: "utf-8" });
220
+ const license = licenseSchema.parse(JSON.parse(file));
221
+ return license;
222
+ } catch (err) {
223
+ throw new MoonbaseError("File error", "Could not load local license", "LicenseInvalid" /* LicenseInvalid */, err);
224
+ }
225
+ }
226
+ async storeLocalLicense(license) {
227
+ await fs.writeFile(this.path, JSON.stringify(license), { encoding: "utf-8" });
228
+ }
229
+ async deleteLocalLicense() {
230
+ if (!fsSync.existsSync(this.path))
231
+ return;
232
+ await fs.rm(this.path);
233
+ }
234
+ get path() {
235
+ var _a, _b, _c, _d;
236
+ return path.resolve((_b = (_a = this.options) == null ? void 0 : _a.dir) != null ? _b : path.resolve(), (_d = (_c = this.options) == null ? void 0 : _c.licenseFileName) != null ? _d : "license.mb");
237
+ }
238
+ };
239
+
240
+ // src/validator.ts
241
+ import { z as z2 } from "zod";
242
+ import jwt from "jsonwebtoken";
243
+ var licenseClaimsSchema = z2.object({
244
+ ["l:id" /* LicenseId */]: z2.string(),
245
+ ["trial" /* Trial */]: z2.string().or(z2.boolean()).transform((v) => v === true || v === "true").pipe(z2.boolean()),
246
+ ["method" /* ActivationMethod */]: z2.nativeEnum(ActivationMethod),
247
+ ["sig" /* ComputerSignature */]: z2.string(),
248
+ ["iat" /* IssuedAt */]: z2.number().transform((v) => new Date(v * 1e3)).pipe(z2.date()),
249
+ ["exp" /* ExpiresAt */]: z2.number().nullish().transform((v) => v ? new Date(v * 1e3) : void 0).pipe(z2.date().nullish()),
250
+ ["validated" /* ValidatedAt */]: z2.number().transform((v) => new Date(v * 1e3)).pipe(z2.date()),
251
+ ["p:id" /* ProductId */]: z2.string(),
252
+ ["p:name" /* ProductName */]: z2.string(),
253
+ ["p:rel" /* ProductReleaseVersion */]: z2.string().nullish(),
254
+ ["u:id" /* UserId */]: z2.string(),
255
+ ["u:name" /* UserName */]: z2.string(),
256
+ ["u:email" /* UserEmail */]: z2.string()
257
+ });
258
+ var LicenseValidator = class {
259
+ constructor(configuration, deviceIdResolver) {
260
+ this.configuration = configuration;
261
+ this.deviceIdResolver = deviceIdResolver;
262
+ }
263
+ async validateLicense(token) {
264
+ const [license, claims] = await this.parseLicenseToken(token);
265
+ if (license.expiresAt && license.expiresAt < /* @__PURE__ */ new Date()) {
266
+ throw new MoonbaseError(
267
+ "License expired",
268
+ "This license has expired",
269
+ "LicenseExpired" /* LicenseExpired */
270
+ );
271
+ }
272
+ const expectedSignature = await this.deviceIdResolver.resolveDeviceId();
273
+ if (expectedSignature !== claims["sig" /* ComputerSignature */]) {
274
+ throw new MoonbaseError(
275
+ "License invalide",
276
+ "This license is not for this device",
277
+ "LicenseExpired" /* LicenseExpired */
278
+ );
279
+ }
280
+ return license;
281
+ }
282
+ parseLicenseToken(token) {
283
+ return new Promise((resolve, reject) => {
284
+ jwt.verify(token, this.configuration.publicKey, {
285
+ ignoreExpiration: true,
286
+ issuer: this.configuration.accountId,
287
+ audience: this.configuration.productId
288
+ }, (err, decoded) => {
289
+ var _a;
290
+ if (err) {
291
+ reject(new MoonbaseError(
292
+ "Could not validate license",
293
+ err.message,
294
+ "LicenseInvalid" /* LicenseInvalid */,
295
+ err
296
+ ));
297
+ return;
298
+ }
299
+ if (typeof decoded === "string") {
300
+ reject(new MoonbaseError(
301
+ "Could not validate license",
302
+ "The given license token could not be parsed",
303
+ "LicenseInvalid" /* LicenseInvalid */
304
+ ));
305
+ return;
306
+ }
307
+ try {
308
+ const claims = licenseClaimsSchema.parse(decoded);
309
+ resolve([{
310
+ id: claims["l:id" /* LicenseId */],
311
+ trial: claims["trial" /* Trial */],
312
+ activationMethod: claims["method" /* ActivationMethod */],
313
+ product: {
314
+ id: claims["p:id" /* ProductId */],
315
+ name: claims["p:name" /* ProductName */],
316
+ currentReleaseVersion: (_a = claims["p:rel" /* ProductReleaseVersion */]) != null ? _a : void 0
317
+ },
318
+ issuedTo: {
319
+ id: claims["u:id" /* UserId */],
320
+ name: claims["u:name" /* UserName */],
321
+ email: claims["u:email" /* UserEmail */]
322
+ },
323
+ expiresAt: claims["exp" /* ExpiresAt */] || void 0,
324
+ issuedAt: claims["iat" /* IssuedAt */],
325
+ validatedAt: claims["validated" /* ValidatedAt */],
326
+ token
327
+ }, claims]);
328
+ } catch (err2) {
329
+ const error = err2;
330
+ reject(new MoonbaseError(
331
+ "Could not validate license",
332
+ error.message,
333
+ "LicenseInvalid" /* LicenseInvalid */,
334
+ error
335
+ ));
336
+ }
337
+ });
338
+ });
339
+ }
340
+ };
341
+
342
+ // src/index.ts
343
+ var MoonbaseLicensing = class {
344
+ constructor(configuration) {
345
+ var _a, _b;
346
+ this.configuration = {
347
+ ...configuration,
348
+ endpoint: configuration.endpoint.replace(/\/$/, "")
349
+ };
350
+ this.store = (_a = configuration.licenseStore) != null ? _a : new InMemoryLicenseStore();
351
+ this.deviceIdResolver = (_b = configuration.deivceIdResolver) != null ? _b : new DefaultDeviceIdResolver();
352
+ this.validator = new LicenseValidator(this.configuration, this.deviceIdResolver);
353
+ this.client = new LicenseClient(this.configuration, this.deviceIdResolver, this.validator);
354
+ }
355
+ async generateDeviceToken() {
356
+ const token = {
357
+ id: await this.deviceIdResolver.resolveDeviceId(),
358
+ name: await this.deviceIdResolver.resolveDeviceName(),
359
+ productId: this.configuration.productId,
360
+ format: "JWT"
361
+ };
362
+ const json = JSON.stringify(token);
363
+ return Buffer.from(Buffer.from(json).toString("base64"));
364
+ }
365
+ async readRawLicense(license) {
366
+ return await this.client.validateRawLicense(license);
367
+ }
368
+ };
369
+ export {
370
+ ActivationMethod,
371
+ DefaultDeviceIdResolver,
372
+ ErrorType,
373
+ FileLicenseStore,
374
+ InMemoryLicenseStore,
375
+ LicenseClient,
376
+ LicenseValidator,
377
+ MoonbaseError,
378
+ MoonbaseLicensing
379
+ };
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@moonbase.sh/licensing",
3
+ "type": "module",
4
+ "version": "0.3.37",
5
+ "description": "Package to add sotftware licensing using Moonbase.sh to your node.js apps",
6
+ "author": "Tobias Lønnerød Madsen <m@dsen.tv>",
7
+ "license": "MIT",
8
+ "sideEffects": false,
9
+ "main": "./dist/index.js",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "files": [
13
+ "dist/**"
14
+ ],
15
+ "dependencies": {
16
+ "cross-fetch": "^3.1.5",
17
+ "jsonwebtoken": "^9.0.2",
18
+ "systeminformation": "^5.25.11",
19
+ "zod": "^3.23.8"
20
+ },
21
+ "devDependencies": {
22
+ "@types/jsonwebtoken": "^9.0.9",
23
+ "@types/node": "^18.19.50",
24
+ "rimraf": "^5.0.10",
25
+ "tsup": "^7.1.0",
26
+ "typescript": "~5.1.6",
27
+ "vitest": "^2.1.4"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup src/index.ts --format esm,cjs --dts",
31
+ "dev": "tsup src/index.ts --format esm,cjs --watch --dts",
32
+ "version": "npm version",
33
+ "test": "vitest"
34
+ }
35
+ }