n8n
Version:
n8n Workflow Automation Tool
366 lines • 15.3 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExternalSecretsManager = void 0;
const settings_repository_1 = require("../databases/repositories/settings.repository");
const n8n_core_1 = require("n8n-core");
const typedi_1 = __importStar(require("typedi"));
const Logger_1 = require("../Logger");
const n8n_workflow_1 = require("n8n-workflow");
const constants_1 = require("./constants");
const License_1 = require("../License");
const event_service_1 = require("../events/event.service");
const externalSecretsHelper_ee_1 = require("./externalSecretsHelper.ee");
const ExternalSecretsProviders_ee_1 = require("./ExternalSecretsProviders.ee");
const orchestration_service_1 = require("../services/orchestration.service");
let ExternalSecretsManager = class ExternalSecretsManager {
constructor(logger, settingsRepo, license, secretsProviders, cipher, eventService) {
this.logger = logger;
this.settingsRepo = settingsRepo;
this.license = license;
this.secretsProviders = secretsProviders;
this.cipher = cipher;
this.eventService = eventService;
this.providers = {};
this.cachedSettings = {};
this.initialized = false;
this.initRetryTimeouts = {};
}
async init() {
if (!this.initialized) {
if (!this.initializingPromise) {
this.initializingPromise = new Promise(async (resolve) => {
await this.internalInit();
this.initialized = true;
resolve();
this.initializingPromise = undefined;
this.updateInterval = setInterval(async () => await this.updateSecrets(), (0, externalSecretsHelper_ee_1.updateIntervalTime)());
});
}
return await this.initializingPromise;
}
}
shutdown() {
clearInterval(this.updateInterval);
Object.values(this.providers).forEach((p) => {
void p.disconnect().catch(() => { });
});
Object.values(this.initRetryTimeouts).forEach((v) => clearTimeout(v));
}
async reloadAllProviders(backoff) {
this.logger.debug('Reloading all external secrets providers');
const providers = this.getProviderNames();
if (!providers) {
return;
}
for (const provider of providers) {
await this.reloadProvider(provider, backoff);
}
}
async broadcastReloadExternalSecretsProviders() {
await typedi_1.default.get(orchestration_service_1.OrchestrationService).publish('reloadExternalSecretsProviders');
}
decryptSecretsSettings(value) {
const decryptedData = this.cipher.decrypt(value);
try {
return (0, n8n_workflow_1.jsonParse)(decryptedData);
}
catch (e) {
throw new n8n_workflow_1.ApplicationError('External Secrets Settings could not be decrypted. The likely reason is that a different "encryptionKey" was used to encrypt the data.');
}
}
async getDecryptedSettings(settingsRepo) {
const encryptedSettings = await settingsRepo.getEncryptedSecretsProviderSettings();
if (encryptedSettings === null) {
return null;
}
return this.decryptSecretsSettings(encryptedSettings);
}
async internalInit() {
const settings = await this.getDecryptedSettings(this.settingsRepo);
if (!settings) {
return;
}
const providers = (await Promise.allSettled(Object.entries(settings).map(async ([name, providerSettings]) => await this.initProvider(name, providerSettings)))).map((i) => (i.status === 'rejected' ? null : i.value));
this.providers = Object.fromEntries(providers.filter((p) => p !== null).map((s) => [s.name, s]));
this.cachedSettings = settings;
await this.updateSecrets();
}
async initProvider(name, providerSettings, currentBackoff = constants_1.EXTERNAL_SECRETS_INITIAL_BACKOFF) {
const providerClass = this.secretsProviders.getProvider(name);
if (!providerClass) {
return null;
}
const provider = new providerClass();
try {
await provider.init(providerSettings);
}
catch (e) {
this.logger.error(`Error initializing secrets provider ${provider.displayName} (${provider.name}).`);
this.retryInitWithBackoff(name, currentBackoff);
return provider;
}
try {
if (providerSettings.connected) {
await provider.connect();
}
}
catch (e) {
try {
await provider.disconnect();
}
catch { }
this.logger.error(`Error initializing secrets provider ${provider.displayName} (${provider.name}).`);
this.retryInitWithBackoff(name, currentBackoff);
return provider;
}
return provider;
}
retryInitWithBackoff(name, currentBackoff) {
if (name in this.initRetryTimeouts) {
clearTimeout(this.initRetryTimeouts[name]);
delete this.initRetryTimeouts[name];
}
this.initRetryTimeouts[name] = setTimeout(() => {
delete this.initRetryTimeouts[name];
if (this.providers[name] && this.providers[name].state !== 'error') {
return;
}
void this.reloadProvider(name, Math.min(currentBackoff * 2, constants_1.EXTERNAL_SECRETS_MAX_BACKOFF));
}, currentBackoff);
}
async updateSecrets() {
if (!this.license.isExternalSecretsEnabled()) {
return;
}
await Promise.allSettled(Object.entries(this.providers).map(async ([k, p]) => {
try {
if (this.cachedSettings[k].connected && p.state === 'connected') {
await p.update();
}
}
catch {
this.logger.error(`Error updating secrets provider ${p.displayName} (${p.name}).`);
}
}));
}
getProvider(provider) {
return this.providers[provider];
}
hasProvider(provider) {
return provider in this.providers;
}
getProviderNames() {
return Object.keys(this.providers);
}
getSecret(provider, name) {
var _a;
return (_a = this.getProvider(provider)) === null || _a === void 0 ? void 0 : _a.getSecret(name);
}
hasSecret(provider, name) {
var _a, _b;
return (_b = (_a = this.getProvider(provider)) === null || _a === void 0 ? void 0 : _a.hasSecret(name)) !== null && _b !== void 0 ? _b : false;
}
getSecretNames(provider) {
var _a;
return (_a = this.getProvider(provider)) === null || _a === void 0 ? void 0 : _a.getSecretNames();
}
getAllSecretNames() {
return Object.fromEntries(Object.keys(this.providers).map((provider) => {
var _a;
return [
provider,
(_a = this.getSecretNames(provider)) !== null && _a !== void 0 ? _a : [],
];
}));
}
getProvidersWithSettings() {
return Object.entries(this.secretsProviders.getAllProviders()).map(([k, c]) => {
var _a, _b;
return ({
provider: (_a = this.getProvider(k)) !== null && _a !== void 0 ? _a : new c(),
settings: (_b = this.cachedSettings[k]) !== null && _b !== void 0 ? _b : {},
});
});
}
getProviderWithSettings(provider) {
var _a, _b;
const providerConstructor = this.secretsProviders.getProvider(provider);
if (!providerConstructor) {
return undefined;
}
return {
provider: (_a = this.getProvider(provider)) !== null && _a !== void 0 ? _a : new providerConstructor(),
settings: (_b = this.cachedSettings[provider]) !== null && _b !== void 0 ? _b : {},
};
}
async reloadProvider(provider, backoff = constants_1.EXTERNAL_SECRETS_INITIAL_BACKOFF) {
if (provider in this.providers) {
await this.providers[provider].disconnect();
delete this.providers[provider];
}
const newProvider = await this.initProvider(provider, this.cachedSettings[provider], backoff);
if (newProvider) {
this.providers[provider] = newProvider;
}
}
async setProviderSettings(provider, data, userId) {
var _a, _b, _c, _d;
let isNewProvider = false;
let settings = await this.getDecryptedSettings(this.settingsRepo);
if (!settings) {
settings = {};
}
if (!(provider in settings)) {
isNewProvider = true;
}
settings[provider] = {
connected: (_b = (_a = settings[provider]) === null || _a === void 0 ? void 0 : _a.connected) !== null && _b !== void 0 ? _b : false,
connectedAt: (_d = (_c = settings[provider]) === null || _c === void 0 ? void 0 : _c.connectedAt) !== null && _d !== void 0 ? _d : new Date(),
settings: data,
};
await this.saveAndSetSettings(settings, this.settingsRepo);
this.cachedSettings = settings;
await this.reloadProvider(provider);
await this.broadcastReloadExternalSecretsProviders();
void this.trackProviderSave(provider, isNewProvider, userId);
}
async setProviderConnected(provider, connected) {
var _a, _b, _c, _d;
let settings = await this.getDecryptedSettings(this.settingsRepo);
if (!settings) {
settings = {};
}
settings[provider] = {
connected,
connectedAt: connected ? new Date() : (_b = (_a = settings[provider]) === null || _a === void 0 ? void 0 : _a.connectedAt) !== null && _b !== void 0 ? _b : null,
settings: (_d = (_c = settings[provider]) === null || _c === void 0 ? void 0 : _c.settings) !== null && _d !== void 0 ? _d : {},
};
await this.saveAndSetSettings(settings, this.settingsRepo);
this.cachedSettings = settings;
await this.reloadProvider(provider);
await this.updateSecrets();
await this.broadcastReloadExternalSecretsProviders();
}
async trackProviderSave(vaultType, isNew, userId) {
var _a, _b;
let testResult;
try {
testResult = await ((_a = this.getProvider(vaultType)) === null || _a === void 0 ? void 0 : _a.test());
}
catch { }
this.eventService.emit('external-secrets-provider-settings-saved', {
userId,
vaultType,
isNew,
isValid: (_b = testResult === null || testResult === void 0 ? void 0 : testResult[0]) !== null && _b !== void 0 ? _b : false,
errorMessage: testResult === null || testResult === void 0 ? void 0 : testResult[1],
});
}
encryptSecretsSettings(settings) {
return this.cipher.encrypt(settings);
}
async saveAndSetSettings(settings, settingsRepo) {
const encryptedSettings = this.encryptSecretsSettings(settings);
await settingsRepo.saveEncryptedSecretsProviderSettings(encryptedSettings);
}
async testProviderSettings(provider, data) {
var _a;
let testProvider = null;
try {
testProvider = await this.initProvider(provider, {
connected: true,
connectedAt: new Date(),
settings: data,
});
if (!testProvider) {
return {
success: false,
testState: 'error',
};
}
const [success, error] = await testProvider.test();
let testState = 'error';
if (success && ((_a = this.cachedSettings[provider]) === null || _a === void 0 ? void 0 : _a.connected)) {
testState = 'connected';
}
else if (success) {
testState = 'tested';
}
return {
success,
testState,
error,
};
}
catch {
return {
success: false,
testState: 'error',
};
}
finally {
if (testProvider) {
await testProvider.disconnect();
}
}
}
async updateProvider(provider) {
if (!this.license.isExternalSecretsEnabled()) {
return false;
}
if (!this.providers[provider] || this.providers[provider].state !== 'connected') {
return false;
}
try {
await this.providers[provider].update();
await this.broadcastReloadExternalSecretsProviders();
return true;
}
catch {
return false;
}
}
};
exports.ExternalSecretsManager = ExternalSecretsManager;
exports.ExternalSecretsManager = ExternalSecretsManager = __decorate([
(0, typedi_1.Service)(),
__metadata("design:paramtypes", [Logger_1.Logger,
settings_repository_1.SettingsRepository,
License_1.License,
ExternalSecretsProviders_ee_1.ExternalSecretsProviders,
n8n_core_1.Cipher,
event_service_1.EventService])
], ExternalSecretsManager);
//# sourceMappingURL=ExternalSecretsManager.ee.js.map