Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

N8N-4126 credentials injection and testing on specific nodes #3816

Merged
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
034e0d2
Add cred injection and cred testing
agobrech Jul 19, 2022
94bba72
Add cred injection, cred testing
agobrech Jul 19, 2022
a261fb0
add cred injection, cred testing to supabase
agobrech Jul 19, 2022
d645116
✨ Add cred injection and moved cred testing for dropcontact
agobrech Jul 19, 2022
1ec38b6
🔥 Removed old cred testing method
agobrech Jul 19, 2022
049b1fa
Add cred injection, cred testing to lemlist
agobrech Jul 19, 2022
39d7bb6
🔥 remove log message
agobrech Jul 19, 2022
3c9ce5b
✨ Add cred injection to segment
agobrech Jul 19, 2022
f686f04
Add cred injection for uproc
agobrech Jul 19, 2022
eae4342
Merge branch 'master' into n8n-4126-credentials-injection-and-testing…
agobrech Aug 2, 2022
9436987
🎨 Fix format issue
agobrech Aug 2, 2022
1e2403a
Merge branch 'master' into n8n-4126-credentials-injection-and-testing…
agobrech Aug 4, 2022
8e40e99
Merge branch 'master' into n8n-4126-credentials-injection-and-testing…
agobrech Aug 10, 2022
9cd5010
✨ Add credential injection to AWS Lambda
agobrech Aug 10, 2022
0ac510e
✨ Add credentials injection to S3 AWS
agobrech Aug 10, 2022
1318711
✨ Add S3 SES Textract credentials injection
agobrech Aug 10, 2022
5be7c8a
⏪ Revert "✨ Add credential injection to AWS Lambda"
agobrech Aug 17, 2022
58fab55
🐛 Fix a bug where wrong endpoint was being use for testing
agobrech Aug 17, 2022
de9fa4b
🐛 Improved testing for uproc
agobrech Aug 17, 2022
e1f0ea7
Merge branch 'master' into n8n-4126-credentials-injection-and-testing…
agobrech Aug 23, 2022
aa6b66b
Revert "✨ Add credentials injection to S3 AWS"
agobrech Aug 23, 2022
2174fb6
Revert "✨ Add S3 SES Textract credentials injection"
agobrech Aug 23, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion packages/nodes-base/credentials/Aws.credentials.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ICredentialType, INodeProperties } from 'n8n-workflow';
import {Request, sign } from 'aws4';
import { IHttpRequestMethods } from 'n8n-workflow';
import { ICredentialDataDecryptedObject, ICredentialType, IDataObject, IHttpRequestOptions, INodeProperties } from 'n8n-workflow';

export const regions = [
{
Expand Down Expand Up @@ -259,4 +261,64 @@ export class Aws implements ICredentialType {
placeholder: 'https://s3.{region}.amazonaws.com',
},
];


async authenticate(credentials: ICredentialDataDecryptedObject, requestOptions: IHttpRequestOptions): Promise<IHttpRequestOptions> {
let endpoint;
const service = requestOptions.qs?.service;
let path = requestOptions.qs?.path;
const method = requestOptions.method;
const body = requestOptions.body;
const region = credentials.region;
const query = requestOptions.qs?.query as IDataObject;

if (service === 'lambda' && credentials.lambdaEndpoint) {
endpoint = credentials.lambdaEndpoint;
} else if (service === 'sns' && credentials.snsEndpoint) {
agobrech marked this conversation as resolved.
Show resolved Hide resolved
endpoint = credentials.snsEndpoint;
} else if (service === 'sqs' && credentials.sqsEndpoint) {
agobrech marked this conversation as resolved.
Show resolved Hide resolved
endpoint = credentials.sqsEndpoint;
} else if (service === 's3' && credentials.s3Endpoint) {
endpoint = credentials.s3Endpoint;
}
else if (service === 'ses' && credentials.sesEndpoint) {
agobrech marked this conversation as resolved.
Show resolved Hide resolved
endpoint = credentials.sesEndpoint;
}
else if (service === 'rekognition' && credentials.rekognitionEndpoint) {
endpoint = credentials.rekognitionEndpoint;
}
else if (service === 'sqs' && credentials.sqsEndpoint) {
endpoint = credentials.sqsEndpoint;
}
else {
console.log('ERROR SQS ', service);
agobrech marked this conversation as resolved.
Show resolved Hide resolved
endpoint = `https://${service}.${credentials.region}.amazonaws.com`;
}
endpoint = new URL((endpoint as string).replace('{region}', credentials.region as string));

if(service === 's3' && credentials.s3Endpoint) {
path = `${endpoint.pathname}?${queryToString(query).replace(/\+/g, '%2B')}`;
}
const signOpts = { headers: requestOptions.headers, host: endpoint.host, method, path, body, region} as Request;
const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials ? `${credentials.sessionToken}`.trim() : undefined,
};

sign(signOpts, securityHeaders);
const options: IHttpRequestOptions = {
headers: signOpts.headers,
method,
url: endpoint.href + path,
body: signOpts.body,
};
return options;
}
}

