@n8n_io/license-sdk 1.3.3 → 1.4.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.
@@ -9,6 +9,7 @@ declare type TLicenseManagerConfig = {
9
9
  loadCertStr: () => Promise<TLicenseContainerStr>;
10
10
  saveCertStr: (cert: TLicenseContainerStr) => Promise<void>;
11
11
  deviceFingerprint?: () => string | Promise<string>;
12
+ onFeatureChange?: () => any;
12
13
  logger?: TLogger;
13
14
  };
14
15
  declare type TLicenseContainerStr = string;
@@ -40,6 +41,7 @@ declare type TLicenseCertObj = {
40
41
  terminatesAt: Date;
41
42
  featureSets: TFeatureSet[];
42
43
  productMetadata: {};
44
+ managementJwt: string;
43
45
  };
44
46
  declare type TLogger = {
45
47
  error: Function;
@@ -47,6 +49,12 @@ declare type TLogger = {
47
49
  info: Function;
48
50
  debug: Function;
49
51
  };
52
+ declare const enum LogLevel {
53
+ ERROR = "error",
54
+ WARN = "warn",
55
+ INFO = "info",
56
+ DEBUG = "debug"
57
+ }
50
58
  declare class LicenseManager {
51
59
  config: TLicenseManagerConfig;
52
60
  private key?;
@@ -56,7 +64,10 @@ declare class LicenseManager {
56
64
  private x509IssuerCert;
57
65
  private deviceFingerprint?;
58
66
  private renewalIntervalPointer?;
67
+ private checkUpcomingFeatureChangesCron?;
68
+ private featureChangeTimeoutPointer?;
59
69
  constructor(config: TLicenseManagerConfig);
70
+ log(msg: string, logLevel: LogLevel): void;
60
71
  initialize(): Promise<void>;
61
72
  reset(): void;
62
73
  computeDeviceFingerprint(): Promise<string>;
@@ -73,8 +84,11 @@ declare class LicenseManager {
73
84
  getFeatureValue(feature: string, requireValidCert?: boolean): undefined | boolean | number | string;
74
85
  getFeatures(): TFeatures;
75
86
  getProductMetadata(): {};
87
+ getManagementJwt(): string;
76
88
  isRenewalDue(): boolean;
77
89
  toString(): string;
90
+ private triggerOnFeatureChangeCallback;
91
+ private setTimerForNextFeatureChange;
78
92
  private renewalCron;
79
93
  private initCert;
80
94
  private stringifyCertContainer;
@@ -1,4 +1,4 @@
1
- "use strict";var y=Object.create;var o=Object.defineProperty;var m=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var I=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var b=(n,t)=>{for(var e in t)o(n,e,{get:t[e],enumerable:!0})},h=(n,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of v(t))!A.call(n,r)&&r!==e&&o(n,r,{get:()=>t[r],enumerable:!(i=m(t,r))||i.enumerable});return n};var u=(n,t,e)=>(e=n!=null?y(I(n)):{},h(t||!n||!n.__esModule?o(e,"default",{value:n,enumerable:!0}):e,n)),E=n=>h(o({},"__esModule",{value:!0}),n);var S={};b(S,{LicenseManager:()=>f});module.exports=E(S);var d=u(require("axios")),p=u(require("node-rsa")),l=u(require("crypto-js")),w=require("node-machine-id"),g=require("crypto"),f=class{constructor(t){this.config=t,this.config.logger?this.logger=this.config.logger:this.logger={error(){console.log("ERROR:",...arguments)},warn(){console.log("WARN:",...arguments)},info(){console.log("INFO:",...arguments)},debug(){console.log("DEBUG:",...arguments)}},this.x509IssuerCert=new g.X509Certificate(`-----BEGIN CERTIFICATE-----
1
+ "use strict";var w=Object.create;var c=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var I=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var b=(n,e)=>{for(var t in e)c(n,t,{get:e[t],enumerable:!0})},f=(n,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of v(e))!A.call(n,r)&&r!==t&&c(n,r,{get:()=>e[r],enumerable:!(i=y(e,r))||i.enumerable});return n};var u=(n,e,t)=>(t=n!=null?w(I(n)):{},f(e||!n||!n.__esModule?c(t,"default",{value:n,enumerable:!0}):t,n)),F=n=>f(c({},"__esModule",{value:!0}),n);var T={};b(T,{LicenseManager:()=>d});module.exports=F(T);var g=u(require("axios")),p=u(require("node-rsa")),l=u(require("crypto-js")),C=require("node-machine-id"),h=require("crypto");var d=class{constructor(e){this.config=e,this.config.logger?this.logger=this.config.logger:this.logger={error(){console.log("ERROR:",...arguments)},warn(){console.log("WARN:",...arguments)},info(){console.log("INFO:",...arguments)},debug(){console.log("DEBUG:",...arguments)}},this.x509IssuerCert=new h.X509Certificate(`-----BEGIN CERTIFICATE-----
2
2
  MIIFDDCCAvQCCQCWGBewlWbp0DANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJE
3
3
  RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xFzAVBgNVBAMMDmxp
4
4
  Y2Vuc2UubjhuLmlvMB4XDTIyMDYyNDA0MDkzM1oXDTQ5MTEwOTA0MDkzM1owSDEL
@@ -26,7 +26,7 @@ uMNs3MjEmfbaBV1K0GKG5UToF9UmUxxVmTcRUZrAQX+yBkRezDTpOQuRnB58BDQP
26
26
  A62lcgZlikzJw3lHue33qAudyUrUmjfHGll7GFQNeLO42jPMeM4NJiNIrBZ7j0uD
27
27
  4slHdDi/44PHcKchvde/5k7ZJMi6OC1Vu+bOnKvzhnWQIOkHFQ55m13oslV2ozZT
28
28
  /oqhn/8/LeV0ooZuYnBeRkRTveniUeho2OFe5xZvWSSfuBrbHt9+zBg+5MWPUTIJ
29
- -----END CERTIFICATE-----`),this.config.autoRenewEnabled=this.config.autoRenewEnabled??!0,this.config.autoRenewOffset=this.config.autoRenewOffset??60*60*72,this.config.server=this.config.server??"https://license.n8n.io/v1"}async initialize(){this.deviceFingerprint=await this.computeDeviceFingerprint(),this.logger.info(`initializing for deviceFingerprint ${this.deviceFingerprint}`),await this.initCert(),this.config.autoRenewEnabled&&(await this.renewalCron({force:!0}),this.renewalIntervalPointer=setInterval(()=>this.renewalCron({force:!1}),1e3*60*15))}reset(){this.config.autoRenewEnabled&&clearInterval(this.renewalIntervalPointer),this.licenseCert=void 0,this.deviceFingerprint=void 0}async computeDeviceFingerprint(){return this.config.deviceFingerprint&&typeof this.config.deviceFingerprint=="function"?await this.config.deviceFingerprint():await(0,w.machineId)()}async activate(t){let e=await d.default.post(`${this.config.server}/activate`,{reservationId:t,tenantId:this.config.tenantId,productIdentifier:this.config.productIdentifier,deviceFingerprint:this.deviceFingerprint},{validateStatus:i=>!0,timeout:1e4});if(e.status==200){if(!e.data.hasOwnProperty("licenseKey")||!e.data.hasOwnProperty("x509"))throw new Error("unexpected server response");let i=this.stringifyCertContainer(e.data);await this.config.saveCertStr(i),await this.initCert()}else{let i=new Error(`license activation failed: ${e.data.message??"unknown reason"}`);throw this.logger.warn(i.message),i}}async renew(){if(!this.isInitialized())throw new Error("renewal failed because current cert is not initialized");if(this.isTerminated())throw new Error("renewal failed because current cert was terminated");let t=await d.default.post(`${this.config.server}/renew`,{certId:this.licenseCert.id,tenantId:this.config.tenantId,productIdentifier:this.config.productIdentifier,deviceFingerprint:this.deviceFingerprint,renewalToken:this.licenseCert.renewalToken},{validateStatus:e=>!0,timeout:1e4});if(t.status==200){if(!t.data.hasOwnProperty("licenseKey")||!t.data.hasOwnProperty("x509"))throw new Error("unexpected server response");let e=this.stringifyCertContainer(t.data);await this.config.saveCertStr(e),this.logger.info("license successfully renewed"),await this.initCert()}else{let e=new Error(`license renewal failed: ${t.data.message??"unknown reason"}`);throw this.logger.warn(e.message),e}}isInitialized(){return this.licenseCert!==void 0}isTerminated(){if(!this.isInitialized())throw new Error("Cert is not initialized");let t=new Date;return this.licenseCert.terminatesAt<t}getExpiryDate(){if(!this.isInitialized())throw new Error("Cert is not initialized");return this.licenseCert.expiresAt}getTerminationDate(){if(!this.isInitialized())throw new Error("Cert is not initialized");return this.licenseCert.terminatesAt}isValid(t=!0){let e=this.logger,i=a=>{t&&e.debug(a)};if(!this.isInitialized())return i("cert is invalid because it is undefined"),!1;let r=this.licenseCert,s=new Date;return r.expiresAt<s?(i("cert is invalid because it has expired"),!1):r.terminatesAt<s?(i("cert is invalid because it was terminated"),!1):r.createdAt.getTime()-3e5>s.getTime()?(i("cert is invalid because system clock is out of sync"),!1):r.deviceLock&&this.deviceFingerprint!==r.deviceFingerprint?(i("cert is invalid because device fingerprint does not match"),!1):this.config.tenantId!==r.tenantId?(i("cert is invalid because tenant ID does not match"),!1):new RegExp(r.productIdentifierPattern).test(this.config.productIdentifier)?!0:(i("cert is invalid because product identifier does not match"),!1)}hasFeatureEnabled(t,e=!0){return!!this.getFeatureValue(t,e)}hasFeatureDefined(t,e=!0){return this.getFeatureValue(t,e)!==void 0}hasQuotaLeft(t,e){let i=this.getFeatureValue(t);if(i===void 0)return!1;if(typeof i!="number")throw new Error(`${t} cannot be used as quota as it is not numeric`);return i===-1?!0:Math.ceil(e)<Math.ceil(i)}getFeatureValue(t,e=!0){if(!this.isInitialized()||e&&!this.isValid())return;let i=this.getFeatures();if(!!i.hasOwnProperty(t))return i[t]}getFeatures(){if(!this.isInitialized())return{};let t=new Date().getTime(),e=this.licenseCert.createdAt.getTime(),i=this.licenseCert.featureSets.find(r=>r.validity===0||e+r.validity*1e3*60>=t);return i?i.features:{}}getProductMetadata(){return this.isInitialized()?this.licenseCert.productMetadata:{}}isRenewalDue(){if(!this.isInitialized())return!1;let t=new Date().getTime(),e=this.licenseCert.expiresAt.getTime(),i=this.licenseCert.terminatesAt.getTime();return t>e-this.config.autoRenewOffset*1e3&&t<i}toString(){return`certId: ${this.licenseCert?.id??"<n/a>"}
29
+ -----END CERTIFICATE-----`),this.config.autoRenewEnabled=this.config.autoRenewEnabled??!0,this.config.autoRenewOffset=this.config.autoRenewOffset??60*60*72,this.config.server=this.config.server??"https://license.n8n.io/v1"}log(e,t){this.logger[t](`[license] ${e}`)}async initialize(){this.isInitialized()||(this.deviceFingerprint=await this.computeDeviceFingerprint(),this.log(`initializing for deviceFingerprint ${this.deviceFingerprint}`,"info"),await this.initCert(),this.config.onFeatureChange&&(this.checkUpcomingFeatureChangesCron=setInterval(()=>this.setTimerForNextFeatureChange(),1e3*60*15)),this.config.autoRenewEnabled&&(await this.renewalCron({force:!0}),this.renewalIntervalPointer=setInterval(()=>this.renewalCron({force:!1}),1e3*60*15)))}reset(){this.config.autoRenewEnabled&&clearInterval(this.renewalIntervalPointer),this.checkUpcomingFeatureChangesCron&&clearInterval(this.checkUpcomingFeatureChangesCron),this.featureChangeTimeoutPointer&&clearTimeout(this.featureChangeTimeoutPointer),this.licenseCert=void 0,this.deviceFingerprint=void 0}async computeDeviceFingerprint(){return this.config.deviceFingerprint&&typeof this.config.deviceFingerprint=="function"?await this.config.deviceFingerprint():await(0,C.machineId)()}async activate(e){let t=await g.default.post(`${this.config.server}/activate`,{reservationId:e,tenantId:this.config.tenantId,productIdentifier:this.config.productIdentifier,deviceFingerprint:this.deviceFingerprint},{validateStatus:i=>!0,timeout:1e4});if(t.status==200){if(!t.data.hasOwnProperty("licenseKey")||!t.data.hasOwnProperty("x509"))throw new Error("unexpected server response");let i=this.stringifyCertContainer(t.data);await this.config.saveCertStr(i),await this.initCert()}else{let i=new Error(`license activation failed: ${t.data.message??"unknown reason"}`);throw this.log(i.message,"warn"),i}}async renew(){if(!this.isInitialized())throw new Error("renewal failed because current cert is not initialized");if(this.isTerminated())throw new Error("renewal failed because current cert was terminated");let e=await g.default.post(`${this.config.server}/renew`,{certId:this.licenseCert.id,tenantId:this.config.tenantId,productIdentifier:this.config.productIdentifier,deviceFingerprint:this.deviceFingerprint,renewalToken:this.licenseCert.renewalToken},{validateStatus:t=>!0,timeout:1e4});if(e.status==200){if(!e.data.hasOwnProperty("licenseKey")||!e.data.hasOwnProperty("x509"))throw new Error("unexpected server response");let t=this.stringifyCertContainer(e.data);await this.config.saveCertStr(t),this.log("license successfully renewed","info"),await this.initCert()}else{let t=new Error(`license renewal failed: ${e.data.message??"unknown reason"}`);throw this.log(t.message,"warn"),t}}isInitialized(){return this.licenseCert!==void 0}isTerminated(){if(!this.isInitialized())throw new Error("Cert is not initialized");let e=new Date;return this.licenseCert.terminatesAt<e}getExpiryDate(){if(!this.isInitialized())throw new Error("Cert is not initialized");return this.licenseCert.expiresAt}getTerminationDate(){if(!this.isInitialized())throw new Error("Cert is not initialized");return this.licenseCert.terminatesAt}isValid(e=!0){let t=s=>{e&&this.log(s,"debug")};if(!this.isInitialized())return t("cert is invalid because it is undefined"),!1;let i=this.licenseCert,r=new Date;return i.expiresAt<r?(t("cert is invalid because it has expired"),!1):i.terminatesAt<r?(t("cert is invalid because it was terminated"),!1):i.createdAt.getTime()-3e5>r.getTime()?(t("cert is invalid because system clock is out of sync"),!1):i.deviceLock&&this.deviceFingerprint!==i.deviceFingerprint?(t("cert is invalid because device fingerprint does not match"),!1):this.config.tenantId!==i.tenantId?(t("cert is invalid because tenant ID does not match"),!1):new RegExp(i.productIdentifierPattern).test(this.config.productIdentifier)?!0:(t("cert is invalid because product identifier does not match"),!1)}hasFeatureEnabled(e,t=!0){return!!this.getFeatureValue(e,t)}hasFeatureDefined(e,t=!0){return this.getFeatureValue(e,t)!==void 0}hasQuotaLeft(e,t){let i=this.getFeatureValue(e);if(i===void 0)return!1;if(typeof i!="number")throw new Error(`${e} cannot be used as quota as it is not numeric`);return i===-1?!0:Math.ceil(t)<Math.ceil(i)}getFeatureValue(e,t=!0){if(!this.isInitialized()||t&&!this.isValid())return;let i=this.getFeatures();if(!!i.hasOwnProperty(e))return i[e]}getFeatures(){if(!this.isInitialized())return{};let e=new Date().getTime(),t=this.licenseCert.createdAt.getTime(),i=this.licenseCert.featureSets.find(r=>r.validity===0||t+r.validity*1e3*60>=e);return i?i.features:{}}getProductMetadata(){return this.isInitialized()?this.licenseCert.productMetadata:{}}getManagementJwt(){return this.isInitialized()?this.licenseCert.managementJwt:""}isRenewalDue(){if(!this.isInitialized())return!1;let e=new Date().getTime(),t=this.licenseCert.expiresAt.getTime(),i=this.licenseCert.terminatesAt.getTime();return e>t-this.config.autoRenewOffset*1e3&&e<i}toString(){return`certId: ${this.licenseCert?.id??"<n/a>"}
30
30
  tenantId: ${this.config.tenantId??"<n/a>"}
31
31
  productIdentifier: ${this.config.productIdentifier??"<n/a>"}
32
32
  deviceFingerprint: ${this.deviceFingerprint}
@@ -37,5 +37,5 @@ terminatesAt: ${this.licenseCert?.terminatesAt??"<n/a>"}
37
37
  isValid: ${this.isValid(!1)}
38
38
  isRenewalDue: ${this.isRenewalDue()}
39
39
  featureSets: ${this.licenseCert?.featureSets?JSON.stringify(this.licenseCert?.featureSets):"<n/a>"}
40
- `}async renewalCron({force:t}){if(t||this.isRenewalDue()){this.logger.info("attempting license renewal");try{await this.renew()}catch{}}}async initCert(){try{let t=await this.config.loadCertStr();if(!t||t.length<50)throw new Error("cert length is too short");let{x509:e,licenseKey:i}=this.parseLicenseCertContainerStr(t);if(this.x509Cert=new g.X509Certificate(e),!this.x509Cert.checkIssued(this.getIssuerCert()))throw new Error("cert was not issued by an approved issuer");let s=this.x509Cert.publicKey.export({format:"pem",type:"pkcs1"});this.key=new p.default(s),this.licenseCert=this.parseLicenseKeyStr(i)}catch(t){this.logger.error(`cert could not be initialized. ${t instanceof Error?t.message:""}`)}}stringifyCertContainer(t){let e=JSON.stringify(t);return Buffer.from(e).toString("base64")}parseLicenseCertContainerStr(t){let e=Buffer.from(t,"base64").toString("ascii"),i=JSON.parse(e);if(!i.hasOwnProperty("licenseKey")||!i.hasOwnProperty("x509"))throw new Error("license cert container could not be parsed");return i}parseLicenseKeyStr(t){let e=this.validateLicenseKey(t);return{id:e.id,version:e.version,tenantId:e.tenantId,renewalToken:e.renewalToken,deviceLock:e.deviceLock,deviceFingerprint:e.deviceFingerprint,productIdentifierPattern:e.productIdentifierPattern,createdAt:new Date(e.createdAt),issuedAt:new Date(e.issuedAt),expiresAt:new Date(e.expiresAt),terminatesAt:new Date(e.terminatesAt),featureSets:e.featureSets,productMetadata:e.productMetadata}}validateLicenseKey(t){t=t.replace(/(\r\n|\n|\r)/gm,"");let e=t.match(/^-----BEGIN LICENSE KEY-----(?<encryptedSymmetricKey>.+\|\|)(?<encryptedData>.+)\|\|(?<signature>.+)-----END LICENSE KEY-----$/);if(!e)throw new Error("license key could not be parsed");let i=e.groups.encryptedSymmetricKey,r=e.groups.encryptedData,s=e.groups.signature,c,a;try{c=this.key.decryptPublic(i,"utf8")}catch{throw new Error("Invalid data: Could not extract symmetric key")}try{a=l.default.AES.decrypt(r,c).toString(l.default.enc.Utf8)}catch{throw new Error("Invalid Data: Could not decrypt data with key found")}if(this.key.verify(Buffer.from(a),s,"utf8","base64"))return JSON.parse(a);throw new Error("License Key signature invalid")}getIssuerCert(){return this.x509IssuerCert}};0&&(module.exports={LicenseManager});
40
+ `}triggerOnFeatureChangeCallback(){this.config.onFeatureChange&&this.config.onFeatureChange()}setTimerForNextFeatureChange(){if(!this.isInitialized()||!this.config.onFeatureChange)return;let e=new Date().getTime(),t=this.licenseCert.createdAt.getTime(),i=this.licenseCert.featureSets.find(s=>t+s.validity*1e3*60>e),r=[];i&&r.push(t+i.validity*1e3*60-e),r.push(this.licenseCert.expiresAt.getTime()-e),r.push(this.licenseCert.terminatesAt.getTime()-e),r=r.filter(s=>s>=0).sort((s,o)=>s-o);let a=r[0];a<15*60*1e3&&(clearTimeout(this.featureChangeTimeoutPointer),this.featureChangeTimeoutPointer=setTimeout(()=>{this.triggerOnFeatureChangeCallback(),this.setTimerForNextFeatureChange()},a+1e3))}async renewalCron({force:e}){if(e||this.isRenewalDue()){this.log("attempting license renewal","info");try{await this.renew()}catch{}}}async initCert(){try{let e=await this.config.loadCertStr();if(!e||e.length<50)throw new Error("cert string is undefined or too short");let{x509:t,licenseKey:i}=this.parseLicenseCertContainerStr(e);if(this.x509Cert=new h.X509Certificate(t),!this.x509Cert.checkIssued(this.getIssuerCert()))throw new Error("cert was not issued by an approved issuer");let a=this.x509Cert.publicKey.export({format:"pem",type:"pkcs1"});this.key=new p.default(a),this.licenseCert=this.parseLicenseKeyStr(i),this.triggerOnFeatureChangeCallback(),this.setTimerForNextFeatureChange()}catch(e){this.log(`cert could not be initialized. ${e instanceof Error?e.message:""}`,"error")}}stringifyCertContainer(e){let t=JSON.stringify(e);return Buffer.from(t).toString("base64")}parseLicenseCertContainerStr(e){let t=Buffer.from(e,"base64").toString("ascii"),i=JSON.parse(t);if(!i.hasOwnProperty("licenseKey")||!i.hasOwnProperty("x509"))throw new Error("license cert container could not be parsed");return i}parseLicenseKeyStr(e){let t=this.validateLicenseKey(e),i={...t};return i.createdAt=new Date(t.createdAt),i.issuedAt=new Date(t.issuedAt),i.expiresAt=new Date(t.expiresAt),i.terminatesAt=new Date(t.terminatesAt),i}validateLicenseKey(e){e=e.replace(/(\r\n|\n|\r)/gm,"");let t=e.match(/^-----BEGIN LICENSE KEY-----(?<encryptedSymmetricKey>.+\|\|)(?<encryptedData>.+)\|\|(?<signature>.+)-----END LICENSE KEY-----$/);if(!t)throw new Error("license key could not be parsed");let i=t.groups.encryptedSymmetricKey,r=t.groups.encryptedData,a=t.groups.signature,s,o;try{s=this.key.decryptPublic(i,"utf8")}catch{throw new Error("Invalid data: Could not extract symmetric key")}try{o=l.default.AES.decrypt(r,s).toString(l.default.enc.Utf8)}catch{throw new Error("Invalid Data: Could not decrypt data with key found")}if(this.key.verify(Buffer.from(o),a,"utf8","base64"))return JSON.parse(o);throw new Error("License Key signature invalid")}getIssuerCert(){return this.x509IssuerCert}};0&&(module.exports={LicenseManager});
41
41
  //# sourceMappingURL=LicenseManager.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/LicenseManager.ts"],"sourcesContent":["import axios from 'axios'\nimport NodeRSA from 'node-rsa'\nimport CryptoJS from 'crypto-js'\nimport { machineId } from 'node-machine-id'\nimport { X509Certificate } from 'node:crypto'\n\nexport type TLicenseManagerConfig = {\n server?: string\n tenantId: number\n productIdentifier: string\n autoRenewEnabled?: boolean\n autoRenewOffset?: number\n loadCertStr: () => Promise<TLicenseContainerStr>\n saveCertStr: (cert: TLicenseContainerStr) => Promise<void>\n deviceFingerprint?: () => string | Promise<string>\n logger?: TLogger\n}\n\nexport type TLicenseContainerStr = string\n\nexport type TLicenseContainer = {\n licenseKey: string\n x509: string\n}\n\nexport type TFeatures = { [key: string]: boolean | number | string }\n\nexport type TMetadata = {\n [key: string]: boolean | number | string | Array<any> | {}\n}\n\nexport type TFeatureSet = {\n validity: number | string // either number in minutes or duration (e.g. \"P14D\") as string\n features: TFeatures\n}\n\nexport type TLicenseCertObj = {\n id: string\n version: number\n tenantId: number\n renewalToken: string\n deviceLock: boolean\n deviceFingerprint: string\n productIdentifierPattern: string\n createdAt: Date\n issuedAt: Date\n expiresAt: Date\n terminatesAt: Date\n featureSets: TFeatureSet[]\n productMetadata: {}\n}\n\nexport type TLogger = {\n error: Function\n warn: Function\n info: Function\n debug: Function\n}\n\nexport class LicenseManager {\n public config: TLicenseManagerConfig\n\n private key?: NodeRSA\n private logger: TLogger\n private licenseCert?: TLicenseCertObj\n private x509Cert?: X509Certificate\n private x509IssuerCert: X509Certificate\n private deviceFingerprint?: string\n private renewalIntervalPointer?: NodeJS.Timer\n\n constructor(config: TLicenseManagerConfig) {\n this.config = config\n\n if (this.config.logger) {\n this.logger = this.config.logger\n } else {\n this.logger = {\n error() {\n console.log('ERROR:', ...arguments)\n },\n warn() {\n console.log('WARN:', ...arguments)\n },\n info() {\n console.log('INFO:', ...arguments)\n },\n debug() {\n console.log('DEBUG:', ...arguments)\n },\n }\n }\n\n this.x509IssuerCert = new X509Certificate(\n '-----BEGIN CERTIFICATE-----\\n' +\n 'MIIFDDCCAvQCCQCWGBewlWbp0DANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJE\\n' +\n 'RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xFzAVBgNVBAMMDmxp\\n' +\n 'Y2Vuc2UubjhuLmlvMB4XDTIyMDYyNDA0MDkzM1oXDTQ5MTEwOTA0MDkzM1owSDEL\\n' +\n 'MAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVybGluMRcw\\n' +\n 'FQYDVQQDDA5saWNlbnNlLm44bi5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC\\n' +\n 'AgoCggIBANK6Uj5CSyPaa2rf/bwH/AqzzINeWg4n94pECv4p8tsjy0+ZscodNn7Q\\n' +\n 'IvYW/6IUpax8fZvHCSqu0L7fsgLkw0+HDLlsln+ryI/3h1ElVZm67BfqOvhSfPj+\\n' +\n 'btxcP8EtS+6hbf74sqPEBFD0wikKhIPGdtBolp7rLXfTGs+5eMqSA5q4W1V+HUUU\\n' +\n 'zgaCdchzlHGTdIICNpbRozGeFTIIx1MPzMie+4zIs6i680efx2KJVZWsa2WuCSED\\n' +\n '+b0gSRTgoKQ3B7JjxJKfzHdOdM6JxhkCjrJIkJCrZL7wFypn+wMHsVFrsw/80WkS\\n' +\n 'dwBj/RqCPzKcRwnxs0WNLhkyT/XCMS/1pNzPymdFADu2tEZjhFsa5ziIhdoQz8po\\n' +\n 'Efheyg3mOZDWyu6oyHCLH9lUlsNjV9zZ6RICgvHZvHPmPqOLPomy4Qymq2osuH+S\\n' +\n '28rwEy0W3DCEfuS3dZHrSQfohGC9EAyyFAIPSGhTJSYJl0oNBZjpRM+jAm9ER7PM\\n' +\n 'K70/7g6z8uIgKa8/SD/Pezd/aWzxH/tOokAF5X5o5TzSOwVzqOJzY06EZC7CJnhs\\n' +\n 'sigAJTy1trZJBcZuWnKY5FqrK3QzjsQ9sWM0tRocfNOYmD21mubNo+RmMMo3kvYL\\n' +\n 'JoBfap/cuP6kx3OiRzBJ4luTEa6nRIYy+EjcPaN3+9L5iEZ9/NABAgMBAAEwDQYJ\\n' +\n 'KoZIhvcNAQELBQADggIBAIUpJ0Rh6C92cJqy6iehS8c77r1prj62gr6Acdy5QGh8\\n' +\n 'ax30ANDbPtkezVIIBk+0JjLkMxr3mwqCRsPgMshPcxhZwEafmZrWPPGRVsOfukB3\\n' +\n 'Gp10cIv1YmZ7AFY4i/izj5184+A+GjxrJBULQG1JfX4c7KW06Kaps85AaX/Tp0fl\\n' +\n '/hZ6oUe48aSSTuAW38hWZ5jCpBqfFyQ15ablJZt0fB8NkXEdFUcUEt/OHJfqF5fP\\n' +\n 'Nt5PWC1AuBxzSbzjwabOy/M4r8m5CzCeXSIjqbcsAq52myMoxvNrjKRtucQ7CjqK\\n' +\n 'LR6WdhMf+NLvyTI+evXMoXpDzlevkCpz17uDiDt9XrmvLSf3Ff8mdTRwzVmOmHfc\\n' +\n 'Ruz5v7WBR4cpBR/sC+WxOw9heLMHgYhPyRUM4voo55EcJGusXr/iavblBAnI0GUw\\n' +\n 'uMNs3MjEmfbaBV1K0GKG5UToF9UmUxxVmTcRUZrAQX+yBkRezDTpOQuRnB58BDQP\\n' +\n 'A62lcgZlikzJw3lHue33qAudyUrUmjfHGll7GFQNeLO42jPMeM4NJiNIrBZ7j0uD\\n' +\n '4slHdDi/44PHcKchvde/5k7ZJMi6OC1Vu+bOnKvzhnWQIOkHFQ55m13oslV2ozZT\\n' +\n '/oqhn/8/LeV0ooZuYnBeRkRTveniUeho2OFe5xZvWSSfuBrbHt9+zBg+5MWPUTIJ\\n' +\n '-----END CERTIFICATE-----'\n )\n\n //set defaults for not set config properties:\n this.config.autoRenewEnabled = this.config.autoRenewEnabled ?? true\n this.config.autoRenewOffset = this.config.autoRenewOffset ?? 60 * 60 * 72 // default: 72 hours\n this.config.server = this.config.server ?? 'https://license.n8n.io/v1'\n }\n\n async initialize() {\n this.deviceFingerprint = await this.computeDeviceFingerprint()\n this.logger.info(\n `initializing for deviceFingerprint ${this.deviceFingerprint}`\n )\n await this.initCert()\n\n if (this.config.autoRenewEnabled) {\n //invoke renewal immediately once:\n await this.renewalCron({ force: true })\n\n //and periodically:\n this.renewalIntervalPointer = setInterval(\n () => this.renewalCron({ force: false }),\n 1000 * 60 * 15 //15 minutes\n )\n }\n }\n\n reset() {\n if (this.config.autoRenewEnabled) {\n clearInterval(this.renewalIntervalPointer)\n }\n this.licenseCert = undefined\n this.deviceFingerprint = undefined\n }\n\n async computeDeviceFingerprint() {\n if (\n this.config.deviceFingerprint &&\n typeof this.config.deviceFingerprint === 'function'\n ) {\n return await this.config.deviceFingerprint()\n }\n return await machineId()\n }\n\n async activate(reservationId: string) {\n const response = await axios.post(\n `${this.config.server!}/activate`,\n {\n reservationId,\n tenantId: this.config.tenantId,\n productIdentifier: this.config.productIdentifier,\n deviceFingerprint: this.deviceFingerprint,\n },\n {\n validateStatus: (status) => true, //axios should never throw\n timeout: 10000,\n }\n )\n\n if (response.status == 200) {\n if (\n !response.data.hasOwnProperty('licenseKey') ||\n !response.data.hasOwnProperty('x509')\n ) {\n throw new Error('unexpected server response')\n }\n const containerStr = this.stringifyCertContainer(\n response.data as TLicenseContainer\n )\n await this.config.saveCertStr(containerStr)\n await this.initCert()\n } else {\n const e = new Error(\n `license activation failed: ${\n response.data.message ?? 'unknown reason'\n }`\n )\n this.logger.warn(e.message)\n throw e\n }\n }\n\n async renew() {\n if (!this.isInitialized()) {\n throw new Error('renewal failed because current cert is not initialized')\n }\n\n if (this.isTerminated()) {\n throw new Error('renewal failed because current cert was terminated')\n }\n\n const response = await axios.post(\n `${this.config.server!}/renew`,\n {\n certId: this.licenseCert!.id,\n tenantId: this.config.tenantId,\n productIdentifier: this.config.productIdentifier,\n deviceFingerprint: this.deviceFingerprint,\n renewalToken: this.licenseCert!.renewalToken,\n },\n {\n validateStatus: (_status) => true, //axios should never throw\n timeout: 10000,\n }\n )\n\n if (response.status == 200) {\n if (\n !response.data.hasOwnProperty('licenseKey') ||\n !response.data.hasOwnProperty('x509')\n ) {\n throw new Error('unexpected server response')\n }\n const containerStr = this.stringifyCertContainer(\n response.data as TLicenseContainer\n )\n await this.config.saveCertStr(containerStr)\n this.logger.info('license successfully renewed')\n await this.initCert()\n } else {\n const e = new Error(\n `license renewal failed: ${response.data.message ?? 'unknown reason'}`\n )\n this.logger.warn(e.message)\n throw e\n }\n }\n\n private isInitialized() {\n return this.licenseCert !== undefined\n }\n\n isTerminated(): boolean {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n const now = new Date()\n\n return this.licenseCert!.terminatesAt < now\n }\n\n getExpiryDate(): Date {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n return this.licenseCert!.expiresAt\n }\n\n getTerminationDate(): Date {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n return this.licenseCert!.terminatesAt\n }\n\n isValid(useLogger = true): boolean {\n const logger = this.logger\n const debug = (msg: string) => {\n if (useLogger) {\n logger.debug(msg)\n }\n }\n\n if (!this.isInitialized()) {\n debug('cert is invalid because it is undefined')\n return false\n }\n\n const cert = this.licenseCert as TLicenseCertObj\n const now = new Date()\n\n if (cert.expiresAt < now) {\n debug('cert is invalid because it has expired')\n return false\n }\n\n if (cert.terminatesAt < now) {\n debug('cert is invalid because it was terminated')\n return false\n }\n\n //allow clocks to be out of sync by no more than 300,000 ms / = 5 minutes\n if (cert.createdAt.getTime() - 300000 > now.getTime()) {\n debug('cert is invalid because system clock is out of sync')\n return false\n }\n\n if (cert.deviceLock && this.deviceFingerprint !== cert.deviceFingerprint) {\n debug('cert is invalid because device fingerprint does not match')\n return false\n }\n\n if (this.config.tenantId !== cert.tenantId) {\n debug('cert is invalid because tenant ID does not match')\n return false\n }\n\n const regex = new RegExp(cert.productIdentifierPattern)\n\n if (!regex.test(this.config.productIdentifier)) {\n debug('cert is invalid because product identifier does not match')\n return false\n }\n\n return true\n }\n\n hasFeatureEnabled(\n feature: string,\n requireValidCert: boolean = true\n ): boolean {\n return this.getFeatureValue(feature, requireValidCert) ? true : false\n }\n\n hasFeatureDefined(\n feature: string,\n requireValidCert: boolean = true\n ): boolean {\n return this.getFeatureValue(feature, requireValidCert) !== undefined\n ? true\n : false\n }\n\n hasQuotaLeft(quotaFeatureName: string, currentConsumption: number): boolean {\n const quota = this.getFeatureValue(quotaFeatureName)\n\n if (quota === undefined) {\n return false\n }\n\n if (typeof quota !== 'number') {\n throw new Error(\n `${quotaFeatureName} cannot be used as quota as it is not numeric`\n )\n }\n\n // -1 means unlimited quota!\n if (quota === -1) {\n return true\n }\n\n return Math.ceil(currentConsumption) < Math.ceil(quota)\n }\n\n getFeatureValue(\n feature: string,\n requireValidCert: boolean = true\n ): undefined | boolean | number | string {\n if (!this.isInitialized()) {\n return undefined\n }\n\n if (requireValidCert && !this.isValid()) {\n return undefined\n }\n\n const currentlyValidFeatures = this.getFeatures()\n\n if (!currentlyValidFeatures.hasOwnProperty(feature)) {\n return undefined\n }\n\n return currentlyValidFeatures[feature]\n }\n\n getFeatures() {\n if (!this.isInitialized()) {\n return {}\n }\n\n const now = new Date().getTime()\n const created = this.licenseCert!.createdAt.getTime()\n\n const firstCurrentlyValidFeatureSet = this.licenseCert!.featureSets.find(\n (fs) =>\n fs.validity === 0 ||\n created + (fs.validity as number) * 1000 * 60 >= now\n )\n\n if (!firstCurrentlyValidFeatureSet) {\n return {}\n }\n\n return firstCurrentlyValidFeatureSet.features\n }\n\n getProductMetadata() {\n if (!this.isInitialized()) {\n return {}\n }\n\n return this.licenseCert!.productMetadata\n }\n\n isRenewalDue(): boolean {\n if (!this.isInitialized()) {\n return false\n }\n\n const now = new Date().getTime()\n const expiry = this.licenseCert!.expiresAt.getTime()\n const termination = this.licenseCert!.terminatesAt.getTime()\n\n //returns TRUE when current time is close enough to expiry and not after termination\n return (\n now > expiry - this.config.autoRenewOffset! * 1000 && now < termination\n )\n }\n\n toString() {\n return (\n `certId: ${this.licenseCert?.id ?? '<n/a>'}\\n` +\n `tenantId: ${this.config.tenantId ?? '<n/a>'}\\n` +\n `productIdentifier: ${this.config.productIdentifier ?? '<n/a>'}\\n` +\n `deviceFingerprint: ${this.deviceFingerprint}\\n` +\n `createdAt: ${this.licenseCert?.createdAt ?? '<n/a>'}\\n` +\n `issuedAt: ${this.licenseCert?.issuedAt ?? '<n/a>'}\\n` +\n `expiresAt: ${this.licenseCert?.expiresAt ?? '<n/a>'}\\n` +\n `terminatesAt: ${this.licenseCert?.terminatesAt ?? '<n/a>'}\\n` +\n `isValid: ${this.isValid(false)}\\n` +\n `isRenewalDue: ${this.isRenewalDue()}\\n` +\n `featureSets: ${\n this.licenseCert?.featureSets\n ? JSON.stringify(this.licenseCert?.featureSets)\n : '<n/a>'\n }\\n`\n )\n }\n\n private async renewalCron({ force }: { force: boolean }) {\n if (force || this.isRenewalDue()) {\n this.logger.info('attempting license renewal')\n try {\n await this.renew()\n } catch (e) {}\n }\n }\n\n private async initCert() {\n try {\n const containerStr = await this.config.loadCertStr()\n if (!containerStr || containerStr.length < 50) {\n throw new Error('cert length is too short')\n }\n const { x509, licenseKey } =\n this.parseLicenseCertContainerStr(containerStr)\n this.x509Cert = new X509Certificate(x509)\n const hasApprovedIssuer = this.x509Cert.checkIssued(this.getIssuerCert())\n if (!hasApprovedIssuer) {\n throw new Error('cert was not issued by an approved issuer')\n }\n const publicKey = this.x509Cert.publicKey.export({\n format: 'pem',\n type: 'pkcs1',\n })\n this.key = new NodeRSA(publicKey)\n this.licenseCert = this.parseLicenseKeyStr(licenseKey)\n } catch (e) {\n this.logger.error(\n `cert could not be initialized. ${e instanceof Error ? e.message : ''}`\n )\n }\n }\n\n private stringifyCertContainer(container: TLicenseContainer): string {\n const containerStr = JSON.stringify(container)\n return Buffer.from(containerStr).toString('base64')\n }\n\n private parseLicenseCertContainerStr(\n strigifiedContainer: string\n ): TLicenseContainer {\n const containerStr = Buffer.from(strigifiedContainer, 'base64').toString(\n 'ascii'\n )\n const container = JSON.parse(containerStr)\n if (\n !container.hasOwnProperty('licenseKey') ||\n !container.hasOwnProperty('x509')\n ) {\n throw new Error('license cert container could not be parsed')\n }\n\n return container as TLicenseContainer\n }\n\n private parseLicenseKeyStr(cert: string): TLicenseCertObj {\n const certPayload = this.validateLicenseKey(cert)\n return {\n id: certPayload.id,\n version: certPayload.version,\n tenantId: certPayload.tenantId,\n renewalToken: certPayload.renewalToken,\n deviceLock: certPayload.deviceLock,\n deviceFingerprint: certPayload.deviceFingerprint,\n productIdentifierPattern: certPayload.productIdentifierPattern,\n createdAt: new Date(certPayload.createdAt),\n issuedAt: new Date(certPayload.issuedAt),\n expiresAt: new Date(certPayload.expiresAt),\n terminatesAt: new Date(certPayload.terminatesAt),\n featureSets: certPayload.featureSets as TFeatureSet[],\n productMetadata: certPayload.productMetadata,\n }\n }\n\n private validateLicenseKey(licenseKey: string) {\n //remove all line breaks\n licenseKey = licenseKey.replace(/(\\r\\n|\\n|\\r)/gm, '')\n\n //extract parts\n const match = licenseKey.match(\n /^-----BEGIN LICENSE KEY-----(?<encryptedSymmetricKey>.+\\|\\|)(?<encryptedData>.+)\\|\\|(?<signature>.+)-----END LICENSE KEY-----$/\n )\n\n if (!match) {\n throw new Error('license key could not be parsed')\n }\n\n const encryptedSymmetricKey = match.groups!.encryptedSymmetricKey\n const payload = match.groups!.encryptedData\n const signature = match.groups!.signature\n\n let symmetricKey, decryptedData\n\n //decrypt the random symmetric key\n try {\n symmetricKey = this.key!.decryptPublic(encryptedSymmetricKey, 'utf8')\n } catch (e) {\n throw new Error('Invalid data: Could not extract symmetric key')\n }\n\n //decrypt the payload\n try {\n decryptedData = CryptoJS.AES.decrypt(payload, symmetricKey).toString(\n CryptoJS.enc.Utf8\n )\n } catch (e) {\n throw new Error('Invalid Data: Could not decrypt data with key found')\n }\n\n //verify the signature.\n if (\n this.key!.verify(Buffer.from(decryptedData), signature, 'utf8', 'base64')\n ) {\n //return the decryped data.\n return JSON.parse(decryptedData)\n } else {\n throw new Error('License Key signature invalid')\n }\n }\n\n public getIssuerCert() {\n return this.x509IssuerCert\n }\n}\n"],"mappings":"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","names":["LicenseManager_exports","__export","LicenseManager","__toCommonJS","import_axios","import_node_rsa","import_crypto_js","import_node_machine_id","import_node_crypto","config","reservationId","response","axios","status","containerStr","e","_status","now","useLogger","logger","debug","msg","cert","feature","requireValidCert","quotaFeatureName","currentConsumption","quota","currentlyValidFeatures","created","firstCurrentlyValidFeatureSet","fs","expiry","termination","force","x509","licenseKey","publicKey","NodeRSA","container","strigifiedContainer","certPayload","match","encryptedSymmetricKey","payload","signature","symmetricKey","decryptedData","CryptoJS"]}
1
+ {"version":3,"sources":["../src/LicenseManager.ts"],"sourcesContent":["import axios from 'axios'\nimport NodeRSA from 'node-rsa'\nimport CryptoJS from 'crypto-js'\nimport { machineId } from 'node-machine-id'\nimport { X509Certificate } from 'node:crypto'\n\nexport type TLicenseManagerConfig = {\n server?: string\n tenantId: number\n productIdentifier: string\n autoRenewEnabled?: boolean\n autoRenewOffset?: number\n loadCertStr: () => Promise<TLicenseContainerStr>\n saveCertStr: (cert: TLicenseContainerStr) => Promise<void>\n deviceFingerprint?: () => string | Promise<string>\n onFeatureChange?: () => any\n logger?: TLogger\n}\n\nexport type TLicenseContainerStr = string\n\nexport type TLicenseContainer = {\n licenseKey: string\n x509: string\n}\n\nexport type TFeatures = { [key: string]: boolean | number | string }\n\nexport type TMetadata = {\n [key: string]: boolean | number | string | Array<any> | {}\n}\n\nexport type TFeatureSet = {\n validity: number | string // either number in minutes or duration (e.g. \"P14D\") as string\n features: TFeatures\n}\n\nexport type TLicenseCertObj = {\n id: string\n version: number\n tenantId: number\n renewalToken: string\n deviceLock: boolean\n deviceFingerprint: string\n productIdentifierPattern: string\n createdAt: Date\n issuedAt: Date\n expiresAt: Date\n terminatesAt: Date\n featureSets: TFeatureSet[]\n productMetadata: {}\n managementJwt: string\n}\n\nexport type TLogger = {\n error: Function\n warn: Function\n info: Function\n debug: Function\n}\n\nconst enum LogLevel {\n ERROR = 'error',\n WARN = 'warn',\n INFO = 'info',\n DEBUG = 'debug',\n}\n\nexport class LicenseManager {\n public config: TLicenseManagerConfig\n\n private key?: NodeRSA\n private logger: TLogger\n private licenseCert?: TLicenseCertObj\n private x509Cert?: X509Certificate\n private x509IssuerCert: X509Certificate\n private deviceFingerprint?: string\n private renewalIntervalPointer?: NodeJS.Timer\n private checkUpcomingFeatureChangesCron?: NodeJS.Timer\n private featureChangeTimeoutPointer?: NodeJS.Timer\n\n constructor(config: TLicenseManagerConfig) {\n this.config = config\n\n if (this.config.logger) {\n this.logger = this.config.logger\n } else {\n this.logger = {\n error() {\n console.log('ERROR:', ...arguments)\n },\n warn() {\n console.log('WARN:', ...arguments)\n },\n info() {\n console.log('INFO:', ...arguments)\n },\n debug() {\n console.log('DEBUG:', ...arguments)\n },\n }\n }\n\n this.x509IssuerCert = new X509Certificate(\n '-----BEGIN CERTIFICATE-----\\n' +\n 'MIIFDDCCAvQCCQCWGBewlWbp0DANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJE\\n' +\n 'RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xFzAVBgNVBAMMDmxp\\n' +\n 'Y2Vuc2UubjhuLmlvMB4XDTIyMDYyNDA0MDkzM1oXDTQ5MTEwOTA0MDkzM1owSDEL\\n' +\n 'MAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVybGluMRcw\\n' +\n 'FQYDVQQDDA5saWNlbnNlLm44bi5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC\\n' +\n 'AgoCggIBANK6Uj5CSyPaa2rf/bwH/AqzzINeWg4n94pECv4p8tsjy0+ZscodNn7Q\\n' +\n 'IvYW/6IUpax8fZvHCSqu0L7fsgLkw0+HDLlsln+ryI/3h1ElVZm67BfqOvhSfPj+\\n' +\n 'btxcP8EtS+6hbf74sqPEBFD0wikKhIPGdtBolp7rLXfTGs+5eMqSA5q4W1V+HUUU\\n' +\n 'zgaCdchzlHGTdIICNpbRozGeFTIIx1MPzMie+4zIs6i680efx2KJVZWsa2WuCSED\\n' +\n '+b0gSRTgoKQ3B7JjxJKfzHdOdM6JxhkCjrJIkJCrZL7wFypn+wMHsVFrsw/80WkS\\n' +\n 'dwBj/RqCPzKcRwnxs0WNLhkyT/XCMS/1pNzPymdFADu2tEZjhFsa5ziIhdoQz8po\\n' +\n 'Efheyg3mOZDWyu6oyHCLH9lUlsNjV9zZ6RICgvHZvHPmPqOLPomy4Qymq2osuH+S\\n' +\n '28rwEy0W3DCEfuS3dZHrSQfohGC9EAyyFAIPSGhTJSYJl0oNBZjpRM+jAm9ER7PM\\n' +\n 'K70/7g6z8uIgKa8/SD/Pezd/aWzxH/tOokAF5X5o5TzSOwVzqOJzY06EZC7CJnhs\\n' +\n 'sigAJTy1trZJBcZuWnKY5FqrK3QzjsQ9sWM0tRocfNOYmD21mubNo+RmMMo3kvYL\\n' +\n 'JoBfap/cuP6kx3OiRzBJ4luTEa6nRIYy+EjcPaN3+9L5iEZ9/NABAgMBAAEwDQYJ\\n' +\n 'KoZIhvcNAQELBQADggIBAIUpJ0Rh6C92cJqy6iehS8c77r1prj62gr6Acdy5QGh8\\n' +\n 'ax30ANDbPtkezVIIBk+0JjLkMxr3mwqCRsPgMshPcxhZwEafmZrWPPGRVsOfukB3\\n' +\n 'Gp10cIv1YmZ7AFY4i/izj5184+A+GjxrJBULQG1JfX4c7KW06Kaps85AaX/Tp0fl\\n' +\n '/hZ6oUe48aSSTuAW38hWZ5jCpBqfFyQ15ablJZt0fB8NkXEdFUcUEt/OHJfqF5fP\\n' +\n 'Nt5PWC1AuBxzSbzjwabOy/M4r8m5CzCeXSIjqbcsAq52myMoxvNrjKRtucQ7CjqK\\n' +\n 'LR6WdhMf+NLvyTI+evXMoXpDzlevkCpz17uDiDt9XrmvLSf3Ff8mdTRwzVmOmHfc\\n' +\n 'Ruz5v7WBR4cpBR/sC+WxOw9heLMHgYhPyRUM4voo55EcJGusXr/iavblBAnI0GUw\\n' +\n 'uMNs3MjEmfbaBV1K0GKG5UToF9UmUxxVmTcRUZrAQX+yBkRezDTpOQuRnB58BDQP\\n' +\n 'A62lcgZlikzJw3lHue33qAudyUrUmjfHGll7GFQNeLO42jPMeM4NJiNIrBZ7j0uD\\n' +\n '4slHdDi/44PHcKchvde/5k7ZJMi6OC1Vu+bOnKvzhnWQIOkHFQ55m13oslV2ozZT\\n' +\n '/oqhn/8/LeV0ooZuYnBeRkRTveniUeho2OFe5xZvWSSfuBrbHt9+zBg+5MWPUTIJ\\n' +\n '-----END CERTIFICATE-----'\n )\n\n //set defaults for not set config properties:\n this.config.autoRenewEnabled = this.config.autoRenewEnabled ?? true\n this.config.autoRenewOffset = this.config.autoRenewOffset ?? 60 * 60 * 72 // default: 72 hours\n this.config.server = this.config.server ?? 'https://license.n8n.io/v1'\n }\n\n log(msg: string, logLevel: LogLevel) {\n this.logger[logLevel](`[license] ${msg}`)\n }\n\n async initialize() {\n if (this.isInitialized()) {\n return\n }\n\n this.deviceFingerprint = await this.computeDeviceFingerprint()\n this.log(\n `initializing for deviceFingerprint ${this.deviceFingerprint}`,\n LogLevel.INFO\n )\n await this.initCert()\n\n if (this.config.onFeatureChange) {\n //set up periodic timer to assess new featureSets turning live\n this.checkUpcomingFeatureChangesCron = setInterval(\n () => this.setTimerForNextFeatureChange(),\n 1000 * 60 * 15 //15 minutes\n )\n }\n\n if (this.config.autoRenewEnabled) {\n //invoke renewal immediately once:\n await this.renewalCron({ force: true })\n\n //and periodically:\n this.renewalIntervalPointer = setInterval(\n () => this.renewalCron({ force: false }),\n 1000 * 60 * 15 //15 minutes\n )\n }\n }\n\n reset() {\n if (this.config.autoRenewEnabled) {\n clearInterval(this.renewalIntervalPointer)\n }\n if (this.checkUpcomingFeatureChangesCron) {\n clearInterval(this.checkUpcomingFeatureChangesCron)\n }\n if (this.featureChangeTimeoutPointer) {\n clearTimeout(this.featureChangeTimeoutPointer)\n }\n this.licenseCert = undefined\n this.deviceFingerprint = undefined\n }\n\n async computeDeviceFingerprint() {\n if (\n this.config.deviceFingerprint &&\n typeof this.config.deviceFingerprint === 'function'\n ) {\n return await this.config.deviceFingerprint()\n }\n return await machineId()\n }\n\n async activate(reservationId: string) {\n const response = await axios.post(\n `${this.config.server!}/activate`,\n {\n reservationId,\n tenantId: this.config.tenantId,\n productIdentifier: this.config.productIdentifier,\n deviceFingerprint: this.deviceFingerprint,\n },\n {\n validateStatus: (status) => true, //axios should never throw\n timeout: 10000,\n }\n )\n\n if (response.status == 200) {\n if (\n !response.data.hasOwnProperty('licenseKey') ||\n !response.data.hasOwnProperty('x509')\n ) {\n throw new Error('unexpected server response')\n }\n const containerStr = this.stringifyCertContainer(\n response.data as TLicenseContainer\n )\n await this.config.saveCertStr(containerStr)\n await this.initCert()\n } else {\n const e = new Error(\n `license activation failed: ${\n response.data.message ?? 'unknown reason'\n }`\n )\n this.log(e.message, LogLevel.WARN)\n throw e\n }\n }\n\n async renew() {\n if (!this.isInitialized()) {\n throw new Error('renewal failed because current cert is not initialized')\n }\n\n if (this.isTerminated()) {\n throw new Error('renewal failed because current cert was terminated')\n }\n\n const response = await axios.post(\n `${this.config.server!}/renew`,\n {\n certId: this.licenseCert!.id,\n tenantId: this.config.tenantId,\n productIdentifier: this.config.productIdentifier,\n deviceFingerprint: this.deviceFingerprint,\n renewalToken: this.licenseCert!.renewalToken,\n },\n {\n validateStatus: (_status) => true, //axios should never throw\n timeout: 10000,\n }\n )\n\n if (response.status == 200) {\n if (\n !response.data.hasOwnProperty('licenseKey') ||\n !response.data.hasOwnProperty('x509')\n ) {\n throw new Error('unexpected server response')\n }\n const containerStr = this.stringifyCertContainer(\n response.data as TLicenseContainer\n )\n await this.config.saveCertStr(containerStr)\n this.log('license successfully renewed', LogLevel.INFO)\n await this.initCert()\n } else {\n const e = new Error(\n `license renewal failed: ${response.data.message ?? 'unknown reason'}`\n )\n this.log(e.message, LogLevel.WARN)\n throw e\n }\n }\n\n private isInitialized() {\n return this.licenseCert !== undefined\n }\n\n isTerminated(): boolean {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n const now = new Date()\n\n return this.licenseCert!.terminatesAt < now\n }\n\n getExpiryDate(): Date {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n return this.licenseCert!.expiresAt\n }\n\n getTerminationDate(): Date {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n return this.licenseCert!.terminatesAt\n }\n\n isValid(useLogger = true): boolean {\n const debug = (msg: string) => {\n if (useLogger) {\n this.log(msg, LogLevel.DEBUG)\n }\n }\n\n if (!this.isInitialized()) {\n debug('cert is invalid because it is undefined')\n return false\n }\n\n const cert = this.licenseCert as TLicenseCertObj\n const now = new Date()\n\n if (cert.expiresAt < now) {\n debug('cert is invalid because it has expired')\n return false\n }\n\n if (cert.terminatesAt < now) {\n debug('cert is invalid because it was terminated')\n return false\n }\n\n //allow clocks to be out of sync by no more than 300,000 ms / = 5 minutes\n if (cert.createdAt.getTime() - 300000 > now.getTime()) {\n debug('cert is invalid because system clock is out of sync')\n return false\n }\n\n if (cert.deviceLock && this.deviceFingerprint !== cert.deviceFingerprint) {\n debug('cert is invalid because device fingerprint does not match')\n return false\n }\n\n if (this.config.tenantId !== cert.tenantId) {\n debug('cert is invalid because tenant ID does not match')\n return false\n }\n\n const regex = new RegExp(cert.productIdentifierPattern)\n\n if (!regex.test(this.config.productIdentifier)) {\n debug('cert is invalid because product identifier does not match')\n return false\n }\n\n return true\n }\n\n hasFeatureEnabled(\n feature: string,\n requireValidCert: boolean = true\n ): boolean {\n return this.getFeatureValue(feature, requireValidCert) ? true : false\n }\n\n hasFeatureDefined(\n feature: string,\n requireValidCert: boolean = true\n ): boolean {\n return this.getFeatureValue(feature, requireValidCert) !== undefined\n ? true\n : false\n }\n\n hasQuotaLeft(quotaFeatureName: string, currentConsumption: number): boolean {\n const quota = this.getFeatureValue(quotaFeatureName)\n\n if (quota === undefined) {\n return false\n }\n\n if (typeof quota !== 'number') {\n throw new Error(\n `${quotaFeatureName} cannot be used as quota as it is not numeric`\n )\n }\n\n // -1 means unlimited quota!\n if (quota === -1) {\n return true\n }\n\n return Math.ceil(currentConsumption) < Math.ceil(quota)\n }\n\n getFeatureValue(\n feature: string,\n requireValidCert: boolean = true\n ): undefined | boolean | number | string {\n if (!this.isInitialized()) {\n return undefined\n }\n\n if (requireValidCert && !this.isValid()) {\n return undefined\n }\n\n const currentlyValidFeatures = this.getFeatures()\n\n if (!currentlyValidFeatures.hasOwnProperty(feature)) {\n return undefined\n }\n\n return currentlyValidFeatures[feature]\n }\n\n getFeatures() {\n if (!this.isInitialized()) {\n return {}\n }\n\n const now = new Date().getTime()\n const created = this.licenseCert!.createdAt.getTime()\n\n const firstCurrentlyValidFeatureSet = this.licenseCert!.featureSets.find(\n (fs) =>\n fs.validity === 0 ||\n created + (fs.validity as number) * 1000 * 60 >= now\n )\n\n if (!firstCurrentlyValidFeatureSet) {\n return {}\n }\n\n return firstCurrentlyValidFeatureSet.features\n }\n\n getProductMetadata() {\n if (!this.isInitialized()) {\n return {}\n }\n\n return this.licenseCert!.productMetadata\n }\n\n getManagementJwt() {\n if (!this.isInitialized()) {\n return ''\n }\n\n return this.licenseCert!.managementJwt\n }\n\n isRenewalDue(): boolean {\n if (!this.isInitialized()) {\n return false\n }\n\n const now = new Date().getTime()\n const expiry = this.licenseCert!.expiresAt.getTime()\n const termination = this.licenseCert!.terminatesAt.getTime()\n\n //returns TRUE when current time is close enough to expiry and not after termination\n return (\n now > expiry - this.config.autoRenewOffset! * 1000 && now < termination\n )\n }\n\n toString() {\n return (\n `certId: ${this.licenseCert?.id ?? '<n/a>'}\\n` +\n `tenantId: ${this.config.tenantId ?? '<n/a>'}\\n` +\n `productIdentifier: ${this.config.productIdentifier ?? '<n/a>'}\\n` +\n `deviceFingerprint: ${this.deviceFingerprint}\\n` +\n `createdAt: ${this.licenseCert?.createdAt ?? '<n/a>'}\\n` +\n `issuedAt: ${this.licenseCert?.issuedAt ?? '<n/a>'}\\n` +\n `expiresAt: ${this.licenseCert?.expiresAt ?? '<n/a>'}\\n` +\n `terminatesAt: ${this.licenseCert?.terminatesAt ?? '<n/a>'}\\n` +\n `isValid: ${this.isValid(false)}\\n` +\n `isRenewalDue: ${this.isRenewalDue()}\\n` +\n `featureSets: ${\n this.licenseCert?.featureSets\n ? JSON.stringify(this.licenseCert?.featureSets)\n : '<n/a>'\n }\\n`\n )\n }\n\n private triggerOnFeatureChangeCallback() {\n if (this.config.onFeatureChange) {\n this.config.onFeatureChange()\n }\n }\n\n private setTimerForNextFeatureChange() {\n if (!this.isInitialized() || !this.config.onFeatureChange) {\n return\n }\n\n const now = new Date().getTime()\n const certCreatedAt = this.licenseCert!.createdAt.getTime()\n\n const nextFeatureSet = this.licenseCert!.featureSets.find(\n (fs) => certCreatedAt + (fs.validity as number) * 1000 * 60 > now\n )\n\n let upcomingEvents = []\n\n if (nextFeatureSet) {\n upcomingEvents.push(\n certCreatedAt + (nextFeatureSet.validity as number) * 1000 * 60 - now\n )\n }\n\n upcomingEvents.push(this.licenseCert!.expiresAt.getTime() - now)\n upcomingEvents.push(this.licenseCert!.terminatesAt.getTime() - now)\n\n upcomingEvents = upcomingEvents\n .filter((timeTillEventInMs) => timeTillEventInMs >= 0)\n .sort((a, b) => a - b)\n\n const timeTillNextEventInMs = upcomingEvents[0]\n\n if (timeTillNextEventInMs < 15 * 60 * 1000) {\n // 15*60*1000 == 15 minutes\n clearTimeout(this.featureChangeTimeoutPointer)\n this.featureChangeTimeoutPointer = setTimeout(() => {\n this.triggerOnFeatureChangeCallback()\n this.setTimerForNextFeatureChange()\n }, timeTillNextEventInMs + 1000)\n }\n }\n\n private async renewalCron({ force }: { force: boolean }) {\n if (force || this.isRenewalDue()) {\n this.log('attempting license renewal', LogLevel.INFO)\n try {\n await this.renew()\n } catch (e) {}\n }\n }\n\n private async initCert() {\n try {\n const containerStr = await this.config.loadCertStr()\n if (!containerStr || containerStr.length < 50) {\n throw new Error('cert string is undefined or too short')\n }\n const { x509, licenseKey } =\n this.parseLicenseCertContainerStr(containerStr)\n this.x509Cert = new X509Certificate(x509)\n const hasApprovedIssuer = this.x509Cert.checkIssued(this.getIssuerCert())\n if (!hasApprovedIssuer) {\n throw new Error('cert was not issued by an approved issuer')\n }\n const publicKey = this.x509Cert.publicKey.export({\n format: 'pem',\n type: 'pkcs1',\n })\n this.key = new NodeRSA(publicKey)\n this.licenseCert = this.parseLicenseKeyStr(licenseKey)\n this.triggerOnFeatureChangeCallback()\n this.setTimerForNextFeatureChange()\n } catch (e) {\n this.log(\n `cert could not be initialized. ${e instanceof Error ? e.message : ''}`,\n LogLevel.ERROR\n )\n }\n }\n\n private stringifyCertContainer(container: TLicenseContainer): string {\n const containerStr = JSON.stringify(container)\n return Buffer.from(containerStr).toString('base64')\n }\n\n private parseLicenseCertContainerStr(\n strigifiedContainer: string\n ): TLicenseContainer {\n const containerStr = Buffer.from(strigifiedContainer, 'base64').toString(\n 'ascii'\n )\n const container = JSON.parse(containerStr)\n if (\n !container.hasOwnProperty('licenseKey') ||\n !container.hasOwnProperty('x509')\n ) {\n throw new Error('license cert container could not be parsed')\n }\n\n return container as TLicenseContainer\n }\n\n private parseLicenseKeyStr(certStr: string): TLicenseCertObj {\n const certPayload = this.validateLicenseKey(certStr)\n\n const cert = { ...certPayload } as TLicenseCertObj\n\n // turn timestamp strings into Date objects\n cert.createdAt = new Date(certPayload.createdAt)\n cert.issuedAt = new Date(certPayload.issuedAt)\n cert.expiresAt = new Date(certPayload.expiresAt)\n cert.terminatesAt = new Date(certPayload.terminatesAt)\n\n return cert\n }\n\n private validateLicenseKey(licenseKey: string) {\n //remove all line breaks\n licenseKey = licenseKey.replace(/(\\r\\n|\\n|\\r)/gm, '')\n\n //extract parts\n const match = licenseKey.match(\n /^-----BEGIN LICENSE KEY-----(?<encryptedSymmetricKey>.+\\|\\|)(?<encryptedData>.+)\\|\\|(?<signature>.+)-----END LICENSE KEY-----$/\n )\n\n if (!match) {\n throw new Error('license key could not be parsed')\n }\n\n const encryptedSymmetricKey = match.groups!.encryptedSymmetricKey\n const payload = match.groups!.encryptedData\n const signature = match.groups!.signature\n\n let symmetricKey, decryptedData\n\n //decrypt the random symmetric key\n try {\n symmetricKey = this.key!.decryptPublic(encryptedSymmetricKey, 'utf8')\n } catch (e) {\n throw new Error('Invalid data: Could not extract symmetric key')\n }\n\n //decrypt the payload\n try {\n decryptedData = CryptoJS.AES.decrypt(payload, symmetricKey).toString(\n CryptoJS.enc.Utf8\n )\n } catch (e) {\n throw new Error('Invalid Data: Could not decrypt data with key found')\n }\n\n //verify the signature.\n if (\n this.key!.verify(Buffer.from(decryptedData), signature, 'utf8', 'base64')\n ) {\n //return the decryped data.\n return JSON.parse(decryptedData)\n } else {\n throw new Error('License Key signature invalid')\n }\n }\n\n public getIssuerCert() {\n return this.x509IssuerCert\n }\n}\n"],"mappings":"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","names":["LicenseManager_exports","__export","LicenseManager","__toCommonJS","import_axios","import_node_rsa","import_crypto_js","import_node_machine_id","import_node_crypto","LicenseManager","config","msg","logLevel","reservationId","response","axios","status","containerStr","e","_status","now","useLogger","debug","cert","feature","requireValidCert","quotaFeatureName","currentConsumption","quota","currentlyValidFeatures","created","firstCurrentlyValidFeatureSet","fs","expiry","termination","certCreatedAt","nextFeatureSet","upcomingEvents","timeTillEventInMs","a","b","timeTillNextEventInMs","force","x509","licenseKey","publicKey","NodeRSA","container","strigifiedContainer","certStr","certPayload","match","encryptedSymmetricKey","payload","signature","symmetricKey","decryptedData","CryptoJS"]}
@@ -1,4 +1,4 @@
1
- import o from"axios";import g from"node-rsa";import c from"crypto-js";import{machineId as f}from"node-machine-id";import{X509Certificate as u}from"crypto";var d=class{constructor(t){this.config=t,this.config.logger?this.logger=this.config.logger:this.logger={error(){console.log("ERROR:",...arguments)},warn(){console.log("WARN:",...arguments)},info(){console.log("INFO:",...arguments)},debug(){console.log("DEBUG:",...arguments)}},this.x509IssuerCert=new u(`-----BEGIN CERTIFICATE-----
1
+ import o from"axios";import h from"node-rsa";import c from"crypto-js";import{machineId as d}from"node-machine-id";import{X509Certificate as u}from"crypto";var g=class{constructor(e){this.config=e,this.config.logger?this.logger=this.config.logger:this.logger={error(){console.log("ERROR:",...arguments)},warn(){console.log("WARN:",...arguments)},info(){console.log("INFO:",...arguments)},debug(){console.log("DEBUG:",...arguments)}},this.x509IssuerCert=new u(`-----BEGIN CERTIFICATE-----
2
2
  MIIFDDCCAvQCCQCWGBewlWbp0DANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJE
3
3
  RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xFzAVBgNVBAMMDmxp
4
4
  Y2Vuc2UubjhuLmlvMB4XDTIyMDYyNDA0MDkzM1oXDTQ5MTEwOTA0MDkzM1owSDEL
@@ -26,7 +26,7 @@ uMNs3MjEmfbaBV1K0GKG5UToF9UmUxxVmTcRUZrAQX+yBkRezDTpOQuRnB58BDQP
26
26
  A62lcgZlikzJw3lHue33qAudyUrUmjfHGll7GFQNeLO42jPMeM4NJiNIrBZ7j0uD
27
27
  4slHdDi/44PHcKchvde/5k7ZJMi6OC1Vu+bOnKvzhnWQIOkHFQ55m13oslV2ozZT
28
28
  /oqhn/8/LeV0ooZuYnBeRkRTveniUeho2OFe5xZvWSSfuBrbHt9+zBg+5MWPUTIJ
29
- -----END CERTIFICATE-----`),this.config.autoRenewEnabled=this.config.autoRenewEnabled??!0,this.config.autoRenewOffset=this.config.autoRenewOffset??60*60*72,this.config.server=this.config.server??"https://license.n8n.io/v1"}async initialize(){this.deviceFingerprint=await this.computeDeviceFingerprint(),this.logger.info(`initializing for deviceFingerprint ${this.deviceFingerprint}`),await this.initCert(),this.config.autoRenewEnabled&&(await this.renewalCron({force:!0}),this.renewalIntervalPointer=setInterval(()=>this.renewalCron({force:!1}),1e3*60*15))}reset(){this.config.autoRenewEnabled&&clearInterval(this.renewalIntervalPointer),this.licenseCert=void 0,this.deviceFingerprint=void 0}async computeDeviceFingerprint(){return this.config.deviceFingerprint&&typeof this.config.deviceFingerprint=="function"?await this.config.deviceFingerprint():await f()}async activate(t){let e=await o.post(`${this.config.server}/activate`,{reservationId:t,tenantId:this.config.tenantId,productIdentifier:this.config.productIdentifier,deviceFingerprint:this.deviceFingerprint},{validateStatus:i=>!0,timeout:1e4});if(e.status==200){if(!e.data.hasOwnProperty("licenseKey")||!e.data.hasOwnProperty("x509"))throw new Error("unexpected server response");let i=this.stringifyCertContainer(e.data);await this.config.saveCertStr(i),await this.initCert()}else{let i=new Error(`license activation failed: ${e.data.message??"unknown reason"}`);throw this.logger.warn(i.message),i}}async renew(){if(!this.isInitialized())throw new Error("renewal failed because current cert is not initialized");if(this.isTerminated())throw new Error("renewal failed because current cert was terminated");let t=await o.post(`${this.config.server}/renew`,{certId:this.licenseCert.id,tenantId:this.config.tenantId,productIdentifier:this.config.productIdentifier,deviceFingerprint:this.deviceFingerprint,renewalToken:this.licenseCert.renewalToken},{validateStatus:e=>!0,timeout:1e4});if(t.status==200){if(!t.data.hasOwnProperty("licenseKey")||!t.data.hasOwnProperty("x509"))throw new Error("unexpected server response");let e=this.stringifyCertContainer(t.data);await this.config.saveCertStr(e),this.logger.info("license successfully renewed"),await this.initCert()}else{let e=new Error(`license renewal failed: ${t.data.message??"unknown reason"}`);throw this.logger.warn(e.message),e}}isInitialized(){return this.licenseCert!==void 0}isTerminated(){if(!this.isInitialized())throw new Error("Cert is not initialized");let t=new Date;return this.licenseCert.terminatesAt<t}getExpiryDate(){if(!this.isInitialized())throw new Error("Cert is not initialized");return this.licenseCert.expiresAt}getTerminationDate(){if(!this.isInitialized())throw new Error("Cert is not initialized");return this.licenseCert.terminatesAt}isValid(t=!0){let e=this.logger,i=s=>{t&&e.debug(s)};if(!this.isInitialized())return i("cert is invalid because it is undefined"),!1;let r=this.licenseCert,n=new Date;return r.expiresAt<n?(i("cert is invalid because it has expired"),!1):r.terminatesAt<n?(i("cert is invalid because it was terminated"),!1):r.createdAt.getTime()-3e5>n.getTime()?(i("cert is invalid because system clock is out of sync"),!1):r.deviceLock&&this.deviceFingerprint!==r.deviceFingerprint?(i("cert is invalid because device fingerprint does not match"),!1):this.config.tenantId!==r.tenantId?(i("cert is invalid because tenant ID does not match"),!1):new RegExp(r.productIdentifierPattern).test(this.config.productIdentifier)?!0:(i("cert is invalid because product identifier does not match"),!1)}hasFeatureEnabled(t,e=!0){return!!this.getFeatureValue(t,e)}hasFeatureDefined(t,e=!0){return this.getFeatureValue(t,e)!==void 0}hasQuotaLeft(t,e){let i=this.getFeatureValue(t);if(i===void 0)return!1;if(typeof i!="number")throw new Error(`${t} cannot be used as quota as it is not numeric`);return i===-1?!0:Math.ceil(e)<Math.ceil(i)}getFeatureValue(t,e=!0){if(!this.isInitialized()||e&&!this.isValid())return;let i=this.getFeatures();if(!!i.hasOwnProperty(t))return i[t]}getFeatures(){if(!this.isInitialized())return{};let t=new Date().getTime(),e=this.licenseCert.createdAt.getTime(),i=this.licenseCert.featureSets.find(r=>r.validity===0||e+r.validity*1e3*60>=t);return i?i.features:{}}getProductMetadata(){return this.isInitialized()?this.licenseCert.productMetadata:{}}isRenewalDue(){if(!this.isInitialized())return!1;let t=new Date().getTime(),e=this.licenseCert.expiresAt.getTime(),i=this.licenseCert.terminatesAt.getTime();return t>e-this.config.autoRenewOffset*1e3&&t<i}toString(){return`certId: ${this.licenseCert?.id??"<n/a>"}
29
+ -----END CERTIFICATE-----`),this.config.autoRenewEnabled=this.config.autoRenewEnabled??!0,this.config.autoRenewOffset=this.config.autoRenewOffset??60*60*72,this.config.server=this.config.server??"https://license.n8n.io/v1"}log(e,t){this.logger[t](`[license] ${e}`)}async initialize(){this.isInitialized()||(this.deviceFingerprint=await this.computeDeviceFingerprint(),this.log(`initializing for deviceFingerprint ${this.deviceFingerprint}`,"info"),await this.initCert(),this.config.onFeatureChange&&(this.checkUpcomingFeatureChangesCron=setInterval(()=>this.setTimerForNextFeatureChange(),1e3*60*15)),this.config.autoRenewEnabled&&(await this.renewalCron({force:!0}),this.renewalIntervalPointer=setInterval(()=>this.renewalCron({force:!1}),1e3*60*15)))}reset(){this.config.autoRenewEnabled&&clearInterval(this.renewalIntervalPointer),this.checkUpcomingFeatureChangesCron&&clearInterval(this.checkUpcomingFeatureChangesCron),this.featureChangeTimeoutPointer&&clearTimeout(this.featureChangeTimeoutPointer),this.licenseCert=void 0,this.deviceFingerprint=void 0}async computeDeviceFingerprint(){return this.config.deviceFingerprint&&typeof this.config.deviceFingerprint=="function"?await this.config.deviceFingerprint():await d()}async activate(e){let t=await o.post(`${this.config.server}/activate`,{reservationId:e,tenantId:this.config.tenantId,productIdentifier:this.config.productIdentifier,deviceFingerprint:this.deviceFingerprint},{validateStatus:i=>!0,timeout:1e4});if(t.status==200){if(!t.data.hasOwnProperty("licenseKey")||!t.data.hasOwnProperty("x509"))throw new Error("unexpected server response");let i=this.stringifyCertContainer(t.data);await this.config.saveCertStr(i),await this.initCert()}else{let i=new Error(`license activation failed: ${t.data.message??"unknown reason"}`);throw this.log(i.message,"warn"),i}}async renew(){if(!this.isInitialized())throw new Error("renewal failed because current cert is not initialized");if(this.isTerminated())throw new Error("renewal failed because current cert was terminated");let e=await o.post(`${this.config.server}/renew`,{certId:this.licenseCert.id,tenantId:this.config.tenantId,productIdentifier:this.config.productIdentifier,deviceFingerprint:this.deviceFingerprint,renewalToken:this.licenseCert.renewalToken},{validateStatus:t=>!0,timeout:1e4});if(e.status==200){if(!e.data.hasOwnProperty("licenseKey")||!e.data.hasOwnProperty("x509"))throw new Error("unexpected server response");let t=this.stringifyCertContainer(e.data);await this.config.saveCertStr(t),this.log("license successfully renewed","info"),await this.initCert()}else{let t=new Error(`license renewal failed: ${e.data.message??"unknown reason"}`);throw this.log(t.message,"warn"),t}}isInitialized(){return this.licenseCert!==void 0}isTerminated(){if(!this.isInitialized())throw new Error("Cert is not initialized");let e=new Date;return this.licenseCert.terminatesAt<e}getExpiryDate(){if(!this.isInitialized())throw new Error("Cert is not initialized");return this.licenseCert.expiresAt}getTerminationDate(){if(!this.isInitialized())throw new Error("Cert is not initialized");return this.licenseCert.terminatesAt}isValid(e=!0){let t=n=>{e&&this.log(n,"debug")};if(!this.isInitialized())return t("cert is invalid because it is undefined"),!1;let i=this.licenseCert,r=new Date;return i.expiresAt<r?(t("cert is invalid because it has expired"),!1):i.terminatesAt<r?(t("cert is invalid because it was terminated"),!1):i.createdAt.getTime()-3e5>r.getTime()?(t("cert is invalid because system clock is out of sync"),!1):i.deviceLock&&this.deviceFingerprint!==i.deviceFingerprint?(t("cert is invalid because device fingerprint does not match"),!1):this.config.tenantId!==i.tenantId?(t("cert is invalid because tenant ID does not match"),!1):new RegExp(i.productIdentifierPattern).test(this.config.productIdentifier)?!0:(t("cert is invalid because product identifier does not match"),!1)}hasFeatureEnabled(e,t=!0){return!!this.getFeatureValue(e,t)}hasFeatureDefined(e,t=!0){return this.getFeatureValue(e,t)!==void 0}hasQuotaLeft(e,t){let i=this.getFeatureValue(e);if(i===void 0)return!1;if(typeof i!="number")throw new Error(`${e} cannot be used as quota as it is not numeric`);return i===-1?!0:Math.ceil(t)<Math.ceil(i)}getFeatureValue(e,t=!0){if(!this.isInitialized()||t&&!this.isValid())return;let i=this.getFeatures();if(!!i.hasOwnProperty(e))return i[e]}getFeatures(){if(!this.isInitialized())return{};let e=new Date().getTime(),t=this.licenseCert.createdAt.getTime(),i=this.licenseCert.featureSets.find(r=>r.validity===0||t+r.validity*1e3*60>=e);return i?i.features:{}}getProductMetadata(){return this.isInitialized()?this.licenseCert.productMetadata:{}}getManagementJwt(){return this.isInitialized()?this.licenseCert.managementJwt:""}isRenewalDue(){if(!this.isInitialized())return!1;let e=new Date().getTime(),t=this.licenseCert.expiresAt.getTime(),i=this.licenseCert.terminatesAt.getTime();return e>t-this.config.autoRenewOffset*1e3&&e<i}toString(){return`certId: ${this.licenseCert?.id??"<n/a>"}
30
30
  tenantId: ${this.config.tenantId??"<n/a>"}
31
31
  productIdentifier: ${this.config.productIdentifier??"<n/a>"}
32
32
  deviceFingerprint: ${this.deviceFingerprint}
@@ -37,5 +37,5 @@ terminatesAt: ${this.licenseCert?.terminatesAt??"<n/a>"}
37
37
  isValid: ${this.isValid(!1)}
38
38
  isRenewalDue: ${this.isRenewalDue()}
39
39
  featureSets: ${this.licenseCert?.featureSets?JSON.stringify(this.licenseCert?.featureSets):"<n/a>"}
40
- `}async renewalCron({force:t}){if(t||this.isRenewalDue()){this.logger.info("attempting license renewal");try{await this.renew()}catch{}}}async initCert(){try{let t=await this.config.loadCertStr();if(!t||t.length<50)throw new Error("cert length is too short");let{x509:e,licenseKey:i}=this.parseLicenseCertContainerStr(t);if(this.x509Cert=new u(e),!this.x509Cert.checkIssued(this.getIssuerCert()))throw new Error("cert was not issued by an approved issuer");let n=this.x509Cert.publicKey.export({format:"pem",type:"pkcs1"});this.key=new g(n),this.licenseCert=this.parseLicenseKeyStr(i)}catch(t){this.logger.error(`cert could not be initialized. ${t instanceof Error?t.message:""}`)}}stringifyCertContainer(t){let e=JSON.stringify(t);return Buffer.from(e).toString("base64")}parseLicenseCertContainerStr(t){let e=Buffer.from(t,"base64").toString("ascii"),i=JSON.parse(e);if(!i.hasOwnProperty("licenseKey")||!i.hasOwnProperty("x509"))throw new Error("license cert container could not be parsed");return i}parseLicenseKeyStr(t){let e=this.validateLicenseKey(t);return{id:e.id,version:e.version,tenantId:e.tenantId,renewalToken:e.renewalToken,deviceLock:e.deviceLock,deviceFingerprint:e.deviceFingerprint,productIdentifierPattern:e.productIdentifierPattern,createdAt:new Date(e.createdAt),issuedAt:new Date(e.issuedAt),expiresAt:new Date(e.expiresAt),terminatesAt:new Date(e.terminatesAt),featureSets:e.featureSets,productMetadata:e.productMetadata}}validateLicenseKey(t){t=t.replace(/(\r\n|\n|\r)/gm,"");let e=t.match(/^-----BEGIN LICENSE KEY-----(?<encryptedSymmetricKey>.+\|\|)(?<encryptedData>.+)\|\|(?<signature>.+)-----END LICENSE KEY-----$/);if(!e)throw new Error("license key could not be parsed");let i=e.groups.encryptedSymmetricKey,r=e.groups.encryptedData,n=e.groups.signature,a,s;try{a=this.key.decryptPublic(i,"utf8")}catch{throw new Error("Invalid data: Could not extract symmetric key")}try{s=c.AES.decrypt(r,a).toString(c.enc.Utf8)}catch{throw new Error("Invalid Data: Could not decrypt data with key found")}if(this.key.verify(Buffer.from(s),n,"utf8","base64"))return JSON.parse(s);throw new Error("License Key signature invalid")}getIssuerCert(){return this.x509IssuerCert}};export{d as LicenseManager};
40
+ `}triggerOnFeatureChangeCallback(){this.config.onFeatureChange&&this.config.onFeatureChange()}setTimerForNextFeatureChange(){if(!this.isInitialized()||!this.config.onFeatureChange)return;let e=new Date().getTime(),t=this.licenseCert.createdAt.getTime(),i=this.licenseCert.featureSets.find(n=>t+n.validity*1e3*60>e),r=[];i&&r.push(t+i.validity*1e3*60-e),r.push(this.licenseCert.expiresAt.getTime()-e),r.push(this.licenseCert.terminatesAt.getTime()-e),r=r.filter(n=>n>=0).sort((n,a)=>n-a);let s=r[0];s<15*60*1e3&&(clearTimeout(this.featureChangeTimeoutPointer),this.featureChangeTimeoutPointer=setTimeout(()=>{this.triggerOnFeatureChangeCallback(),this.setTimerForNextFeatureChange()},s+1e3))}async renewalCron({force:e}){if(e||this.isRenewalDue()){this.log("attempting license renewal","info");try{await this.renew()}catch{}}}async initCert(){try{let e=await this.config.loadCertStr();if(!e||e.length<50)throw new Error("cert string is undefined or too short");let{x509:t,licenseKey:i}=this.parseLicenseCertContainerStr(e);if(this.x509Cert=new u(t),!this.x509Cert.checkIssued(this.getIssuerCert()))throw new Error("cert was not issued by an approved issuer");let s=this.x509Cert.publicKey.export({format:"pem",type:"pkcs1"});this.key=new h(s),this.licenseCert=this.parseLicenseKeyStr(i),this.triggerOnFeatureChangeCallback(),this.setTimerForNextFeatureChange()}catch(e){this.log(`cert could not be initialized. ${e instanceof Error?e.message:""}`,"error")}}stringifyCertContainer(e){let t=JSON.stringify(e);return Buffer.from(t).toString("base64")}parseLicenseCertContainerStr(e){let t=Buffer.from(e,"base64").toString("ascii"),i=JSON.parse(t);if(!i.hasOwnProperty("licenseKey")||!i.hasOwnProperty("x509"))throw new Error("license cert container could not be parsed");return i}parseLicenseKeyStr(e){let t=this.validateLicenseKey(e),i={...t};return i.createdAt=new Date(t.createdAt),i.issuedAt=new Date(t.issuedAt),i.expiresAt=new Date(t.expiresAt),i.terminatesAt=new Date(t.terminatesAt),i}validateLicenseKey(e){e=e.replace(/(\r\n|\n|\r)/gm,"");let t=e.match(/^-----BEGIN LICENSE KEY-----(?<encryptedSymmetricKey>.+\|\|)(?<encryptedData>.+)\|\|(?<signature>.+)-----END LICENSE KEY-----$/);if(!t)throw new Error("license key could not be parsed");let i=t.groups.encryptedSymmetricKey,r=t.groups.encryptedData,s=t.groups.signature,n,a;try{n=this.key.decryptPublic(i,"utf8")}catch{throw new Error("Invalid data: Could not extract symmetric key")}try{a=c.AES.decrypt(r,n).toString(c.enc.Utf8)}catch{throw new Error("Invalid Data: Could not decrypt data with key found")}if(this.key.verify(Buffer.from(a),s,"utf8","base64"))return JSON.parse(a);throw new Error("License Key signature invalid")}getIssuerCert(){return this.x509IssuerCert}};export{g as LicenseManager};
41
41
  //# sourceMappingURL=LicenseManager.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/LicenseManager.ts"],"sourcesContent":["import axios from 'axios'\nimport NodeRSA from 'node-rsa'\nimport CryptoJS from 'crypto-js'\nimport { machineId } from 'node-machine-id'\nimport { X509Certificate } from 'node:crypto'\n\nexport type TLicenseManagerConfig = {\n server?: string\n tenantId: number\n productIdentifier: string\n autoRenewEnabled?: boolean\n autoRenewOffset?: number\n loadCertStr: () => Promise<TLicenseContainerStr>\n saveCertStr: (cert: TLicenseContainerStr) => Promise<void>\n deviceFingerprint?: () => string | Promise<string>\n logger?: TLogger\n}\n\nexport type TLicenseContainerStr = string\n\nexport type TLicenseContainer = {\n licenseKey: string\n x509: string\n}\n\nexport type TFeatures = { [key: string]: boolean | number | string }\n\nexport type TMetadata = {\n [key: string]: boolean | number | string | Array<any> | {}\n}\n\nexport type TFeatureSet = {\n validity: number | string // either number in minutes or duration (e.g. \"P14D\") as string\n features: TFeatures\n}\n\nexport type TLicenseCertObj = {\n id: string\n version: number\n tenantId: number\n renewalToken: string\n deviceLock: boolean\n deviceFingerprint: string\n productIdentifierPattern: string\n createdAt: Date\n issuedAt: Date\n expiresAt: Date\n terminatesAt: Date\n featureSets: TFeatureSet[]\n productMetadata: {}\n}\n\nexport type TLogger = {\n error: Function\n warn: Function\n info: Function\n debug: Function\n}\n\nexport class LicenseManager {\n public config: TLicenseManagerConfig\n\n private key?: NodeRSA\n private logger: TLogger\n private licenseCert?: TLicenseCertObj\n private x509Cert?: X509Certificate\n private x509IssuerCert: X509Certificate\n private deviceFingerprint?: string\n private renewalIntervalPointer?: NodeJS.Timer\n\n constructor(config: TLicenseManagerConfig) {\n this.config = config\n\n if (this.config.logger) {\n this.logger = this.config.logger\n } else {\n this.logger = {\n error() {\n console.log('ERROR:', ...arguments)\n },\n warn() {\n console.log('WARN:', ...arguments)\n },\n info() {\n console.log('INFO:', ...arguments)\n },\n debug() {\n console.log('DEBUG:', ...arguments)\n },\n }\n }\n\n this.x509IssuerCert = new X509Certificate(\n '-----BEGIN CERTIFICATE-----\\n' +\n 'MIIFDDCCAvQCCQCWGBewlWbp0DANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJE\\n' +\n 'RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xFzAVBgNVBAMMDmxp\\n' +\n 'Y2Vuc2UubjhuLmlvMB4XDTIyMDYyNDA0MDkzM1oXDTQ5MTEwOTA0MDkzM1owSDEL\\n' +\n 'MAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVybGluMRcw\\n' +\n 'FQYDVQQDDA5saWNlbnNlLm44bi5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC\\n' +\n 'AgoCggIBANK6Uj5CSyPaa2rf/bwH/AqzzINeWg4n94pECv4p8tsjy0+ZscodNn7Q\\n' +\n 'IvYW/6IUpax8fZvHCSqu0L7fsgLkw0+HDLlsln+ryI/3h1ElVZm67BfqOvhSfPj+\\n' +\n 'btxcP8EtS+6hbf74sqPEBFD0wikKhIPGdtBolp7rLXfTGs+5eMqSA5q4W1V+HUUU\\n' +\n 'zgaCdchzlHGTdIICNpbRozGeFTIIx1MPzMie+4zIs6i680efx2KJVZWsa2WuCSED\\n' +\n '+b0gSRTgoKQ3B7JjxJKfzHdOdM6JxhkCjrJIkJCrZL7wFypn+wMHsVFrsw/80WkS\\n' +\n 'dwBj/RqCPzKcRwnxs0WNLhkyT/XCMS/1pNzPymdFADu2tEZjhFsa5ziIhdoQz8po\\n' +\n 'Efheyg3mOZDWyu6oyHCLH9lUlsNjV9zZ6RICgvHZvHPmPqOLPomy4Qymq2osuH+S\\n' +\n '28rwEy0W3DCEfuS3dZHrSQfohGC9EAyyFAIPSGhTJSYJl0oNBZjpRM+jAm9ER7PM\\n' +\n 'K70/7g6z8uIgKa8/SD/Pezd/aWzxH/tOokAF5X5o5TzSOwVzqOJzY06EZC7CJnhs\\n' +\n 'sigAJTy1trZJBcZuWnKY5FqrK3QzjsQ9sWM0tRocfNOYmD21mubNo+RmMMo3kvYL\\n' +\n 'JoBfap/cuP6kx3OiRzBJ4luTEa6nRIYy+EjcPaN3+9L5iEZ9/NABAgMBAAEwDQYJ\\n' +\n 'KoZIhvcNAQELBQADggIBAIUpJ0Rh6C92cJqy6iehS8c77r1prj62gr6Acdy5QGh8\\n' +\n 'ax30ANDbPtkezVIIBk+0JjLkMxr3mwqCRsPgMshPcxhZwEafmZrWPPGRVsOfukB3\\n' +\n 'Gp10cIv1YmZ7AFY4i/izj5184+A+GjxrJBULQG1JfX4c7KW06Kaps85AaX/Tp0fl\\n' +\n '/hZ6oUe48aSSTuAW38hWZ5jCpBqfFyQ15ablJZt0fB8NkXEdFUcUEt/OHJfqF5fP\\n' +\n 'Nt5PWC1AuBxzSbzjwabOy/M4r8m5CzCeXSIjqbcsAq52myMoxvNrjKRtucQ7CjqK\\n' +\n 'LR6WdhMf+NLvyTI+evXMoXpDzlevkCpz17uDiDt9XrmvLSf3Ff8mdTRwzVmOmHfc\\n' +\n 'Ruz5v7WBR4cpBR/sC+WxOw9heLMHgYhPyRUM4voo55EcJGusXr/iavblBAnI0GUw\\n' +\n 'uMNs3MjEmfbaBV1K0GKG5UToF9UmUxxVmTcRUZrAQX+yBkRezDTpOQuRnB58BDQP\\n' +\n 'A62lcgZlikzJw3lHue33qAudyUrUmjfHGll7GFQNeLO42jPMeM4NJiNIrBZ7j0uD\\n' +\n '4slHdDi/44PHcKchvde/5k7ZJMi6OC1Vu+bOnKvzhnWQIOkHFQ55m13oslV2ozZT\\n' +\n '/oqhn/8/LeV0ooZuYnBeRkRTveniUeho2OFe5xZvWSSfuBrbHt9+zBg+5MWPUTIJ\\n' +\n '-----END CERTIFICATE-----'\n )\n\n //set defaults for not set config properties:\n this.config.autoRenewEnabled = this.config.autoRenewEnabled ?? true\n this.config.autoRenewOffset = this.config.autoRenewOffset ?? 60 * 60 * 72 // default: 72 hours\n this.config.server = this.config.server ?? 'https://license.n8n.io/v1'\n }\n\n async initialize() {\n this.deviceFingerprint = await this.computeDeviceFingerprint()\n this.logger.info(\n `initializing for deviceFingerprint ${this.deviceFingerprint}`\n )\n await this.initCert()\n\n if (this.config.autoRenewEnabled) {\n //invoke renewal immediately once:\n await this.renewalCron({ force: true })\n\n //and periodically:\n this.renewalIntervalPointer = setInterval(\n () => this.renewalCron({ force: false }),\n 1000 * 60 * 15 //15 minutes\n )\n }\n }\n\n reset() {\n if (this.config.autoRenewEnabled) {\n clearInterval(this.renewalIntervalPointer)\n }\n this.licenseCert = undefined\n this.deviceFingerprint = undefined\n }\n\n async computeDeviceFingerprint() {\n if (\n this.config.deviceFingerprint &&\n typeof this.config.deviceFingerprint === 'function'\n ) {\n return await this.config.deviceFingerprint()\n }\n return await machineId()\n }\n\n async activate(reservationId: string) {\n const response = await axios.post(\n `${this.config.server!}/activate`,\n {\n reservationId,\n tenantId: this.config.tenantId,\n productIdentifier: this.config.productIdentifier,\n deviceFingerprint: this.deviceFingerprint,\n },\n {\n validateStatus: (status) => true, //axios should never throw\n timeout: 10000,\n }\n )\n\n if (response.status == 200) {\n if (\n !response.data.hasOwnProperty('licenseKey') ||\n !response.data.hasOwnProperty('x509')\n ) {\n throw new Error('unexpected server response')\n }\n const containerStr = this.stringifyCertContainer(\n response.data as TLicenseContainer\n )\n await this.config.saveCertStr(containerStr)\n await this.initCert()\n } else {\n const e = new Error(\n `license activation failed: ${\n response.data.message ?? 'unknown reason'\n }`\n )\n this.logger.warn(e.message)\n throw e\n }\n }\n\n async renew() {\n if (!this.isInitialized()) {\n throw new Error('renewal failed because current cert is not initialized')\n }\n\n if (this.isTerminated()) {\n throw new Error('renewal failed because current cert was terminated')\n }\n\n const response = await axios.post(\n `${this.config.server!}/renew`,\n {\n certId: this.licenseCert!.id,\n tenantId: this.config.tenantId,\n productIdentifier: this.config.productIdentifier,\n deviceFingerprint: this.deviceFingerprint,\n renewalToken: this.licenseCert!.renewalToken,\n },\n {\n validateStatus: (_status) => true, //axios should never throw\n timeout: 10000,\n }\n )\n\n if (response.status == 200) {\n if (\n !response.data.hasOwnProperty('licenseKey') ||\n !response.data.hasOwnProperty('x509')\n ) {\n throw new Error('unexpected server response')\n }\n const containerStr = this.stringifyCertContainer(\n response.data as TLicenseContainer\n )\n await this.config.saveCertStr(containerStr)\n this.logger.info('license successfully renewed')\n await this.initCert()\n } else {\n const e = new Error(\n `license renewal failed: ${response.data.message ?? 'unknown reason'}`\n )\n this.logger.warn(e.message)\n throw e\n }\n }\n\n private isInitialized() {\n return this.licenseCert !== undefined\n }\n\n isTerminated(): boolean {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n const now = new Date()\n\n return this.licenseCert!.terminatesAt < now\n }\n\n getExpiryDate(): Date {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n return this.licenseCert!.expiresAt\n }\n\n getTerminationDate(): Date {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n return this.licenseCert!.terminatesAt\n }\n\n isValid(useLogger = true): boolean {\n const logger = this.logger\n const debug = (msg: string) => {\n if (useLogger) {\n logger.debug(msg)\n }\n }\n\n if (!this.isInitialized()) {\n debug('cert is invalid because it is undefined')\n return false\n }\n\n const cert = this.licenseCert as TLicenseCertObj\n const now = new Date()\n\n if (cert.expiresAt < now) {\n debug('cert is invalid because it has expired')\n return false\n }\n\n if (cert.terminatesAt < now) {\n debug('cert is invalid because it was terminated')\n return false\n }\n\n //allow clocks to be out of sync by no more than 300,000 ms / = 5 minutes\n if (cert.createdAt.getTime() - 300000 > now.getTime()) {\n debug('cert is invalid because system clock is out of sync')\n return false\n }\n\n if (cert.deviceLock && this.deviceFingerprint !== cert.deviceFingerprint) {\n debug('cert is invalid because device fingerprint does not match')\n return false\n }\n\n if (this.config.tenantId !== cert.tenantId) {\n debug('cert is invalid because tenant ID does not match')\n return false\n }\n\n const regex = new RegExp(cert.productIdentifierPattern)\n\n if (!regex.test(this.config.productIdentifier)) {\n debug('cert is invalid because product identifier does not match')\n return false\n }\n\n return true\n }\n\n hasFeatureEnabled(\n feature: string,\n requireValidCert: boolean = true\n ): boolean {\n return this.getFeatureValue(feature, requireValidCert) ? true : false\n }\n\n hasFeatureDefined(\n feature: string,\n requireValidCert: boolean = true\n ): boolean {\n return this.getFeatureValue(feature, requireValidCert) !== undefined\n ? true\n : false\n }\n\n hasQuotaLeft(quotaFeatureName: string, currentConsumption: number): boolean {\n const quota = this.getFeatureValue(quotaFeatureName)\n\n if (quota === undefined) {\n return false\n }\n\n if (typeof quota !== 'number') {\n throw new Error(\n `${quotaFeatureName} cannot be used as quota as it is not numeric`\n )\n }\n\n // -1 means unlimited quota!\n if (quota === -1) {\n return true\n }\n\n return Math.ceil(currentConsumption) < Math.ceil(quota)\n }\n\n getFeatureValue(\n feature: string,\n requireValidCert: boolean = true\n ): undefined | boolean | number | string {\n if (!this.isInitialized()) {\n return undefined\n }\n\n if (requireValidCert && !this.isValid()) {\n return undefined\n }\n\n const currentlyValidFeatures = this.getFeatures()\n\n if (!currentlyValidFeatures.hasOwnProperty(feature)) {\n return undefined\n }\n\n return currentlyValidFeatures[feature]\n }\n\n getFeatures() {\n if (!this.isInitialized()) {\n return {}\n }\n\n const now = new Date().getTime()\n const created = this.licenseCert!.createdAt.getTime()\n\n const firstCurrentlyValidFeatureSet = this.licenseCert!.featureSets.find(\n (fs) =>\n fs.validity === 0 ||\n created + (fs.validity as number) * 1000 * 60 >= now\n )\n\n if (!firstCurrentlyValidFeatureSet) {\n return {}\n }\n\n return firstCurrentlyValidFeatureSet.features\n }\n\n getProductMetadata() {\n if (!this.isInitialized()) {\n return {}\n }\n\n return this.licenseCert!.productMetadata\n }\n\n isRenewalDue(): boolean {\n if (!this.isInitialized()) {\n return false\n }\n\n const now = new Date().getTime()\n const expiry = this.licenseCert!.expiresAt.getTime()\n const termination = this.licenseCert!.terminatesAt.getTime()\n\n //returns TRUE when current time is close enough to expiry and not after termination\n return (\n now > expiry - this.config.autoRenewOffset! * 1000 && now < termination\n )\n }\n\n toString() {\n return (\n `certId: ${this.licenseCert?.id ?? '<n/a>'}\\n` +\n `tenantId: ${this.config.tenantId ?? '<n/a>'}\\n` +\n `productIdentifier: ${this.config.productIdentifier ?? '<n/a>'}\\n` +\n `deviceFingerprint: ${this.deviceFingerprint}\\n` +\n `createdAt: ${this.licenseCert?.createdAt ?? '<n/a>'}\\n` +\n `issuedAt: ${this.licenseCert?.issuedAt ?? '<n/a>'}\\n` +\n `expiresAt: ${this.licenseCert?.expiresAt ?? '<n/a>'}\\n` +\n `terminatesAt: ${this.licenseCert?.terminatesAt ?? '<n/a>'}\\n` +\n `isValid: ${this.isValid(false)}\\n` +\n `isRenewalDue: ${this.isRenewalDue()}\\n` +\n `featureSets: ${\n this.licenseCert?.featureSets\n ? JSON.stringify(this.licenseCert?.featureSets)\n : '<n/a>'\n }\\n`\n )\n }\n\n private async renewalCron({ force }: { force: boolean }) {\n if (force || this.isRenewalDue()) {\n this.logger.info('attempting license renewal')\n try {\n await this.renew()\n } catch (e) {}\n }\n }\n\n private async initCert() {\n try {\n const containerStr = await this.config.loadCertStr()\n if (!containerStr || containerStr.length < 50) {\n throw new Error('cert length is too short')\n }\n const { x509, licenseKey } =\n this.parseLicenseCertContainerStr(containerStr)\n this.x509Cert = new X509Certificate(x509)\n const hasApprovedIssuer = this.x509Cert.checkIssued(this.getIssuerCert())\n if (!hasApprovedIssuer) {\n throw new Error('cert was not issued by an approved issuer')\n }\n const publicKey = this.x509Cert.publicKey.export({\n format: 'pem',\n type: 'pkcs1',\n })\n this.key = new NodeRSA(publicKey)\n this.licenseCert = this.parseLicenseKeyStr(licenseKey)\n } catch (e) {\n this.logger.error(\n `cert could not be initialized. ${e instanceof Error ? e.message : ''}`\n )\n }\n }\n\n private stringifyCertContainer(container: TLicenseContainer): string {\n const containerStr = JSON.stringify(container)\n return Buffer.from(containerStr).toString('base64')\n }\n\n private parseLicenseCertContainerStr(\n strigifiedContainer: string\n ): TLicenseContainer {\n const containerStr = Buffer.from(strigifiedContainer, 'base64').toString(\n 'ascii'\n )\n const container = JSON.parse(containerStr)\n if (\n !container.hasOwnProperty('licenseKey') ||\n !container.hasOwnProperty('x509')\n ) {\n throw new Error('license cert container could not be parsed')\n }\n\n return container as TLicenseContainer\n }\n\n private parseLicenseKeyStr(cert: string): TLicenseCertObj {\n const certPayload = this.validateLicenseKey(cert)\n return {\n id: certPayload.id,\n version: certPayload.version,\n tenantId: certPayload.tenantId,\n renewalToken: certPayload.renewalToken,\n deviceLock: certPayload.deviceLock,\n deviceFingerprint: certPayload.deviceFingerprint,\n productIdentifierPattern: certPayload.productIdentifierPattern,\n createdAt: new Date(certPayload.createdAt),\n issuedAt: new Date(certPayload.issuedAt),\n expiresAt: new Date(certPayload.expiresAt),\n terminatesAt: new Date(certPayload.terminatesAt),\n featureSets: certPayload.featureSets as TFeatureSet[],\n productMetadata: certPayload.productMetadata,\n }\n }\n\n private validateLicenseKey(licenseKey: string) {\n //remove all line breaks\n licenseKey = licenseKey.replace(/(\\r\\n|\\n|\\r)/gm, '')\n\n //extract parts\n const match = licenseKey.match(\n /^-----BEGIN LICENSE KEY-----(?<encryptedSymmetricKey>.+\\|\\|)(?<encryptedData>.+)\\|\\|(?<signature>.+)-----END LICENSE KEY-----$/\n )\n\n if (!match) {\n throw new Error('license key could not be parsed')\n }\n\n const encryptedSymmetricKey = match.groups!.encryptedSymmetricKey\n const payload = match.groups!.encryptedData\n const signature = match.groups!.signature\n\n let symmetricKey, decryptedData\n\n //decrypt the random symmetric key\n try {\n symmetricKey = this.key!.decryptPublic(encryptedSymmetricKey, 'utf8')\n } catch (e) {\n throw new Error('Invalid data: Could not extract symmetric key')\n }\n\n //decrypt the payload\n try {\n decryptedData = CryptoJS.AES.decrypt(payload, symmetricKey).toString(\n CryptoJS.enc.Utf8\n )\n } catch (e) {\n throw new Error('Invalid Data: Could not decrypt data with key found')\n }\n\n //verify the signature.\n if (\n this.key!.verify(Buffer.from(decryptedData), signature, 'utf8', 'base64')\n ) {\n //return the decryped data.\n return JSON.parse(decryptedData)\n } else {\n throw new Error('License Key signature invalid')\n }\n }\n\n public getIssuerCert() {\n return this.x509IssuerCert\n }\n}\n"],"mappings":"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","names":["axios","NodeRSA","CryptoJS","machineId","X509Certificate","LicenseManager","config","reservationId","response","status","containerStr","e","_status","now","useLogger","logger","debug","msg","cert","feature","requireValidCert","quotaFeatureName","currentConsumption","quota","currentlyValidFeatures","created","firstCurrentlyValidFeatureSet","fs","expiry","termination","force","x509","licenseKey","publicKey","container","strigifiedContainer","certPayload","match","encryptedSymmetricKey","payload","signature","symmetricKey","decryptedData"]}
1
+ {"version":3,"sources":["../src/LicenseManager.ts"],"sourcesContent":["import axios from 'axios'\nimport NodeRSA from 'node-rsa'\nimport CryptoJS from 'crypto-js'\nimport { machineId } from 'node-machine-id'\nimport { X509Certificate } from 'node:crypto'\n\nexport type TLicenseManagerConfig = {\n server?: string\n tenantId: number\n productIdentifier: string\n autoRenewEnabled?: boolean\n autoRenewOffset?: number\n loadCertStr: () => Promise<TLicenseContainerStr>\n saveCertStr: (cert: TLicenseContainerStr) => Promise<void>\n deviceFingerprint?: () => string | Promise<string>\n onFeatureChange?: () => any\n logger?: TLogger\n}\n\nexport type TLicenseContainerStr = string\n\nexport type TLicenseContainer = {\n licenseKey: string\n x509: string\n}\n\nexport type TFeatures = { [key: string]: boolean | number | string }\n\nexport type TMetadata = {\n [key: string]: boolean | number | string | Array<any> | {}\n}\n\nexport type TFeatureSet = {\n validity: number | string // either number in minutes or duration (e.g. \"P14D\") as string\n features: TFeatures\n}\n\nexport type TLicenseCertObj = {\n id: string\n version: number\n tenantId: number\n renewalToken: string\n deviceLock: boolean\n deviceFingerprint: string\n productIdentifierPattern: string\n createdAt: Date\n issuedAt: Date\n expiresAt: Date\n terminatesAt: Date\n featureSets: TFeatureSet[]\n productMetadata: {}\n managementJwt: string\n}\n\nexport type TLogger = {\n error: Function\n warn: Function\n info: Function\n debug: Function\n}\n\nconst enum LogLevel {\n ERROR = 'error',\n WARN = 'warn',\n INFO = 'info',\n DEBUG = 'debug',\n}\n\nexport class LicenseManager {\n public config: TLicenseManagerConfig\n\n private key?: NodeRSA\n private logger: TLogger\n private licenseCert?: TLicenseCertObj\n private x509Cert?: X509Certificate\n private x509IssuerCert: X509Certificate\n private deviceFingerprint?: string\n private renewalIntervalPointer?: NodeJS.Timer\n private checkUpcomingFeatureChangesCron?: NodeJS.Timer\n private featureChangeTimeoutPointer?: NodeJS.Timer\n\n constructor(config: TLicenseManagerConfig) {\n this.config = config\n\n if (this.config.logger) {\n this.logger = this.config.logger\n } else {\n this.logger = {\n error() {\n console.log('ERROR:', ...arguments)\n },\n warn() {\n console.log('WARN:', ...arguments)\n },\n info() {\n console.log('INFO:', ...arguments)\n },\n debug() {\n console.log('DEBUG:', ...arguments)\n },\n }\n }\n\n this.x509IssuerCert = new X509Certificate(\n '-----BEGIN CERTIFICATE-----\\n' +\n 'MIIFDDCCAvQCCQCWGBewlWbp0DANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJE\\n' +\n 'RTEPMA0GA1UECAwGQmVybGluMQ8wDQYDVQQHDAZCZXJsaW4xFzAVBgNVBAMMDmxp\\n' +\n 'Y2Vuc2UubjhuLmlvMB4XDTIyMDYyNDA0MDkzM1oXDTQ5MTEwOTA0MDkzM1owSDEL\\n' +\n 'MAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVybGluMRcw\\n' +\n 'FQYDVQQDDA5saWNlbnNlLm44bi5pbzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC\\n' +\n 'AgoCggIBANK6Uj5CSyPaa2rf/bwH/AqzzINeWg4n94pECv4p8tsjy0+ZscodNn7Q\\n' +\n 'IvYW/6IUpax8fZvHCSqu0L7fsgLkw0+HDLlsln+ryI/3h1ElVZm67BfqOvhSfPj+\\n' +\n 'btxcP8EtS+6hbf74sqPEBFD0wikKhIPGdtBolp7rLXfTGs+5eMqSA5q4W1V+HUUU\\n' +\n 'zgaCdchzlHGTdIICNpbRozGeFTIIx1MPzMie+4zIs6i680efx2KJVZWsa2WuCSED\\n' +\n '+b0gSRTgoKQ3B7JjxJKfzHdOdM6JxhkCjrJIkJCrZL7wFypn+wMHsVFrsw/80WkS\\n' +\n 'dwBj/RqCPzKcRwnxs0WNLhkyT/XCMS/1pNzPymdFADu2tEZjhFsa5ziIhdoQz8po\\n' +\n 'Efheyg3mOZDWyu6oyHCLH9lUlsNjV9zZ6RICgvHZvHPmPqOLPomy4Qymq2osuH+S\\n' +\n '28rwEy0W3DCEfuS3dZHrSQfohGC9EAyyFAIPSGhTJSYJl0oNBZjpRM+jAm9ER7PM\\n' +\n 'K70/7g6z8uIgKa8/SD/Pezd/aWzxH/tOokAF5X5o5TzSOwVzqOJzY06EZC7CJnhs\\n' +\n 'sigAJTy1trZJBcZuWnKY5FqrK3QzjsQ9sWM0tRocfNOYmD21mubNo+RmMMo3kvYL\\n' +\n 'JoBfap/cuP6kx3OiRzBJ4luTEa6nRIYy+EjcPaN3+9L5iEZ9/NABAgMBAAEwDQYJ\\n' +\n 'KoZIhvcNAQELBQADggIBAIUpJ0Rh6C92cJqy6iehS8c77r1prj62gr6Acdy5QGh8\\n' +\n 'ax30ANDbPtkezVIIBk+0JjLkMxr3mwqCRsPgMshPcxhZwEafmZrWPPGRVsOfukB3\\n' +\n 'Gp10cIv1YmZ7AFY4i/izj5184+A+GjxrJBULQG1JfX4c7KW06Kaps85AaX/Tp0fl\\n' +\n '/hZ6oUe48aSSTuAW38hWZ5jCpBqfFyQ15ablJZt0fB8NkXEdFUcUEt/OHJfqF5fP\\n' +\n 'Nt5PWC1AuBxzSbzjwabOy/M4r8m5CzCeXSIjqbcsAq52myMoxvNrjKRtucQ7CjqK\\n' +\n 'LR6WdhMf+NLvyTI+evXMoXpDzlevkCpz17uDiDt9XrmvLSf3Ff8mdTRwzVmOmHfc\\n' +\n 'Ruz5v7WBR4cpBR/sC+WxOw9heLMHgYhPyRUM4voo55EcJGusXr/iavblBAnI0GUw\\n' +\n 'uMNs3MjEmfbaBV1K0GKG5UToF9UmUxxVmTcRUZrAQX+yBkRezDTpOQuRnB58BDQP\\n' +\n 'A62lcgZlikzJw3lHue33qAudyUrUmjfHGll7GFQNeLO42jPMeM4NJiNIrBZ7j0uD\\n' +\n '4slHdDi/44PHcKchvde/5k7ZJMi6OC1Vu+bOnKvzhnWQIOkHFQ55m13oslV2ozZT\\n' +\n '/oqhn/8/LeV0ooZuYnBeRkRTveniUeho2OFe5xZvWSSfuBrbHt9+zBg+5MWPUTIJ\\n' +\n '-----END CERTIFICATE-----'\n )\n\n //set defaults for not set config properties:\n this.config.autoRenewEnabled = this.config.autoRenewEnabled ?? true\n this.config.autoRenewOffset = this.config.autoRenewOffset ?? 60 * 60 * 72 // default: 72 hours\n this.config.server = this.config.server ?? 'https://license.n8n.io/v1'\n }\n\n log(msg: string, logLevel: LogLevel) {\n this.logger[logLevel](`[license] ${msg}`)\n }\n\n async initialize() {\n if (this.isInitialized()) {\n return\n }\n\n this.deviceFingerprint = await this.computeDeviceFingerprint()\n this.log(\n `initializing for deviceFingerprint ${this.deviceFingerprint}`,\n LogLevel.INFO\n )\n await this.initCert()\n\n if (this.config.onFeatureChange) {\n //set up periodic timer to assess new featureSets turning live\n this.checkUpcomingFeatureChangesCron = setInterval(\n () => this.setTimerForNextFeatureChange(),\n 1000 * 60 * 15 //15 minutes\n )\n }\n\n if (this.config.autoRenewEnabled) {\n //invoke renewal immediately once:\n await this.renewalCron({ force: true })\n\n //and periodically:\n this.renewalIntervalPointer = setInterval(\n () => this.renewalCron({ force: false }),\n 1000 * 60 * 15 //15 minutes\n )\n }\n }\n\n reset() {\n if (this.config.autoRenewEnabled) {\n clearInterval(this.renewalIntervalPointer)\n }\n if (this.checkUpcomingFeatureChangesCron) {\n clearInterval(this.checkUpcomingFeatureChangesCron)\n }\n if (this.featureChangeTimeoutPointer) {\n clearTimeout(this.featureChangeTimeoutPointer)\n }\n this.licenseCert = undefined\n this.deviceFingerprint = undefined\n }\n\n async computeDeviceFingerprint() {\n if (\n this.config.deviceFingerprint &&\n typeof this.config.deviceFingerprint === 'function'\n ) {\n return await this.config.deviceFingerprint()\n }\n return await machineId()\n }\n\n async activate(reservationId: string) {\n const response = await axios.post(\n `${this.config.server!}/activate`,\n {\n reservationId,\n tenantId: this.config.tenantId,\n productIdentifier: this.config.productIdentifier,\n deviceFingerprint: this.deviceFingerprint,\n },\n {\n validateStatus: (status) => true, //axios should never throw\n timeout: 10000,\n }\n )\n\n if (response.status == 200) {\n if (\n !response.data.hasOwnProperty('licenseKey') ||\n !response.data.hasOwnProperty('x509')\n ) {\n throw new Error('unexpected server response')\n }\n const containerStr = this.stringifyCertContainer(\n response.data as TLicenseContainer\n )\n await this.config.saveCertStr(containerStr)\n await this.initCert()\n } else {\n const e = new Error(\n `license activation failed: ${\n response.data.message ?? 'unknown reason'\n }`\n )\n this.log(e.message, LogLevel.WARN)\n throw e\n }\n }\n\n async renew() {\n if (!this.isInitialized()) {\n throw new Error('renewal failed because current cert is not initialized')\n }\n\n if (this.isTerminated()) {\n throw new Error('renewal failed because current cert was terminated')\n }\n\n const response = await axios.post(\n `${this.config.server!}/renew`,\n {\n certId: this.licenseCert!.id,\n tenantId: this.config.tenantId,\n productIdentifier: this.config.productIdentifier,\n deviceFingerprint: this.deviceFingerprint,\n renewalToken: this.licenseCert!.renewalToken,\n },\n {\n validateStatus: (_status) => true, //axios should never throw\n timeout: 10000,\n }\n )\n\n if (response.status == 200) {\n if (\n !response.data.hasOwnProperty('licenseKey') ||\n !response.data.hasOwnProperty('x509')\n ) {\n throw new Error('unexpected server response')\n }\n const containerStr = this.stringifyCertContainer(\n response.data as TLicenseContainer\n )\n await this.config.saveCertStr(containerStr)\n this.log('license successfully renewed', LogLevel.INFO)\n await this.initCert()\n } else {\n const e = new Error(\n `license renewal failed: ${response.data.message ?? 'unknown reason'}`\n )\n this.log(e.message, LogLevel.WARN)\n throw e\n }\n }\n\n private isInitialized() {\n return this.licenseCert !== undefined\n }\n\n isTerminated(): boolean {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n const now = new Date()\n\n return this.licenseCert!.terminatesAt < now\n }\n\n getExpiryDate(): Date {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n return this.licenseCert!.expiresAt\n }\n\n getTerminationDate(): Date {\n if (!this.isInitialized()) {\n throw new Error('Cert is not initialized')\n }\n\n return this.licenseCert!.terminatesAt\n }\n\n isValid(useLogger = true): boolean {\n const debug = (msg: string) => {\n if (useLogger) {\n this.log(msg, LogLevel.DEBUG)\n }\n }\n\n if (!this.isInitialized()) {\n debug('cert is invalid because it is undefined')\n return false\n }\n\n const cert = this.licenseCert as TLicenseCertObj\n const now = new Date()\n\n if (cert.expiresAt < now) {\n debug('cert is invalid because it has expired')\n return false\n }\n\n if (cert.terminatesAt < now) {\n debug('cert is invalid because it was terminated')\n return false\n }\n\n //allow clocks to be out of sync by no more than 300,000 ms / = 5 minutes\n if (cert.createdAt.getTime() - 300000 > now.getTime()) {\n debug('cert is invalid because system clock is out of sync')\n return false\n }\n\n if (cert.deviceLock && this.deviceFingerprint !== cert.deviceFingerprint) {\n debug('cert is invalid because device fingerprint does not match')\n return false\n }\n\n if (this.config.tenantId !== cert.tenantId) {\n debug('cert is invalid because tenant ID does not match')\n return false\n }\n\n const regex = new RegExp(cert.productIdentifierPattern)\n\n if (!regex.test(this.config.productIdentifier)) {\n debug('cert is invalid because product identifier does not match')\n return false\n }\n\n return true\n }\n\n hasFeatureEnabled(\n feature: string,\n requireValidCert: boolean = true\n ): boolean {\n return this.getFeatureValue(feature, requireValidCert) ? true : false\n }\n\n hasFeatureDefined(\n feature: string,\n requireValidCert: boolean = true\n ): boolean {\n return this.getFeatureValue(feature, requireValidCert) !== undefined\n ? true\n : false\n }\n\n hasQuotaLeft(quotaFeatureName: string, currentConsumption: number): boolean {\n const quota = this.getFeatureValue(quotaFeatureName)\n\n if (quota === undefined) {\n return false\n }\n\n if (typeof quota !== 'number') {\n throw new Error(\n `${quotaFeatureName} cannot be used as quota as it is not numeric`\n )\n }\n\n // -1 means unlimited quota!\n if (quota === -1) {\n return true\n }\n\n return Math.ceil(currentConsumption) < Math.ceil(quota)\n }\n\n getFeatureValue(\n feature: string,\n requireValidCert: boolean = true\n ): undefined | boolean | number | string {\n if (!this.isInitialized()) {\n return undefined\n }\n\n if (requireValidCert && !this.isValid()) {\n return undefined\n }\n\n const currentlyValidFeatures = this.getFeatures()\n\n if (!currentlyValidFeatures.hasOwnProperty(feature)) {\n return undefined\n }\n\n return currentlyValidFeatures[feature]\n }\n\n getFeatures() {\n if (!this.isInitialized()) {\n return {}\n }\n\n const now = new Date().getTime()\n const created = this.licenseCert!.createdAt.getTime()\n\n const firstCurrentlyValidFeatureSet = this.licenseCert!.featureSets.find(\n (fs) =>\n fs.validity === 0 ||\n created + (fs.validity as number) * 1000 * 60 >= now\n )\n\n if (!firstCurrentlyValidFeatureSet) {\n return {}\n }\n\n return firstCurrentlyValidFeatureSet.features\n }\n\n getProductMetadata() {\n if (!this.isInitialized()) {\n return {}\n }\n\n return this.licenseCert!.productMetadata\n }\n\n getManagementJwt() {\n if (!this.isInitialized()) {\n return ''\n }\n\n return this.licenseCert!.managementJwt\n }\n\n isRenewalDue(): boolean {\n if (!this.isInitialized()) {\n return false\n }\n\n const now = new Date().getTime()\n const expiry = this.licenseCert!.expiresAt.getTime()\n const termination = this.licenseCert!.terminatesAt.getTime()\n\n //returns TRUE when current time is close enough to expiry and not after termination\n return (\n now > expiry - this.config.autoRenewOffset! * 1000 && now < termination\n )\n }\n\n toString() {\n return (\n `certId: ${this.licenseCert?.id ?? '<n/a>'}\\n` +\n `tenantId: ${this.config.tenantId ?? '<n/a>'}\\n` +\n `productIdentifier: ${this.config.productIdentifier ?? '<n/a>'}\\n` +\n `deviceFingerprint: ${this.deviceFingerprint}\\n` +\n `createdAt: ${this.licenseCert?.createdAt ?? '<n/a>'}\\n` +\n `issuedAt: ${this.licenseCert?.issuedAt ?? '<n/a>'}\\n` +\n `expiresAt: ${this.licenseCert?.expiresAt ?? '<n/a>'}\\n` +\n `terminatesAt: ${this.licenseCert?.terminatesAt ?? '<n/a>'}\\n` +\n `isValid: ${this.isValid(false)}\\n` +\n `isRenewalDue: ${this.isRenewalDue()}\\n` +\n `featureSets: ${\n this.licenseCert?.featureSets\n ? JSON.stringify(this.licenseCert?.featureSets)\n : '<n/a>'\n }\\n`\n )\n }\n\n private triggerOnFeatureChangeCallback() {\n if (this.config.onFeatureChange) {\n this.config.onFeatureChange()\n }\n }\n\n private setTimerForNextFeatureChange() {\n if (!this.isInitialized() || !this.config.onFeatureChange) {\n return\n }\n\n const now = new Date().getTime()\n const certCreatedAt = this.licenseCert!.createdAt.getTime()\n\n const nextFeatureSet = this.licenseCert!.featureSets.find(\n (fs) => certCreatedAt + (fs.validity as number) * 1000 * 60 > now\n )\n\n let upcomingEvents = []\n\n if (nextFeatureSet) {\n upcomingEvents.push(\n certCreatedAt + (nextFeatureSet.validity as number) * 1000 * 60 - now\n )\n }\n\n upcomingEvents.push(this.licenseCert!.expiresAt.getTime() - now)\n upcomingEvents.push(this.licenseCert!.terminatesAt.getTime() - now)\n\n upcomingEvents = upcomingEvents\n .filter((timeTillEventInMs) => timeTillEventInMs >= 0)\n .sort((a, b) => a - b)\n\n const timeTillNextEventInMs = upcomingEvents[0]\n\n if (timeTillNextEventInMs < 15 * 60 * 1000) {\n // 15*60*1000 == 15 minutes\n clearTimeout(this.featureChangeTimeoutPointer)\n this.featureChangeTimeoutPointer = setTimeout(() => {\n this.triggerOnFeatureChangeCallback()\n this.setTimerForNextFeatureChange()\n }, timeTillNextEventInMs + 1000)\n }\n }\n\n private async renewalCron({ force }: { force: boolean }) {\n if (force || this.isRenewalDue()) {\n this.log('attempting license renewal', LogLevel.INFO)\n try {\n await this.renew()\n } catch (e) {}\n }\n }\n\n private async initCert() {\n try {\n const containerStr = await this.config.loadCertStr()\n if (!containerStr || containerStr.length < 50) {\n throw new Error('cert string is undefined or too short')\n }\n const { x509, licenseKey } =\n this.parseLicenseCertContainerStr(containerStr)\n this.x509Cert = new X509Certificate(x509)\n const hasApprovedIssuer = this.x509Cert.checkIssued(this.getIssuerCert())\n if (!hasApprovedIssuer) {\n throw new Error('cert was not issued by an approved issuer')\n }\n const publicKey = this.x509Cert.publicKey.export({\n format: 'pem',\n type: 'pkcs1',\n })\n this.key = new NodeRSA(publicKey)\n this.licenseCert = this.parseLicenseKeyStr(licenseKey)\n this.triggerOnFeatureChangeCallback()\n this.setTimerForNextFeatureChange()\n } catch (e) {\n this.log(\n `cert could not be initialized. ${e instanceof Error ? e.message : ''}`,\n LogLevel.ERROR\n )\n }\n }\n\n private stringifyCertContainer(container: TLicenseContainer): string {\n const containerStr = JSON.stringify(container)\n return Buffer.from(containerStr).toString('base64')\n }\n\n private parseLicenseCertContainerStr(\n strigifiedContainer: string\n ): TLicenseContainer {\n const containerStr = Buffer.from(strigifiedContainer, 'base64').toString(\n 'ascii'\n )\n const container = JSON.parse(containerStr)\n if (\n !container.hasOwnProperty('licenseKey') ||\n !container.hasOwnProperty('x509')\n ) {\n throw new Error('license cert container could not be parsed')\n }\n\n return container as TLicenseContainer\n }\n\n private parseLicenseKeyStr(certStr: string): TLicenseCertObj {\n const certPayload = this.validateLicenseKey(certStr)\n\n const cert = { ...certPayload } as TLicenseCertObj\n\n // turn timestamp strings into Date objects\n cert.createdAt = new Date(certPayload.createdAt)\n cert.issuedAt = new Date(certPayload.issuedAt)\n cert.expiresAt = new Date(certPayload.expiresAt)\n cert.terminatesAt = new Date(certPayload.terminatesAt)\n\n return cert\n }\n\n private validateLicenseKey(licenseKey: string) {\n //remove all line breaks\n licenseKey = licenseKey.replace(/(\\r\\n|\\n|\\r)/gm, '')\n\n //extract parts\n const match = licenseKey.match(\n /^-----BEGIN LICENSE KEY-----(?<encryptedSymmetricKey>.+\\|\\|)(?<encryptedData>.+)\\|\\|(?<signature>.+)-----END LICENSE KEY-----$/\n )\n\n if (!match) {\n throw new Error('license key could not be parsed')\n }\n\n const encryptedSymmetricKey = match.groups!.encryptedSymmetricKey\n const payload = match.groups!.encryptedData\n const signature = match.groups!.signature\n\n let symmetricKey, decryptedData\n\n //decrypt the random symmetric key\n try {\n symmetricKey = this.key!.decryptPublic(encryptedSymmetricKey, 'utf8')\n } catch (e) {\n throw new Error('Invalid data: Could not extract symmetric key')\n }\n\n //decrypt the payload\n try {\n decryptedData = CryptoJS.AES.decrypt(payload, symmetricKey).toString(\n CryptoJS.enc.Utf8\n )\n } catch (e) {\n throw new Error('Invalid Data: Could not decrypt data with key found')\n }\n\n //verify the signature.\n if (\n this.key!.verify(Buffer.from(decryptedData), signature, 'utf8', 'base64')\n ) {\n //return the decryped data.\n return JSON.parse(decryptedData)\n } else {\n throw new Error('License Key signature invalid')\n }\n }\n\n public getIssuerCert() {\n return this.x509IssuerCert\n }\n}\n"],"mappings":"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","names":["axios","NodeRSA","CryptoJS","machineId","X509Certificate","LicenseManager","config","X509Certificate","msg","logLevel","machineId","reservationId","response","axios","status","containerStr","e","_status","now","useLogger","debug","cert","feature","requireValidCert","quotaFeatureName","currentConsumption","quota","currentlyValidFeatures","created","firstCurrentlyValidFeatureSet","fs","expiry","termination","certCreatedAt","nextFeatureSet","upcomingEvents","timeTillEventInMs","a","b","timeTillNextEventInMs","force","x509","licenseKey","publicKey","NodeRSA","container","strigifiedContainer","certStr","certPayload","match","encryptedSymmetricKey","payload","signature","symmetricKey","decryptedData","CryptoJS"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@n8n_io/license-sdk",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "description": "",
5
5
  "main": "dist/LicenseManager.js",
6
6
  "types": "dist/LicenseManager.d.ts",