mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
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:
parent
f958e6ffab
commit
994c89a6c6
|
@ -37,6 +37,7 @@ import {
|
||||||
WorkflowExecuteMode,
|
WorkflowExecuteMode,
|
||||||
ITaskDataConnections,
|
ITaskDataConnections,
|
||||||
LoggerProxy as Logger,
|
LoggerProxy as Logger,
|
||||||
|
IHttpRequestHelper,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-cycle
|
// eslint-disable-next-line import/no-cycle
|
||||||
|
@ -140,6 +141,61 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||||
return requestOptions as IHttpRequestOptions;
|
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
|
* 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.slice(-1)[0]
|
||||||
: nodeType.description.version,
|
: nodeType.description.version,
|
||||||
position: [0, 0],
|
position: [0, 0],
|
||||||
|
credentials: {
|
||||||
|
[credentialType]: {
|
||||||
|
id: credentialsDecrypted.id.toString(),
|
||||||
|
name: credentialsDecrypted.name,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const workflowData = {
|
const workflowData = {
|
||||||
|
@ -622,7 +684,7 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Do not fail any requests to allow custom error messages and
|
// Do not fail any requests to allow custom error messages and
|
||||||
// make logic easier
|
// make logic easier
|
||||||
if (error.cause.response) {
|
if (error.cause?.response) {
|
||||||
const errorResponseData = {
|
const errorResponseData = {
|
||||||
statusCode: error.cause.response.status,
|
statusCode: error.cause.response.status,
|
||||||
statusMessage: error.cause.response.statusText,
|
statusMessage: error.cause.response.statusText,
|
||||||
|
|
|
@ -6,7 +6,12 @@
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
import { UserSettings, Credentials } from 'n8n-core';
|
import { UserSettings, Credentials } from 'n8n-core';
|
||||||
import { INodeCredentialTestResult, LoggerProxy } from 'n8n-workflow';
|
import {
|
||||||
|
INodeCredentialsDetails,
|
||||||
|
INodeCredentialTestResult,
|
||||||
|
LoggerProxy,
|
||||||
|
WorkflowExecuteMode,
|
||||||
|
} from 'n8n-workflow';
|
||||||
import { getLogger } from '../Logger';
|
import { getLogger } from '../Logger';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -17,6 +22,7 @@ import {
|
||||||
ICredentialsResponse,
|
ICredentialsResponse,
|
||||||
whereClause,
|
whereClause,
|
||||||
ResponseHelper,
|
ResponseHelper,
|
||||||
|
CredentialTypes,
|
||||||
} from '..';
|
} from '..';
|
||||||
|
|
||||||
import { RESPONSE_ERROR_MESSAGES } from '../constants';
|
import { RESPONSE_ERROR_MESSAGES } from '../constants';
|
||||||
|
@ -130,7 +136,6 @@ credentialsController.post(
|
||||||
}
|
}
|
||||||
|
|
||||||
const helper = new CredentialsHelper(encryptionKey);
|
const helper = new CredentialsHelper(encryptionKey);
|
||||||
|
|
||||||
return helper.testCredentials(req.user, credentials.type, credentials, nodeToTestWith);
|
return helper.testCredentials(req.user, credentials.type, credentials, nodeToTestWith);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1182,6 +1182,7 @@ export async function httpRequestWithAuthentication(
|
||||||
additionalData: IWorkflowExecuteAdditionalData,
|
additionalData: IWorkflowExecuteAdditionalData,
|
||||||
additionalCredentialOptions?: IAdditionalCredentialOptions,
|
additionalCredentialOptions?: IAdditionalCredentialOptions,
|
||||||
) {
|
) {
|
||||||
|
let credentialsDecrypted: ICredentialDataDecryptedObject | undefined;
|
||||||
try {
|
try {
|
||||||
const parentTypes = additionalData.credentialsHelper.getParentTypes(credentialsType);
|
const parentTypes = additionalData.credentialsHelper.getParentTypes(credentialsType);
|
||||||
if (parentTypes.includes('oAuth1Api')) {
|
if (parentTypes.includes('oAuth1Api')) {
|
||||||
|
@ -1199,7 +1200,6 @@ export async function httpRequestWithAuthentication(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let credentialsDecrypted: ICredentialDataDecryptedObject | undefined;
|
|
||||||
if (additionalCredentialOptions?.credentialsDecrypted) {
|
if (additionalCredentialOptions?.credentialsDecrypted) {
|
||||||
credentialsDecrypted = additionalCredentialOptions.credentialsDecrypted.data;
|
credentialsDecrypted = additionalCredentialOptions.credentialsDecrypted.data;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1213,6 +1213,20 @@ export async function httpRequestWithAuthentication(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const data = await additionalData.credentialsHelper.preAuthentication(
|
||||||
|
{ helpers: { httpRequest: this.helpers.httpRequest } },
|
||||||
|
credentialsDecrypted,
|
||||||
|
credentialsType,
|
||||||
|
node,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
// make the updated property in the credentials
|
||||||
|
// available to the authenticate method
|
||||||
|
Object.assign(credentialsDecrypted, data);
|
||||||
|
}
|
||||||
|
|
||||||
requestOptions = await additionalData.credentialsHelper.authenticate(
|
requestOptions = await additionalData.credentialsHelper.authenticate(
|
||||||
credentialsDecrypted,
|
credentialsDecrypted,
|
||||||
credentialsType,
|
credentialsType,
|
||||||
|
@ -1223,6 +1237,45 @@ export async function httpRequestWithAuthentication(
|
||||||
);
|
);
|
||||||
return await httpRequest(requestOptions);
|
return await httpRequest(requestOptions);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
// if there is a pre authorization method defined and
|
||||||
|
// the method failed due to unathorized request
|
||||||
|
if (
|
||||||
|
error.response?.status === 401 &&
|
||||||
|
additionalData.credentialsHelper.preAuthentication !== undefined
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
if (credentialsDecrypted !== undefined) {
|
||||||
|
// try to refresh the credentials
|
||||||
|
const data = await additionalData.credentialsHelper.preAuthentication(
|
||||||
|
{ helpers: { httpRequest: this.helpers.httpRequest } },
|
||||||
|
credentialsDecrypted,
|
||||||
|
credentialsType,
|
||||||
|
node,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
// make the updated property in the credentials
|
||||||
|
// available to the authenticate method
|
||||||
|
Object.assign(credentialsDecrypted, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestOptions = await additionalData.credentialsHelper.authenticate(
|
||||||
|
credentialsDecrypted,
|
||||||
|
credentialsType,
|
||||||
|
requestOptions,
|
||||||
|
workflow,
|
||||||
|
node,
|
||||||
|
additionalData.timezone,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// retry the request
|
||||||
|
return await httpRequest(requestOptions);
|
||||||
|
} catch (error) {
|
||||||
|
throw new NodeApiError(this.getNode(), error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
throw new NodeApiError(this.getNode(), error);
|
throw new NodeApiError(this.getNode(), error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1303,6 +1356,8 @@ export async function requestWithAuthentication(
|
||||||
additionalData: IWorkflowExecuteAdditionalData,
|
additionalData: IWorkflowExecuteAdditionalData,
|
||||||
additionalCredentialOptions?: IAdditionalCredentialOptions,
|
additionalCredentialOptions?: IAdditionalCredentialOptions,
|
||||||
) {
|
) {
|
||||||
|
let credentialsDecrypted: ICredentialDataDecryptedObject | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const parentTypes = additionalData.credentialsHelper.getParentTypes(credentialsType);
|
const parentTypes = additionalData.credentialsHelper.getParentTypes(credentialsType);
|
||||||
|
|
||||||
|
@ -1321,7 +1376,6 @@ export async function requestWithAuthentication(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let credentialsDecrypted: ICredentialDataDecryptedObject | undefined;
|
|
||||||
if (additionalCredentialOptions?.credentialsDecrypted) {
|
if (additionalCredentialOptions?.credentialsDecrypted) {
|
||||||
credentialsDecrypted = additionalCredentialOptions.credentialsDecrypted.data;
|
credentialsDecrypted = additionalCredentialOptions.credentialsDecrypted.data;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1335,6 +1389,20 @@ export async function requestWithAuthentication(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const data = await additionalData.credentialsHelper.preAuthentication(
|
||||||
|
{ helpers: { httpRequest: this.helpers.httpRequest } },
|
||||||
|
credentialsDecrypted,
|
||||||
|
credentialsType,
|
||||||
|
node,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
// make the updated property in the credentials
|
||||||
|
// available to the authenticate method
|
||||||
|
Object.assign(credentialsDecrypted, data);
|
||||||
|
}
|
||||||
|
|
||||||
requestOptions = await additionalData.credentialsHelper.authenticate(
|
requestOptions = await additionalData.credentialsHelper.authenticate(
|
||||||
credentialsDecrypted,
|
credentialsDecrypted,
|
||||||
credentialsType,
|
credentialsType,
|
||||||
|
@ -1346,7 +1414,37 @@ export async function requestWithAuthentication(
|
||||||
|
|
||||||
return await proxyRequestToAxios(requestOptions as IDataObject);
|
return await proxyRequestToAxios(requestOptions as IDataObject);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new NodeApiError(this.getNode(), error);
|
try {
|
||||||
|
if (credentialsDecrypted !== undefined) {
|
||||||
|
// try to refresh the credentials
|
||||||
|
const data = await additionalData.credentialsHelper.preAuthentication(
|
||||||
|
{ helpers: { httpRequest: this.helpers.httpRequest } },
|
||||||
|
credentialsDecrypted,
|
||||||
|
credentialsType,
|
||||||
|
node,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
// make the updated property in the credentials
|
||||||
|
// available to the authenticate method
|
||||||
|
Object.assign(credentialsDecrypted, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
requestOptions = await additionalData.credentialsHelper.authenticate(
|
||||||
|
credentialsDecrypted,
|
||||||
|
credentialsType,
|
||||||
|
requestOptions as IHttpRequestOptions,
|
||||||
|
workflow,
|
||||||
|
node,
|
||||||
|
additionalData.timezone,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// retry the request
|
||||||
|
return await proxyRequestToAxios(requestOptions as IDataObject);
|
||||||
|
} catch (error) {
|
||||||
|
throw new NodeApiError(this.getNode(), error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,9 @@ import {
|
||||||
IDataObject,
|
IDataObject,
|
||||||
IDeferredPromise,
|
IDeferredPromise,
|
||||||
IExecuteWorkflowInfo,
|
IExecuteWorkflowInfo,
|
||||||
|
IHttpRequestHelper,
|
||||||
IHttpRequestOptions,
|
IHttpRequestOptions,
|
||||||
|
INode,
|
||||||
INodeCredentialsDetails,
|
INodeCredentialsDetails,
|
||||||
INodeExecutionData,
|
INodeExecutionData,
|
||||||
INodeParameters,
|
INodeParameters,
|
||||||
|
@ -33,6 +35,17 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||||
return requestParams;
|
return requestParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async preAuthentication(
|
||||||
|
helpers: IHttpRequestHelper,
|
||||||
|
credentials: ICredentialDataDecryptedObject,
|
||||||
|
typeName: string,
|
||||||
|
node: INode,
|
||||||
|
credentialsExpired: boolean,
|
||||||
|
): Promise<ICredentialDataDecryptedObject | undefined> {
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
getParentTypes(name: string): string[] {
|
getParentTypes(name: string): string[] {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -639,10 +639,11 @@ export default mixins(showMessage, nodeHelpers).extend({
|
||||||
|
|
||||||
if (this.isCredentialTestable) {
|
if (this.isCredentialTestable) {
|
||||||
this.isTesting = true;
|
this.isTesting = true;
|
||||||
|
|
||||||
// Add the full data including defaults for testing
|
// Add the full data including defaults for testing
|
||||||
credentialDetails.data = this.credentialData;
|
credentialDetails.data = this.credentialData;
|
||||||
|
|
||||||
|
credentialDetails.id = this.credentialId;
|
||||||
|
|
||||||
await this.testCredential(credentialDetails);
|
await this.testCredential(credentialDetails);
|
||||||
this.isTesting = false;
|
this.isTesting = false;
|
||||||
}
|
}
|
||||||
|
|
76
packages/nodes-base/credentials/MetabaseApi.credentials.ts
Normal file
76
packages/nodes-base/credentials/MetabaseApi.credentials.ts
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
import {
|
||||||
|
IAuthenticateGeneric,
|
||||||
|
ICredentialDataDecryptedObject,
|
||||||
|
ICredentialTestRequest,
|
||||||
|
ICredentialType,
|
||||||
|
IHttpRequestHelper,
|
||||||
|
INodeProperties,
|
||||||
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
export class MetabaseApi implements ICredentialType {
|
||||||
|
name = 'metabaseApi';
|
||||||
|
displayName = 'Metabase API';
|
||||||
|
documentationUrl = 'metabase';
|
||||||
|
properties: INodeProperties[] = [
|
||||||
|
{
|
||||||
|
displayName: 'Session Token',
|
||||||
|
name: 'sessionToken',
|
||||||
|
type: 'hidden',
|
||||||
|
typeOptions: {
|
||||||
|
expirable: true,
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'URL',
|
||||||
|
name: 'url',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Username',
|
||||||
|
name: 'username',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Password',
|
||||||
|
name: 'password',
|
||||||
|
type: 'string',
|
||||||
|
typeOptions: {
|
||||||
|
password: true,
|
||||||
|
},
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// method will only be called if "sessionToken" (the expirable property)
|
||||||
|
// is empty or is expired
|
||||||
|
async preAuthentication(this: IHttpRequestHelper, credentials: ICredentialDataDecryptedObject) {
|
||||||
|
// make reques to get session token
|
||||||
|
const url = credentials.url as string;
|
||||||
|
const { id } = (await this.helpers.httpRequest({
|
||||||
|
method: 'POST',
|
||||||
|
url: `${url.endsWith('/') ? url.slice(0, -1) : url}/api/session`,
|
||||||
|
body: {
|
||||||
|
username: credentials.username,
|
||||||
|
password: credentials.password,
|
||||||
|
},
|
||||||
|
})) as { id: string };
|
||||||
|
return { sessionToken: id };
|
||||||
|
}
|
||||||
|
authenticate: IAuthenticateGeneric = {
|
||||||
|
type: 'generic',
|
||||||
|
properties: {
|
||||||
|
headers: {
|
||||||
|
'X-Metabase-Session': '={{$credentials.sessionToken}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
test: ICredentialTestRequest = {
|
||||||
|
request: {
|
||||||
|
baseURL: '={{$credentials?.url}}',
|
||||||
|
url: '/api/user/current',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -183,6 +183,7 @@
|
||||||
"dist/credentials/MediumApi.credentials.js",
|
"dist/credentials/MediumApi.credentials.js",
|
||||||
"dist/credentials/MediumOAuth2Api.credentials.js",
|
"dist/credentials/MediumOAuth2Api.credentials.js",
|
||||||
"dist/credentials/MessageBirdApi.credentials.js",
|
"dist/credentials/MessageBirdApi.credentials.js",
|
||||||
|
"dist/credentials/MetabaseApi.credentials.js",
|
||||||
"dist/credentials/MicrosoftDynamicsOAuth2Api.credentials.js",
|
"dist/credentials/MicrosoftDynamicsOAuth2Api.credentials.js",
|
||||||
"dist/credentials/MicrosoftExcelOAuth2Api.credentials.js",
|
"dist/credentials/MicrosoftExcelOAuth2Api.credentials.js",
|
||||||
"dist/credentials/MicrosoftGraphSecurityOAuth2Api.credentials.js",
|
"dist/credentials/MicrosoftGraphSecurityOAuth2Api.credentials.js",
|
||||||
|
|
|
@ -166,6 +166,9 @@ export interface IRequestOptionsSimplifiedAuth {
|
||||||
skipSslCertificateValidation?: boolean | string;
|
skipSslCertificateValidation?: boolean | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IHttpRequestHelper {
|
||||||
|
helpers: { httpRequest: IAllExecuteFunctions['helpers']['httpRequest'] };
|
||||||
|
}
|
||||||
export abstract class ICredentialsHelper {
|
export abstract class ICredentialsHelper {
|
||||||
encryptionKey: string;
|
encryptionKey: string;
|
||||||
|
|
||||||
|
@ -184,6 +187,14 @@ export abstract class ICredentialsHelper {
|
||||||
defaultTimezone: string,
|
defaultTimezone: string,
|
||||||
): Promise<IHttpRequestOptions>;
|
): Promise<IHttpRequestOptions>;
|
||||||
|
|
||||||
|
abstract preAuthentication(
|
||||||
|
helpers: IHttpRequestHelper,
|
||||||
|
credentials: ICredentialDataDecryptedObject,
|
||||||
|
typeName: string,
|
||||||
|
node: INode,
|
||||||
|
credentialsExpired: boolean,
|
||||||
|
): Promise<ICredentialDataDecryptedObject | undefined>;
|
||||||
|
|
||||||
abstract getCredentials(
|
abstract getCredentials(
|
||||||
nodeCredentials: INodeCredentialsDetails,
|
nodeCredentials: INodeCredentialsDetails,
|
||||||
type: string,
|
type: string,
|
||||||
|
@ -269,6 +280,10 @@ export interface ICredentialType {
|
||||||
documentationUrl?: string;
|
documentationUrl?: string;
|
||||||
__overwrittenProperties?: string[];
|
__overwrittenProperties?: string[];
|
||||||
authenticate?: IAuthenticate;
|
authenticate?: IAuthenticate;
|
||||||
|
preAuthentication?: (
|
||||||
|
this: IHttpRequestHelper,
|
||||||
|
credentials: ICredentialDataDecryptedObject,
|
||||||
|
) => Promise<IDataObject>;
|
||||||
test?: ICredentialTestRequest;
|
test?: ICredentialTestRequest;
|
||||||
genericAuth?: boolean;
|
genericAuth?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -894,6 +909,7 @@ export interface INodePropertyTypeOptions {
|
||||||
rows?: number; // Supported by: string
|
rows?: number; // Supported by: string
|
||||||
showAlpha?: boolean; // Supported by: color
|
showAlpha?: boolean; // Supported by: color
|
||||||
sortable?: boolean; // Supported when "multipleValues" set to true
|
sortable?: boolean; // Supported when "multipleValues" set to true
|
||||||
|
expirable?: boolean; // Supported by: hidden (only in the credentials)
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
IExecuteResponsePromiseData,
|
IExecuteResponsePromiseData,
|
||||||
IExecuteSingleFunctions,
|
IExecuteSingleFunctions,
|
||||||
IExecuteWorkflowInfo,
|
IExecuteWorkflowInfo,
|
||||||
|
IHttpRequestHelper,
|
||||||
IHttpRequestOptions,
|
IHttpRequestOptions,
|
||||||
IN8nHttpFullResponse,
|
IN8nHttpFullResponse,
|
||||||
IN8nHttpResponse,
|
IN8nHttpResponse,
|
||||||
|
@ -111,6 +112,16 @@ export class CredentialsHelper extends ICredentialsHelper {
|
||||||
return requestParams;
|
return requestParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async preAuthentication(
|
||||||
|
helpers: IHttpRequestHelper,
|
||||||
|
credentials: ICredentialDataDecryptedObject,
|
||||||
|
typeName: string,
|
||||||
|
node: INode,
|
||||||
|
credentialsExpired: boolean,
|
||||||
|
): Promise<{ updatedCredentials: boolean; data: ICredentialDataDecryptedObject }> {
|
||||||
|
return { updatedCredentials: false, data: {} }
|
||||||
|
};
|
||||||
|
|
||||||
getParentTypes(name: string): string[] {
|
getParentTypes(name: string): string[] {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue