| import { Container, Service } from '@n8n/di'; |
| import type { IDataObject } from 'n8n-workflow'; |
| import { deepCopy } from 'n8n-workflow'; |
|
|
| import { CREDENTIAL_BLANKING_VALUE } from '@/constants'; |
|
|
| import { ExternalSecretsManager } from './external-secrets-manager.ee'; |
| import type { ExternalSecretsRequest, SecretsProvider } from './types'; |
|
|
| @Service() |
| export class ExternalSecretsService { |
| getProvider(providerName: string): ExternalSecretsRequest.GetProviderResponse | null { |
| const providerAndSettings = |
| Container.get(ExternalSecretsManager).getProviderWithSettings(providerName); |
| const { provider, settings } = providerAndSettings; |
| return { |
| displayName: provider.displayName, |
| name: provider.name, |
| icon: provider.name, |
| state: provider.state, |
| connected: settings.connected, |
| connectedAt: settings.connectedAt, |
| properties: provider.properties, |
| data: this.redact(settings.settings, provider), |
| }; |
| } |
|
|
| async getProviders() { |
| return Container.get(ExternalSecretsManager) |
| .getProvidersWithSettings() |
| .map(({ provider, settings }) => ({ |
| displayName: provider.displayName, |
| name: provider.name, |
| icon: provider.name, |
| state: provider.state, |
| connected: !!settings.connected, |
| connectedAt: settings.connectedAt, |
| data: this.redact(settings.settings, provider), |
| })); |
| } |
|
|
| |
| |
| redact(data: IDataObject, provider: SecretsProvider): IDataObject { |
| const copiedData = deepCopy(data || {}); |
|
|
| const properties = provider.properties; |
|
|
| for (const dataKey of Object.keys(copiedData)) { |
| |
| if (dataKey === 'oauthTokenData') { |
| copiedData[dataKey] = CREDENTIAL_BLANKING_VALUE; |
| continue; |
| } |
| const prop = properties.find((v) => v.name === dataKey); |
| if (!prop) { |
| continue; |
| } |
|
|
| if ( |
| prop.typeOptions?.password && |
| (!(copiedData[dataKey] as string).startsWith('=') || prop.noDataExpression) |
| ) { |
| copiedData[dataKey] = CREDENTIAL_BLANKING_VALUE; |
| } |
| } |
|
|
| return copiedData; |
| } |
|
|
| private unredactRestoreValues(unmerged: any, replacement: any) { |
| |
| for (const [key, value] of Object.entries(unmerged)) { |
| if (value === CREDENTIAL_BLANKING_VALUE) { |
| |
| unmerged[key] = replacement[key]; |
| } else if ( |
| typeof value === 'object' && |
| value !== null && |
| key in replacement && |
| |
| typeof replacement[key] === 'object' && |
| |
| replacement[key] !== null |
| ) { |
| |
| this.unredactRestoreValues(value, replacement[key]); |
| } |
| } |
| } |
|
|
| |
| |
| unredact(redactedData: IDataObject, savedData: IDataObject): IDataObject { |
| |
| const mergedData = deepCopy(redactedData ?? {}); |
| this.unredactRestoreValues(mergedData, savedData); |
| return mergedData; |
| } |
|
|
| async saveProviderSettings(providerName: string, data: IDataObject, userId: string) { |
| const providerAndSettings = |
| Container.get(ExternalSecretsManager).getProviderWithSettings(providerName); |
| const { settings } = providerAndSettings; |
| const newData = this.unredact(data, settings.settings); |
| await Container.get(ExternalSecretsManager).setProviderSettings(providerName, newData, userId); |
| } |
|
|
| async saveProviderConnected(providerName: string, connected: boolean) { |
| await Container.get(ExternalSecretsManager).setProviderConnected(providerName, connected); |
| return this.getProvider(providerName); |
| } |
|
|
| getAllSecrets(): Record<string, string[]> { |
| return Container.get(ExternalSecretsManager).getAllSecretNames(); |
| } |
|
|
| async testProviderSettings(providerName: string, data: IDataObject) { |
| const providerAndSettings = |
| Container.get(ExternalSecretsManager).getProviderWithSettings(providerName); |
| const { settings } = providerAndSettings; |
| const newData = this.unredact(data, settings.settings); |
| return await Container.get(ExternalSecretsManager).testProviderSettings(providerName, newData); |
| } |
|
|
| async updateProvider(providerName: string) { |
| return await Container.get(ExternalSecretsManager).updateProvider(providerName); |
| } |
| } |
|
|