function queryToString(params: IDataObject) {
return Object.keys(params)
.map((key) => key + '=' + params[key])
.join('&');
}
26 changes: 25 additions & 1 deletion packages/nodes-base/credentials/DropcontactApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { ICredentialType, NodePropertyTypes } from 'n8n-workflow';
import {
IAuthenticateGeneric,
ICredentialTestRequest,
ICredentialType,
NodePropertyTypes,
} from 'n8n-workflow';

export class DropcontactApi implements ICredentialType {
name = 'dropcontactApi';
Expand All @@ -12,4 +17,23 @@ export class DropcontactApi implements ICredentialType {
default: '',
},
];
authenticate: IAuthenticateGeneric = {
type: 'generic',
properties: {
headers: {
'user-agent': 'n8n',
'X-Access-Token': '={{$credentials.apiKey}}',
},
},
};
test: ICredentialTestRequest = {
request: {
baseURL: 'https://api.dropcontact.io',
url: '/batch',
method: 'POST',
body: {
data: [{ email: '' }],
},
},
};
}
23 changes: 22 additions & 1 deletion packages/nodes-base/credentials/LemlistApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { ICredentialType, INodeProperties } from 'n8n-workflow';
import {
ICredentialDataDecryptedObject,
ICredentialTestRequest,
ICredentialType,
IHttpRequestOptions,
INodeProperties,
} from 'n8n-workflow';

export class LemlistApi implements ICredentialType {
name = 'lemlistApi';
Expand All @@ -12,4 +18,19 @@ export class LemlistApi implements ICredentialType {
default: '',
},
];
async authenticate(
credentials: ICredentialDataDecryptedObject,
requestOptions: IHttpRequestOptions,
): Promise<IHttpRequestOptions> {
const encodedApiKey = Buffer.from(':' + credentials.apiKey).toString('base64');
requestOptions.headers!['Authorization'] = `Basic ${encodedApiKey}`;
requestOptions.headers!['user-agent'] = 'n8n';
krynble marked this conversation as resolved.
Show resolved Hide resolved
return requestOptions;
}
test: ICredentialTestRequest = {
request: {
baseURL: 'https://api.lemlist.com/api',
url: '/campaigns',
},
};
}
22 changes: 21 additions & 1 deletion packages/nodes-base/credentials/MailgunApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { ICredentialType, INodeProperties } from 'n8n-workflow';
import {
IAuthenticateGeneric,
ICredentialTestRequest,
ICredentialType,
INodeProperties,
} from 'n8n-workflow';

export class MailgunApi implements ICredentialType {
name = 'mailgunApi';
Expand Down Expand Up @@ -35,4 +40,19 @@ export class MailgunApi implements ICredentialType {
default: '',
},
];
authenticate: IAuthenticateGeneric = {
type: 'generic',
properties: {
auth: {
username: 'api',
password: '={{$credentials.apiKey}}',
},
},
};
test: ICredentialTestRequest = {
request: {
baseURL: '=https://{{$credentials.apiDomain}}/v3',
url: '/domains',
},
};
}
21 changes: 20 additions & 1 deletion packages/nodes-base/credentials/PhantombusterApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { ICredentialType, INodeProperties } from 'n8n-workflow';
import {
IAuthenticateGeneric,
ICredentialTestRequest,
ICredentialType,
INodeProperties,
} from 'n8n-workflow';

export class PhantombusterApi implements ICredentialType {
name = 'phantombusterApi';
Expand All @@ -12,4 +17,18 @@ export class PhantombusterApi implements ICredentialType {
default: '',
},
];
authenticate: IAuthenticateGeneric = {
type: 'generic',
properties: {
headers: {
'X-Phantombuster-Key': '={{$credentials.apiKey}}',
},
},
};
test: ICredentialTestRequest = {
request: {
baseURL: 'https://api.phantombuster.com/api/v2',
url: '/agents/fetch-all',
},
};
}
15 changes: 14 additions & 1 deletion packages/nodes-base/credentials/SegmentApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { ICredentialType, INodeProperties } from 'n8n-workflow';
import {
ICredentialDataDecryptedObject,
ICredentialType,
IHttpRequestOptions,
INodeProperties,
} from 'n8n-workflow';

