n8n/packages/cli/test/CredentialsHelper.test.ts
Jan Oberhauser 0da398b0e4
Nodes as JSON and authentication redesign (#2401)
*  change FE to handle new object type

* 🚸 improve UX of handling invalid credentials

* 🚧 WIP

* 🎨 fix typescript issues

* 🐘 add migrations for all supported dbs

* ✏️ add description to migrations

*  add credential update on import

*  resolve after merge issues

* 👕 fix lint issues

*  check credentials on workflow create/update

* update interface

* 👕 fix ts issues

*  adaption to new credentials UI

* 🐛 intialize cache on BE for credentials check

* 🐛 fix undefined oldCredentials

* 🐛 fix deleting credential

* 🐛 fix check for undefined keys

* 🐛 fix disabling edit in execution

* 🎨 just show credential name on execution view

* ✏️  remove TODO

*  implement review suggestions

*  add cache to getCredentialsByType

*  use getter instead of cache

* ✏️ fix variable name typo

* 🐘 include waiting nodes to migrations

* 🐛 fix reverting migrations command

*  update typeorm command

*  create db:revert command

* 👕 fix lint error

*  Add optional authenticate method to credentials

*  Simplify code and add authentication support to MattermostApi

* 👕 Fix lint issue

*  Add support to own-mode

* 👕 Fix lint issue

*  Add support for predefined auth types bearer and headerAuth

*  Make sure that DateTime Node always returns strings

*  Add support for moment types to If Node

*  Make it possible for HTTP Request Node to use all credential types

*  Add basicAuth support

* Add a new dropcontact node

*  First basic implementation of mainly JSON based nodes

*  Add fixedCollection support, added value parameter and
expression support for value and property

* Improvements to #2389

*  Add credentials verification

*  Small improvement

*  set default time to 45 seconds

*  Add support for preSend and postReceive methods

*  Add lodash merge and set depedency to workflow

* 👕 Fix lint issue

*  Improvements

*  Improvements

*  Improvements

*  Improvements

*  Improvements

* 🐛 Set siren and language correctly

*  Add support for requestDefaults

*  Add support for baseURL to httpRequest

*  Move baseURL to correct location

*  Add support for options loading

* 🐛 Fix error with fullAccess nodes

*  Add credential test functionality

* 🐛 Fix issue with OAuth autentication and lint issue

*  Fix build issue

* 🐛 Fix issue that url got always overwritten to empty

*  Add pagination support

*  Code fix required after merge

*  Remove not needed imports

*  Fix credential test

*  Add expression support for request properties and $self
support on properties

*  Rename $self to $value

* 👕 Fix lint issue

*  Add example how to send data in path

*  Make it possible to not sent in dot notation

*  Add support for postReceive:rootProperty

*  Fix typo

*  Add support for postReceive:set

*  Some fixes

*  Small improvement

* ;zap: Separate RoutingNode code

*  Simplify code and fix bug

*  Remove unused code

*  Make it possible to define "request" and "requestProperty" on
options

* 👕 Fix lint issue

*  Change $credentials variables name

*  Enable expressions and access to credentials in requestDefaults

*  Make parameter option loading use RoutingNode.makeRoutingRequest

*  Allow requestOperations overwrite on LoadOptions

*  Make it possible to access current node parameters in loadOptions

*  Rename parameters variable to make future proof

*  Make it possible to use offset-pagination with body

*  Add support for queryAuth

*  Never return more items than requested

*  Make it possible to overwrite requestOperations on parameter
and option level

* 👕 Fix lint issue

*  Allow simplified auth also with regular nodes

*  Add support for receiving binary data

* 🐛 Fix example node

*  Rename property "name" to "displayName" in loadOptions

*  Send data by default as "query" if nothing is set

*  Rename $self to $parent

*  Change to work with INodeExecutionData instead of IDataObject

*  Improve binaryData handling

*  Property design improvements

*  Fix property name

* 🚨 Add some tests

*  Add also test for request

*  Improve test and fix issues

*  Improvements to loadOptions

*  Normalize loadOptions with rest of code

*  Add info text

*  Add support for $value in postReceive

* 🚨 Add tests for RoutingNode.runNode

*  Remove TODOs and make url property optional

*  Fix bug and lint issue

* 🐛 Fix bug that not the correct property got used

* 🚨 Add tests for CredentialsHelper.authenticate

*  Improve code and resolve expressions also everywhere for
loadOptions and credential test requests

*  Make it possible to define multiple preSend and postReceive
actions

*  Allow to define tests on credentials

*  Remove test data

* ⬆️ Update package-lock.json file

*  Remove old not longer used code

Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
Co-authored-by: Mutasem <mutdmour@gmail.com>
Co-authored-by: PaulineDropcontact <pauline@dropcontact.io>
Co-authored-by: ricardo <ricardoespinoza105@gmail.com>
2022-02-05 22:55:43 +01:00

306 lines
6.9 KiB
TypeScript

import { CredentialsHelper, CredentialTypes } from '../src';
import * as Helpers from './Helpers';
import {
IAuthenticateBasicAuth,
IAuthenticateBearer,
IAuthenticateHeaderAuth,
IAuthenticateQueryAuth,
ICredentialDataDecryptedObject,
ICredentialType,
ICredentialTypeData,
IHttpRequestOptions,
INode,
INodeProperties,
Workflow,
} from 'n8n-workflow';
const TEST_ENCRYPTION_KEY = 'test';
describe('CredentialsHelper', () => {
describe('authenticate', () => {
const tests: Array<{
description: string;
input: {
credentials: ICredentialDataDecryptedObject;
credentialType: ICredentialType;
};
output: IHttpRequestOptions;
}> = [
{
description: 'built-in basicAuth, default property names',
input: {
credentials: {
user: 'user1',
password: 'password1',
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'User',
name: 'user',
type: 'string',
default: '',
},
{
displayName: 'Password',
name: 'password',
type: 'string',
default: '',
},
];
authenticate = {
type: 'basicAuth',
properties: {},
} as IAuthenticateBasicAuth;
})(),
},
output: {
url: '',
headers: {},
auth: { username: 'user1', password: 'password1' },
qs: {},
},
},
{
description: 'built-in basicAuth, custom property names',
input: {
credentials: {
customUser: 'user2',
customPassword: 'password2',
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'User',
name: 'user',
type: 'string',
default: '',
},
{
displayName: 'Password',
name: 'password',
type: 'string',
default: '',
},
];
authenticate = {
type: 'basicAuth',
properties: {
userPropertyName: 'customUser',
passwordPropertyName: 'customPassword',
},
} as IAuthenticateBasicAuth;
})(),
},
output: {
url: '',
headers: {},
auth: { username: 'user2', password: 'password2' },
qs: {},
},
},
{
description: 'built-in headerAuth',
input: {
credentials: {
accessToken: 'test',
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'Access Token',
name: 'accessToken',
type: 'string',
default: '',
},
];
authenticate = {
type: 'headerAuth',
properties: {
name: 'Authorization',
value: '=Bearer {{$credentials.accessToken}}',
},
} as IAuthenticateHeaderAuth;
})(),
},
output: { url: '', headers: { Authorization: 'Bearer test' }, qs: {} },
},
{
description: 'built-in bearer, default property name',
input: {
credentials: {
accessToken: 'test',
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'Access Token',
name: 'accessToken',
type: 'string',
default: '',
},
];
authenticate = {
type: 'bearer',
properties: {},
} as IAuthenticateBearer;
})(),
},
output: { url: '', headers: { Authorization: 'Bearer test' }, qs: {} },
},
{
description: 'built-in bearer, custom property name',
input: {
credentials: {
myToken: 'test',
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'My Token',
name: 'myToken',
type: 'string',
default: '',
},
];
authenticate = {
type: 'bearer',
properties: {
tokenPropertyName: 'myToken',
},
} as IAuthenticateBearer;
})(),
},
output: { url: '', headers: { Authorization: 'Bearer test' }, qs: {} },
},
{
description: 'built-in queryAuth',
input: {
credentials: {
accessToken: 'test',
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'Access Token',
name: 'accessToken',
type: 'string',
default: '',
},
];
authenticate = {
type: 'queryAuth',
properties: {
key: 'accessToken',
value: '={{$credentials.accessToken}}',
},
} as IAuthenticateQueryAuth;
})(),
},
output: { url: '', headers: {}, qs: { accessToken: 'test' } },
},
{
description: 'custom authentication',
input: {
credentials: {
accessToken: 'test',
user: 'testUser',
},
credentialType: new (class TestApi implements ICredentialType {
name = 'testApi';
displayName = 'Test API';
properties: INodeProperties[] = [
{
displayName: 'My Token',
name: 'myToken',
type: 'string',
default: '',
},
];
async authenticate(
credentials: ICredentialDataDecryptedObject,
requestOptions: IHttpRequestOptions,
): Promise<IHttpRequestOptions> {
requestOptions.headers!['Authorization'] = `Bearer ${credentials.accessToken}`;
requestOptions.qs!['user'] = credentials.user;
return requestOptions;
}
})(),
},
output: {
url: '',
headers: { Authorization: 'Bearer test' },
qs: { user: 'testUser' },
},
},
];
const node: INode = {
parameters: {},
name: 'test',
type: 'test.set',
typeVersion: 1,
position: [0, 0],
};
const incomingRequestOptions = {
url: '',
headers: {},
qs: {},
};
const nodeTypes = Helpers.NodeTypes();
const workflow = new Workflow({
nodes: [node],
connections: {},
active: false,
nodeTypes,
});
for (const testData of tests) {
test(testData.description, async () => {
const credentialTypes: ICredentialTypeData = {
[testData.input.credentialType.name]: {
type: testData.input.credentialType,
sourcePath: '',
},
};
await CredentialTypes().init(credentialTypes);
const credentialsHelper = new CredentialsHelper(TEST_ENCRYPTION_KEY);
const result = await credentialsHelper.authenticate(
testData.input.credentials,
testData.input.credentialType.name,
JSON.parse(JSON.stringify(incomingRequestOptions)),
workflow,
node,
);
expect(result).toEqual(testData.output);
});
}
});
});