feat(core): Add license:info command (#6047)

* feat(core): Add license:info command

* revert changes to start.ts

* revert changes to start.ts

* fix typo
This commit is contained in:
Cornelius Suermann 2023-04-21 17:10:10 +02:00 committed by GitHub
parent 54f99a7d0d
commit ab12d3e327
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 72 additions and 39 deletions

View file

@ -116,7 +116,7 @@
"tsconfig-paths": "^4.1.2" "tsconfig-paths": "^4.1.2"
}, },
"dependencies": { "dependencies": {
"@n8n_io/license-sdk": "~2.1.0", "@n8n_io/license-sdk": "~2.3.0",
"@oclif/command": "^1.8.16", "@oclif/command": "^1.8.16",
"@oclif/core": "^1.16.4", "@oclif/core": "^1.16.4",
"@oclif/errors": "^1.3.6", "@oclif/errors": "^1.3.6",

View file

@ -12,34 +12,6 @@ import {
} from './constants'; } from './constants';
import { Service } from 'typedi'; import { Service } from 'typedi';
async function loadCertStr(): Promise<TLicenseBlock> {
// if we have an ephemeral license, we don't want to load it from the database
const ephemeralLicense = config.get('license.cert');
if (ephemeralLicense) {
return ephemeralLicense;
}
const databaseSettings = await Db.collections.Settings.findOne({
where: {
key: SETTINGS_LICENSE_CERT_KEY,
},
});
return databaseSettings?.value ?? '';
}
async function saveCertStr(value: TLicenseBlock): Promise<void> {
// if we have an ephemeral license, we don't want to save it to the database
if (config.get('license.cert')) return;
await Db.collections.Settings.upsert(
{
key: SETTINGS_LICENSE_CERT_KEY,
value,
loadOnStartup: false,
},
['key'],
);
}
@Service() @Service()
export class License { export class License {
private logger: ILogger; private logger: ILogger;
@ -67,8 +39,8 @@ export class License {
autoRenewEnabled, autoRenewEnabled,
autoRenewOffset, autoRenewOffset,
logger: this.logger, logger: this.logger,
loadCertStr, loadCertStr: async () => this.loadCertStr(),
saveCertStr, saveCertStr: async (value: TLicenseBlock) => this.saveCertStr(value),
deviceFingerprint: () => instanceId, deviceFingerprint: () => instanceId,
}); });
@ -80,6 +52,34 @@ export class License {
} }
} }
async loadCertStr(): Promise<TLicenseBlock> {
// if we have an ephemeral license, we don't want to load it from the database
const ephemeralLicense = config.get('license.cert');
if (ephemeralLicense) {
return ephemeralLicense;
}
const databaseSettings = await Db.collections.Settings.findOne({
where: {
key: SETTINGS_LICENSE_CERT_KEY,
},
});
return databaseSettings?.value ?? '';
}
async saveCertStr(value: TLicenseBlock): Promise<void> {
// if we have an ephemeral license, we don't want to save it to the database
if (config.get('license.cert')) return;
await Db.collections.Settings.upsert(
{
key: SETTINGS_LICENSE_CERT_KEY,
value,
loadOnStartup: false,
},
['key'],
);
}
async activate(activationKey: string): Promise<void> { async activate(activationKey: string): Promise<void> {
if (!this.manager) { if (!this.manager) {
return; return;
@ -185,4 +185,12 @@ export class License {
getPlanName(): string { getPlanName(): string {
return (this.getFeatureValue('planName') ?? 'Community') as string; return (this.getFeatureValue('planName') ?? 'Community') as string;
} }
getInfo(): string {
if (!this.manager) {
return 'n/a';
}
return this.manager.toString();
}
} }

View file

@ -0,0 +1,22 @@
import { License } from '@/License';
import { Container } from 'typedi';
import { BaseCommand } from '../BaseCommand';
export class LicenseInfoCommand extends BaseCommand {
static description = 'Print license information';
static examples = ['$ n8n license:info'];
async run() {
const license = Container.get(License);
await license.init(this.instanceId);
this.logger.info('Printing license information:\n' + license.getInfo());
}
async catch(error: Error) {
this.logger.error('\nGOT ERROR');
this.logger.info('====================================');
this.logger.error(error.message);
}
}

View file

@ -1130,7 +1130,7 @@ export const schema = {
format: Boolean, format: Boolean,
default: true, default: true,
env: 'N8N_LICENSE_AUTO_RENEW_ENABLED', env: 'N8N_LICENSE_AUTO_RENEW_ENABLED',
doc: 'Whether autorenew for licenses is enabled.', doc: 'Whether auto renewal for licenses is enabled.',
}, },
autoRenewOffset: { autoRenewOffset: {
format: Number, format: Number,

View file

@ -75,6 +75,7 @@ licenseController.post(
} catch (e) { } catch (e) {
const error = e as Error & { errorId?: string }; const error = e as Error & { errorId?: string };
//override specific error messages (to map License Server vocabulary to n8n terms)
switch (error.errorId ?? 'UNSPECIFIED') { switch (error.errorId ?? 'UNSPECIFIED') {
case 'SCHEMA_VALIDATION': case 'SCHEMA_VALIDATION':
error.message = 'Activation key is in the wrong format'; error.message = 'Activation key is in the wrong format';
@ -92,7 +93,7 @@ licenseController.post(
break; break;
} }
throw new ResponseHelper.BadRequestError((e as Error).message); throw new ResponseHelper.BadRequestError(error.message);
} }
// Return the read data, plus the management JWT // Return the read data, plus the management JWT
@ -115,10 +116,12 @@ licenseController.post(
try { try {
await license.renew(); await license.renew();
} catch (e) { } catch (e) {
const error = e as Error & { errorId?: string };
// not awaiting so as not to make the endpoint hang // not awaiting so as not to make the endpoint hang
void Container.get(InternalHooks).onLicenseRenewAttempt({ success: false }); void Container.get(InternalHooks).onLicenseRenewAttempt({ success: false });
if (e instanceof Error) { if (error instanceof Error) {
throw new ResponseHelper.BadRequestError(e.message); throw new ResponseHelper.BadRequestError(error.message);
} }
} }

View file

@ -158,8 +158,8 @@ importers:
packages/cli: packages/cli:
dependencies: dependencies:
'@n8n_io/license-sdk': '@n8n_io/license-sdk':
specifier: ~2.1.0 specifier: ~2.3.0
version: 2.1.0 version: 2.3.0
'@oclif/command': '@oclif/command':
specifier: ^1.8.16 specifier: ^1.8.16
version: 1.8.18(@oclif/config@1.18.5)(supports-color@8.1.1) version: 1.8.18(@oclif/config@1.18.5)(supports-color@8.1.1)
@ -4300,8 +4300,8 @@ packages:
dev: false dev: false
optional: true optional: true
/@n8n_io/license-sdk@2.1.0: /@n8n_io/license-sdk@2.3.0:
resolution: {integrity: sha512-SwIm9b6a30/fAvl1aY0a6cgoSyQBgKHX44M4Ykesn45VSGBKlzO5uuIiIcEPdVjjLEelm7u6wLoDFdIVG37b7Q==} resolution: {integrity: sha512-1qOg4VEi2mZzhAJ5Uh9IT9Jn/b3xCaxyFbovYLtymzy3ObafUyWieUrSQri3BrCbW1dwQHz99DEVFxYCq1Je0Q==}
engines: {node: '>=14.0.0', npm: '>=7.10.0'} engines: {node: '>=14.0.0', npm: '>=7.10.0'}
dependencies: dependencies:
crypto-js: 4.1.1 crypto-js: 4.1.1