mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
feat: External Secrets storage for credentials (#6477)
Github issue / Community forum post (link here to close automatically): --------- Co-authored-by: Romain Minaud <romain.minaud@gmail.com> Co-authored-by: Valya Bullions <valya@n8n.io> Co-authored-by: Csaba Tuncsik <csaba@n8n.io> Co-authored-by: Giulio Andreini <g.andreini@gmail.com> Co-authored-by: Omar Ajoue <krynble@gmail.com>
This commit is contained in:
@@ -31,6 +31,7 @@ import type {
|
||||
IHttpRequestHelper,
|
||||
INodeTypeData,
|
||||
INodeTypes,
|
||||
IWorkflowExecuteAdditionalData,
|
||||
ICredentialTestFunctions,
|
||||
} from 'n8n-workflow';
|
||||
import {
|
||||
@@ -342,6 +343,7 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||
* @param {boolean} [raw] Return the data as supplied without defaults or overwrites
|
||||
*/
|
||||
async getDecrypted(
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
nodeCredentials: INodeCredentialsDetails,
|
||||
type: string,
|
||||
mode: WorkflowExecuteMode,
|
||||
@@ -356,12 +358,18 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||
return decryptedDataOriginal;
|
||||
}
|
||||
|
||||
await additionalData?.secretsHelpers?.waitForInit();
|
||||
|
||||
const canUseSecrets = await this.credentialOwnedByOwner(nodeCredentials);
|
||||
|
||||
return this.applyDefaultsAndOverwrites(
|
||||
additionalData,
|
||||
decryptedDataOriginal,
|
||||
type,
|
||||
mode,
|
||||
defaultTimezone,
|
||||
expressionResolveValues,
|
||||
canUseSecrets,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -369,11 +377,13 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||
* Applies credential default data and overwrites
|
||||
*/
|
||||
applyDefaultsAndOverwrites(
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
decryptedDataOriginal: ICredentialDataDecryptedObject,
|
||||
type: string,
|
||||
mode: WorkflowExecuteMode,
|
||||
defaultTimezone: string,
|
||||
expressionResolveValues?: ICredentialsExpressionResolveValues,
|
||||
canUseSecrets?: boolean,
|
||||
): ICredentialDataDecryptedObject {
|
||||
const credentialsProperties = this.getCredentialsProperties(type);
|
||||
|
||||
@@ -395,6 +405,10 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||
decryptedData.oauthTokenData = decryptedDataOriginal.oauthTokenData;
|
||||
}
|
||||
|
||||
const additionalKeys = NodeExecuteFunctions.getAdditionalKeys(additionalData, mode, null, {
|
||||
secretsEnabled: canUseSecrets,
|
||||
});
|
||||
|
||||
if (expressionResolveValues) {
|
||||
const timezone = expressionResolveValues.workflow.settings.timezone ?? defaultTimezone;
|
||||
|
||||
@@ -408,7 +422,7 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||
expressionResolveValues.connectionInputData,
|
||||
mode,
|
||||
timezone,
|
||||
{},
|
||||
additionalKeys,
|
||||
undefined,
|
||||
false,
|
||||
decryptedData,
|
||||
@@ -431,7 +445,7 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||
decryptedData as INodeParameters,
|
||||
mode,
|
||||
defaultTimezone,
|
||||
{},
|
||||
additionalKeys,
|
||||
undefined,
|
||||
undefined,
|
||||
decryptedData,
|
||||
@@ -573,10 +587,24 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||
}
|
||||
|
||||
if (credentialsDecrypted.data) {
|
||||
credentialsDecrypted.data = CredentialsOverwrites().applyOverwrite(
|
||||
credentialType,
|
||||
credentialsDecrypted.data,
|
||||
);
|
||||
try {
|
||||
const additionalData = await WorkflowExecuteAdditionalData.getBase(user.id);
|
||||
credentialsDecrypted.data = this.applyDefaultsAndOverwrites(
|
||||
additionalData,
|
||||
credentialsDecrypted.data,
|
||||
credentialType,
|
||||
'internal' as WorkflowExecuteMode,
|
||||
additionalData.timezone,
|
||||
undefined,
|
||||
user.isOwner,
|
||||
);
|
||||
} catch (error) {
|
||||
Logger.debug('Credential test failed', error);
|
||||
return {
|
||||
status: 'Error',
|
||||
message: error.message.toString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof credentialTestFunction === 'function') {
|
||||
@@ -759,6 +787,36 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
}
|
||||
|
||||
async credentialOwnedByOwner(nodeCredential: INodeCredentialsDetails): Promise<boolean> {
|
||||
if (!nodeCredential.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const credential = await Db.collections.SharedCredentials.findOne({
|
||||
where: {
|
||||
role: {
|
||||
scope: 'credential',
|
||||
name: 'owner',
|
||||
},
|
||||
user: {
|
||||
globalRole: {
|
||||
scope: 'global',
|
||||
name: 'owner',
|
||||
},
|
||||
},
|
||||
credentials: {
|
||||
id: nodeCredential.id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!credential) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user