import { ICredentialDataDecryptedObject, } from 'n8n-workflow'; import { CredentialTypes, GenericHelpers, ICredentialsOverwrite, } from './'; class CredentialsOverwritesClass { private credentialTypes = CredentialTypes(); private overwriteData: ICredentialsOverwrite = {}; private resolvedTypes: string[] = []; async init(overwriteData?: ICredentialsOverwrite) { if (overwriteData !== undefined) { // If data is already given it can directly be set instead of // loaded from environment this.__setData(JSON.parse(JSON.stringify(overwriteData))); return; } const data = await GenericHelpers.getConfigValue('credentials.overwrite.data') as string; try { const overwriteData = JSON.parse(data); this.__setData(overwriteData); } catch (error) { throw new Error(`The credentials-overwrite is not valid JSON.`); } } __setData(overwriteData: ICredentialsOverwrite) { this.overwriteData = overwriteData; for (const credentialTypeData of this.credentialTypes.getAll()) { const type = credentialTypeData.name; const overwrites = this.__getExtended(type); if (overwrites && Object.keys(overwrites).length) { this.overwriteData[type] = overwrites; } } } applyOverwrite(type: string, data: ICredentialDataDecryptedObject) { const overwrites = this.get(type); if (overwrites === undefined) { return data; } const returnData = JSON.parse(JSON.stringify(data)); // Overwrite only if there is currently no data set for (const key of Object.keys(overwrites)) { if ([null, undefined, ''].includes(returnData[key])) { returnData[key] = overwrites[key]; } } return returnData; } __getExtended(type: string): ICredentialDataDecryptedObject | undefined { if (this.resolvedTypes.includes(type)) { // Type got already resolved and can so returned directly return this.overwriteData[type]; } const credentialTypeData = this.credentialTypes.getByName(type); if (credentialTypeData === undefined) { throw new Error(`The credentials of type "${type}" are not known.`); } if (credentialTypeData.extends === undefined) { this.resolvedTypes.push(type); return this.overwriteData[type]; } const overwrites: ICredentialDataDecryptedObject = {}; for (const credentialsTypeName of credentialTypeData.extends) { Object.assign(overwrites, this.__getExtended(credentialsTypeName)); } if (this.overwriteData[type] !== undefined) { Object.assign(overwrites, this.overwriteData[type]); } this.resolvedTypes.push(type); return overwrites; } get(type: string): ICredentialDataDecryptedObject | undefined { return this.overwriteData[type]; } getAll(): ICredentialsOverwrite { return this.overwriteData; } } let credentialsOverwritesInstance: CredentialsOverwritesClass | undefined; export function CredentialsOverwrites(): CredentialsOverwritesClass { if (credentialsOverwritesInstance === undefined) { credentialsOverwritesInstance = new CredentialsOverwritesClass(); } return credentialsOverwritesInstance; }