feat: Add support for preAuthentication and add Metabase credentials (#3399)

*  Add preAuthentication method to credentials

* Improvements

*  Improvements

*  Add feedback

* 🔥 Remove comments

*  Add generic type to autheticate method

*  Fix typo

*  Remove console.log and fix indentation

*  Minor improvements

*  Expire credentials in every credential test run

Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
Ricardo Espinoza
2022-07-19 04:09:06 -04:00
committed by GitHub
parent f958e6ffab
commit 994c89a6c6
9 changed files with 290 additions and 7 deletions

View File

@@ -37,6 +37,7 @@ import {
WorkflowExecuteMode,
ITaskDataConnections,
LoggerProxy as Logger,
IHttpRequestHelper,
} from 'n8n-workflow';
// eslint-disable-next-line import/no-cycle
@@ -140,6 +141,61 @@ export class CredentialsHelper extends ICredentialsHelper {
return requestOptions as IHttpRequestOptions;
}
async preAuthentication(
helpers: IHttpRequestHelper,
credentials: ICredentialDataDecryptedObject,
typeName: string,
node: INode,
credentialsExpired: boolean,
): Promise<ICredentialDataDecryptedObject | undefined> {
const credentialType = this.credentialTypes.getByName(typeName);
const expirableProperty = credentialType.properties.find(
(property) => property.type === 'hidden' && property?.typeOptions?.expirable === true,
);
if (expirableProperty === undefined || expirableProperty.name === undefined) {
return undefined;
}
// check if the node is the mockup node used for testing
// if so, it means this is a credential test and not normal node execution
const isTestingCredentials =
node?.parameters?.temp === '' && node?.type === 'n8n-nodes-base.noOp';
if (credentialType.preAuthentication) {
if (typeof credentialType.preAuthentication === 'function') {
// if the expirable property is empty in the credentials
// or are expired, call pre authentication method
// or the credentials are being tested
if (
credentials[expirableProperty?.name] === '' ||
credentialsExpired ||
isTestingCredentials
) {
const output = await credentialType.preAuthentication.call(helpers, credentials);
// if there is data in the output, make sure the returned
// property is the expirable property
// else the database will not get updated
if (output[expirableProperty.name] === undefined) {
return undefined;
}
if (node.credentials) {
await this.updateCredentials(
node.credentials[credentialType.name],
credentialType.name,
Object.assign(credentials, output),
);
return Object.assign(credentials, output);
}
}
}
}
return undefined;
}
/**
* Resolves the given value in case it is an expression
*/
@@ -538,6 +594,12 @@ export class CredentialsHelper extends ICredentialsHelper {
? nodeType.description.version.slice(-1)[0]
: nodeType.description.version,
position: [0, 0],
credentials: {
[credentialType]: {
id: credentialsDecrypted.id.toString(),
name: credentialsDecrypted.name,
},
},
};
const workflowData = {
@@ -622,7 +684,7 @@ export class CredentialsHelper extends ICredentialsHelper {
} catch (error) {
// Do not fail any requests to allow custom error messages and
// make logic easier
if (error.cause.response) {
if (error.cause?.response) {
const errorResponseData = {
statusCode: error.cause.response.status,
statusMessage: error.cause.response.statusText,