export class SegmentApi implements ICredentialType {
name = 'segmentApi';
Expand All @@ -12,4 +17,12 @@ export class SegmentApi implements ICredentialType {
default: '',
},
];
async authenticate(
credentials: ICredentialDataDecryptedObject,
requestOptions: IHttpRequestOptions,
): Promise<IHttpRequestOptions> {
const base64Key = Buffer.from(`${credentials.writekey}:`).toString('base64');
requestOptions.headers!['Authorization'] = `Basic ${base64Key}`;
return requestOptions;
}
}
25 changes: 24 additions & 1 deletion packages/nodes-base/credentials/SupabaseApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { ICredentialType, INodeProperties } from 'n8n-workflow';
import {
IAuthenticateGeneric,
ICredentialTestRequest,
ICredentialType,
INodeProperties,
} from 'n8n-workflow';

export class SupabaseApi implements ICredentialType {
name = 'supabaseApi';
Expand All @@ -19,4 +24,22 @@ export class SupabaseApi implements ICredentialType {
default: '',
},
];
authenticate: IAuthenticateGeneric = {
type: 'generic',
properties: {
headers: {
apikey: '={{$credentials.serviceRole}}',
Authorization: '=Bearer {{$credentials.serviceRole}}',
},
},
};
test: ICredentialTestRequest = {
request: {
baseURL: '={{$credentials.host}}/rest/v1',
headers: {
Prefer: 'return=representation',
},
url: '/',
},
};
}
22 changes: 21 additions & 1 deletion packages/nodes-base/credentials/UProcApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { ICredentialType, INodeProperties } from 'n8n-workflow';
import {
ICredentialDataDecryptedObject,
ICredentialTestRequest,
ICredentialType,
IHttpRequestOptions,
INodeProperties,
} from 'n8n-workflow';

export class UProcApi implements ICredentialType {
name = 'uprocApi';
Expand All @@ -19,4 +25,18 @@ export class UProcApi implements ICredentialType {
default: '',
},
];
async authenticate(
credentials: ICredentialDataDecryptedObject,
requestOptions: IHttpRequestOptions,
): Promise<IHttpRequestOptions> {
const token = Buffer.from(`${credentials.email}:${credentials.apiKey}`).toString('base64');
requestOptions.headers!['Authorization'] = `Basic ${token}`;
return requestOptions;
}
test: ICredentialTestRequest = {
request: {
baseURL: 'https://api.uproc.io/api/v2/process',
agobrech marked this conversation as resolved.
Show resolved Hide resolved
url: '/me',
},
};
}
45 changes: 18 additions & 27 deletions packages/nodes-base/nodes/Aws/DynamoDB/GenericFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { URL } from 'url';

import { sign } from 'aws4';

import {
IExecuteFunctions,
IHookFunctions,
ILoadOptionsFunctions,
IWebhookFunctions,
} from 'n8n-core';

import { ICredentialDataDecryptedObject, IDataObject, INodeExecutionData } from 'n8n-workflow';
import {
ICredentialDataDecryptedObject,
IDataObject,
IHttpRequestOptions,
INodeExecutionData,
} from 'n8n-workflow';

import { IRequestBody } from './types';

Expand Down Expand Up @@ -38,32 +39,22 @@ export async function awsApiRequest(
// tslint:disable-next-line:no-any
): Promise<any> {
const credentials = await this.getCredentials('aws');

// Concatenate path and instantiate URL object so it parses correctly query strings
const endpoint = new URL(getEndpointForService(service, credentials) + path);
const securityHeaders = {
accessKeyId: `${credentials.accessKeyId}`.trim(),
secretAccessKey: `${credentials.secretAccessKey}`.trim(),
sessionToken: credentials.temporaryCredentials
? `${credentials.sessionToken}`.trim()
: undefined,
};
const options = sign(
{
// @ts-ignore
uri: endpoint,
const requestOptions = {
qs: {
service,
region: credentials.region as string,
method,
path: '/',
headers: { ...headers },
body: JSON.stringify(body),
path,
},
securityHeaders,
);
method,
body: JSON.stringify(body),
url: '',
headers,
region: credentials?.region as string,
} as IHttpRequestOptions;

try {
return JSON.parse(await this.helpers.request!(options));
return JSON.parse(
await this.helpers.requestWithAuthentication.call(this, 'aws', requestOptions),
);
} catch (error) {
const errorMessage =
(error.response && error.response.body && error.response.body.message) ||
Expand Down
Loading