refactor(core): Abstract away InstanceSettings and encryptionKey into injectable services (no-changelog) (#7471)

This change ensures that things like `encryptionKey` and `instanceId`
are always available directly where they are needed, instead of passing
them around throughout the code.
This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™
2023-10-23 13:39:35 +02:00
committed by GitHub
parent 519680c2cf
commit b6de910cbe
94 changed files with 501 additions and 1070 deletions

View File

@@ -2,8 +2,7 @@ import { Command } from '@oclif/command';
import { ExitError } from '@oclif/errors';
import { Container } from 'typedi';
import { LoggerProxy, ErrorReporterProxy as ErrorReporter, sleep } from 'n8n-workflow';
import type { IUserSettings } from 'n8n-core';
import { BinaryDataService, ObjectStoreService, UserSettings } from 'n8n-core';
import { BinaryDataService, InstanceSettings, ObjectStoreService } from 'n8n-core';
import type { AbstractServer } from '@/AbstractServer';
import { getLogger } from '@/Logger';
import config from '@/config';
@@ -30,11 +29,9 @@ export abstract class BaseCommand extends Command {
protected nodeTypes: NodeTypes;
protected userSettings: IUserSettings;
protected instanceSettings: InstanceSettings;
protected instanceId: string;
instanceType: N8nInstanceType = 'main';
private instanceType: N8nInstanceType = 'main';
queueModeId: string;
@@ -48,7 +45,7 @@ export abstract class BaseCommand extends Command {
process.once('SIGINT', async () => this.stopProcess());
// Make sure the settings exist
this.userSettings = await UserSettings.prepareUserSettings();
this.instanceSettings = Container.get(InstanceSettings);
await Container.get(LoadNodesAndCredentials).init();
this.nodeTypes = Container.get(NodeTypes);
@@ -76,9 +73,8 @@ export abstract class BaseCommand extends Command {
);
}
this.instanceId = this.userSettings.instanceId ?? '';
await Container.get(PostHogClient).init(this.instanceId);
await Container.get(InternalHooks).init(this.instanceId);
await Container.get(PostHogClient).init();
await Container.get(InternalHooks).init();
}
protected setInstanceType(instanceType: N8nInstanceType) {
@@ -241,7 +237,7 @@ export abstract class BaseCommand extends Command {
async initLicense(): Promise<void> {
const license = Container.get(License);
await license.init(this.instanceId, this.instanceType ?? 'main');
await license.init(this.instanceType ?? 'main');
const activationKey = config.getEnv('license.activationKey');

View File

@@ -2,7 +2,7 @@ import { flags } from '@oclif/command';
import fs from 'fs';
import path from 'path';
import type { FindOptionsWhere } from 'typeorm';
import { Credentials, UserSettings } from 'n8n-core';
import { Credentials } from 'n8n-core';
import * as Db from '@/Db';
import type { ICredentialsDb, ICredentialsDecryptedDb } from '@/Interfaces';
import { BaseCommand } from '../BaseCommand';
@@ -113,13 +113,11 @@ export class ExportCredentialsCommand extends BaseCommand {
const credentials: ICredentialsDb[] = await Db.collections.Credentials.findBy(findQuery);
if (flags.decrypted) {
const encryptionKey = await UserSettings.getEncryptionKey();
for (let i = 0; i < credentials.length; i++) {
const { name, type, nodesAccess, data } = credentials[i];
const id = credentials[i].id;
const credential = new Credentials({ id, name }, type, nodesAccess, data);
const plainData = credential.getData(encryptionKey);
const plainData = credential.getData();
(credentials[i] as ICredentialsDecryptedDb).data = plainData;
}
}

View File

@@ -72,8 +72,6 @@ export class ImportCredentialsCommand extends BaseCommand {
await this.initOwnerCredentialRole();
const user = flags.userId ? await this.getAssignee(flags.userId) : await this.getOwner();
const encryptionKey = this.userSettings.encryptionKey;
if (flags.separate) {
let { input: inputPath } = flags;
@@ -97,7 +95,7 @@ export class ImportCredentialsCommand extends BaseCommand {
if (typeof credential.data === 'object') {
// plain data / decrypted input. Should be encrypted first.
Credentials.prototype.setData.call(credential, credential.data, encryptionKey);
Credentials.prototype.setData.call(credential, credential.data);
}
await this.storeCredential(credential, user);
@@ -125,7 +123,7 @@ export class ImportCredentialsCommand extends BaseCommand {
for (const credential of credentials) {
if (typeof credential.data === 'object') {
// plain data / decrypted input. Should be encrypted first.
Credentials.prototype.setData.call(credential, credential.data, encryptionKey);
Credentials.prototype.setData.call(credential, credential.data);
}
await this.storeCredential(credential, user);
}

View File

@@ -9,7 +9,7 @@ export class LicenseInfoCommand extends BaseCommand {
async run() {
const license = Container.get(License);
await license.init(this.instanceId);
await license.init();
this.logger.info('Printing license information:\n' + license.getInfo());
}

View File

@@ -6,7 +6,6 @@ import path from 'path';
import { mkdir } from 'fs/promises';
import { createReadStream, createWriteStream, existsSync } from 'fs';
import localtunnel from 'localtunnel';
import { TUNNEL_SUBDOMAIN_ENV, UserSettings } from 'n8n-core';
import { flags } from '@oclif/command';
import stream from 'stream';
import replaceStream from 'replacestream';
@@ -245,7 +244,7 @@ export class Start extends BaseCommand {
if (!config.getEnv('userManagement.jwtSecret')) {
// If we don't have a JWT secret set, generate
// one based and save to config.
const encryptionKey = await UserSettings.getEncryptionKey();
const { encryptionKey } = this.instanceSettings;
// For a key off every other letter from encryption key
// CAREFUL: do not change this or it breaks all existing tokens.
@@ -256,8 +255,6 @@ export class Start extends BaseCommand {
config.set('userManagement.jwtSecret', createHash('sha256').update(baseKey).digest('hex'));
}
await UserSettings.getEncryptionKey();
// Load settings from database and set them to config.
const databaseSettings = await Db.collections.Settings.findBy({ loadOnStartup: true });
databaseSettings.forEach((setting) => {
@@ -285,28 +282,19 @@ export class Start extends BaseCommand {
if (flags.tunnel) {
this.log('\nWaiting for tunnel ...');
let tunnelSubdomain;
if (
process.env[TUNNEL_SUBDOMAIN_ENV] !== undefined &&
process.env[TUNNEL_SUBDOMAIN_ENV] !== ''
) {
tunnelSubdomain = process.env[TUNNEL_SUBDOMAIN_ENV];
} else if (this.userSettings.tunnelSubdomain !== undefined) {
tunnelSubdomain = this.userSettings.tunnelSubdomain;
}
let tunnelSubdomain =
process.env.N8N_TUNNEL_SUBDOMAIN ?? this.instanceSettings.tunnelSubdomain ?? '';
if (tunnelSubdomain === undefined) {
if (tunnelSubdomain === '') {
// When no tunnel subdomain did exist yet create a new random one
const availableCharacters = 'abcdefghijklmnopqrstuvwxyz0123456789';
this.userSettings.tunnelSubdomain = Array.from({ length: 24 })
.map(() => {
return availableCharacters.charAt(
Math.floor(Math.random() * availableCharacters.length),
);
})
tunnelSubdomain = Array.from({ length: 24 })
.map(() =>
availableCharacters.charAt(Math.floor(Math.random() * availableCharacters.length)),
)
.join('');
await UserSettings.writeUserSettings(this.userSettings);
this.instanceSettings.update({ tunnelSubdomain });
}
const tunnelSettings: localtunnel.TunnelConfig = {

View File

@@ -318,7 +318,6 @@ export class Worker extends BaseCommand {
await Container.get(OrchestrationWorkerService).init();
await Container.get(OrchestrationHandlerWorkerService).initWithOptions({
queueModeId: this.queueModeId,
instanceId: this.instanceId,
redisPublisher: Container.get(OrchestrationWorkerService).redisPublisher,
getRunningJobIds: () => Object.keys(Worker.runningJobs),
getRunningJobsSummary: () => Object.values(Worker.runningJobsSummary),