mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 21:07:28 -08:00
N8N-4126 credentials injection and testing on specific nodes (#3816)
* Add credential injection and testing to Lemlist, Uproc, Supabase, Segment, Phantombuster, Mailgun and Dropcontact
This commit is contained in:
parent
5285fc1de6
commit
76f9ad8bae
|
@ -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';
|
||||
|
@ -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: '' }],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
@ -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';
|
||||
return requestOptions;
|
||||
}
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.lemlist.com/api',
|
||||
url: '/campaigns',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
@ -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',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
@ -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',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
@ -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: '/',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
@ -19,4 +25,22 @@ 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 = {
|
||||
...requestOptions.headers,
|
||||
Authorization: `Basic ${token}`,
|
||||
};
|
||||
return requestOptions;
|
||||
}
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: 'https://api.uproc.io/api/v2',
|
||||
url: '/profile',
|
||||
method: 'GET',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
NodeApiError,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import { dropcontactApiRequest, validateCredentials } from './GenericFunction';
|
||||
import { dropcontactApiRequest } from './GenericFunction';
|
||||
|
||||
export class Dropcontact implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
|
@ -32,7 +32,6 @@ export class Dropcontact implements INodeType {
|
|||
{
|
||||
name: 'dropcontactApi',
|
||||
required: true,
|
||||
testedBy: 'dropcontactApiCredentialTest',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
@ -244,30 +243,6 @@ export class Dropcontact implements INodeType {
|
|||
},
|
||||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
credentialTest: {
|
||||
async dropcontactApiCredentialTest(
|
||||
this: ICredentialTestFunctions,
|
||||
credential: ICredentialsDecrypted,
|
||||
): Promise<INodeCredentialTestResult> {
|
||||
try {
|
||||
await validateCredentials.call(this, credential.data as ICredentialDataDecryptedObject);
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 'Error',
|
||||
message: 'The API Key included in the request is invalid',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'OK',
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const entryData = this.getInputData();
|
||||
const resource = this.getNodeParameter('resource', 0) as string;
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import { IExecuteFunctions, IHookFunctions } from 'n8n-core';
|
||||
|
||||
import {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialTestFunctions,
|
||||
IDataObject,
|
||||
ILoadOptionsFunctions,
|
||||
NodeApiError,
|
||||
} from 'n8n-workflow';
|
||||
import { IDataObject, ILoadOptionsFunctions, NodeApiError } from 'n8n-workflow';
|
||||
|
||||
import { OptionsWithUri } from 'request';
|
||||
|
||||
|
@ -20,15 +14,7 @@ export async function dropcontactApiRequest(
|
|||
body: IDataObject,
|
||||
qs: IDataObject,
|
||||
) {
|
||||
const { apiKey } = (await this.getCredentials('dropcontactApi')) as {
|
||||
apiKey: string;
|
||||
};
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
'user-agent': 'n8n',
|
||||
'X-Access-Token': apiKey,
|
||||
},
|
||||
method,
|
||||
uri: `https://api.dropcontact.io${endpoint}`,
|
||||
qs,
|
||||
|
@ -45,35 +31,8 @@ export async function dropcontactApiRequest(
|
|||
}
|
||||
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
return await this.helpers.requestWithAuthentication.call(this, 'dropcontactApi', options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function validateCredentials(
|
||||
this: ICredentialTestFunctions,
|
||||
decryptedCredentials: ICredentialDataDecryptedObject,
|
||||
// tslint:disable-next-line:no-any
|
||||
): Promise<any> {
|
||||
const credentials = decryptedCredentials;
|
||||
|
||||
const { apiKey } = credentials as {
|
||||
apiKey: string;
|
||||
};
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
'user-agent': 'n8n',
|
||||
'X-Access-Token': apiKey,
|
||||
},
|
||||
method: 'POST',
|
||||
body: {
|
||||
data: [{ email: '' }],
|
||||
},
|
||||
uri: `https://api.dropcontact.io/batch`,
|
||||
json: true,
|
||||
};
|
||||
|
||||
return this.helpers.request!(options);
|
||||
}
|
||||
|
|
|
@ -17,16 +17,9 @@ export async function lemlistApiRequest(
|
|||
qs: IDataObject = {},
|
||||
option: IDataObject = {},
|
||||
) {
|
||||
const { apiKey } = (await this.getCredentials('lemlistApi')) as {
|
||||
apiKey: string;
|
||||
};
|
||||
|
||||
const encodedApiKey = Buffer.from(':' + apiKey).toString('base64');
|
||||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
'user-agent': 'n8n',
|
||||
Authorization: `Basic ${encodedApiKey}`,
|
||||
},
|
||||
method,
|
||||
uri: `https://api.lemlist.com/api${endpoint}`,
|
||||
|
@ -48,7 +41,7 @@ export async function lemlistApiRequest(
|
|||
}
|
||||
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
return await this.helpers.requestWithAuthentication.call(this,'lemlistApi',options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error);
|
||||
}
|
||||
|
|
|
@ -173,17 +173,13 @@ export class Mailgun implements INodeType {
|
|||
method: 'POST',
|
||||
formData,
|
||||
uri: `https://${credentials.apiDomain}/v3/${credentials.emailDomain}/messages`,
|
||||
auth: {
|
||||
user: 'api',
|
||||
pass: credentials.apiKey as string,
|
||||
},
|
||||
json: true,
|
||||
};
|
||||
|
||||
let responseData;
|
||||
|
||||
try {
|
||||
responseData = await this.helpers.request(options);
|
||||
responseData = await this.helpers.requestWithAuthentication.call(this, 'mailgunApi', options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ export async function phantombusterApiRequest(
|
|||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
'X-Phantombuster-Key': credentials.apiKey,
|
||||
},
|
||||
method,
|
||||
body,
|
||||
|
@ -31,7 +30,7 @@ export async function phantombusterApiRequest(
|
|||
delete options.body;
|
||||
}
|
||||
//@ts-ignore
|
||||
return await this.helpers.request.call(this, options);
|
||||
return await this.helpers.requestWithAuthentication.call(this, 'phantombusterApi',options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error);
|
||||
}
|
||||
|
|
|
@ -17,18 +17,14 @@ export async function segmentApiRequest(
|
|||
| IWebhookFunctions,
|
||||
method: string,
|
||||
resource: string,
|
||||
// tslint:disable-next-line:no-any
|
||||
body: any = {},
|
||||
body: any = {}, // tslint:disable-line:no-any
|
||||
qs: IDataObject = {},
|
||||
uri?: string,
|
||||
option: IDataObject = {},
|
||||
// tslint:disable-next-line:no-any
|
||||
): Promise<any> {
|
||||
const credentials = await this.getCredentials('segmentApi');
|
||||
const base64Key = Buffer.from(`${credentials.writekey}:`).toString('base64');
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
Authorization: `Basic ${base64Key}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method,
|
||||
|
@ -41,7 +37,7 @@ export async function segmentApiRequest(
|
|||
delete options.body;
|
||||
}
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
return await this.helpers.requestWithAuthentication.call(this, 'segmentApi', options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error);
|
||||
}
|
||||
|
|
|
@ -39,8 +39,6 @@ export async function supabaseApiRequest(
|
|||
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
apikey: credentials.serviceRole,
|
||||
Authorization: 'Bearer ' + credentials.serviceRole,
|
||||
Prefer: 'return=representation',
|
||||
},
|
||||
method,
|
||||
|
@ -56,8 +54,8 @@ export async function supabaseApiRequest(
|
|||
if (Object.keys(body).length === 0) {
|
||||
delete options.body;
|
||||
}
|
||||
//@ts-ignore
|
||||
return await this.helpers?.request(options);
|
||||
return await this.helpers.requestWithAuthentication.call(this, 'supabaseApi', options);
|
||||
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error);
|
||||
}
|
||||
|
|
|
@ -7,34 +7,27 @@ import {
|
|||
ILoadOptionsFunctions,
|
||||
} from 'n8n-core';
|
||||
|
||||
import { IDataObject, NodeApiError, NodeOperationError } from 'n8n-workflow';
|
||||
import { IDataObject, IHttpRequestMethods, IHttpRequestOptions, NodeApiError } from 'n8n-workflow';
|
||||
|
||||
export async function uprocApiRequest(
|
||||
this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions,
|
||||
method: string,
|
||||
// tslint:disable-next-line:no-any
|
||||
body: any = {},
|
||||
body: any = {}, // tslint:disable-line:no-any
|
||||
qs: IDataObject = {},
|
||||
uri?: string,
|
||||
option: IDataObject = {},
|
||||
// tslint:disable-next-line:no-any
|
||||
): Promise<any> {
|
||||
const credentials = await this.getCredentials('uprocApi');
|
||||
const token = Buffer.from(`${credentials.email}:${credentials.apiKey}`).toString('base64');
|
||||
const options: OptionsWithUri = {
|
||||
headers: {
|
||||
Authorization: `Basic ${token}`,
|
||||
'User-agent': 'n8n',
|
||||
},
|
||||
method,
|
||||
const options: IHttpRequestOptions = {
|
||||
method: method as IHttpRequestMethods,
|
||||
qs,
|
||||
body,
|
||||
uri: uri || `https://api.uproc.io/api/v2/process`,
|
||||
url: 'https://api.uproc.io/api/v2/process',
|
||||
json: true,
|
||||
};
|
||||
|
||||
try {
|
||||
return await this.helpers.request!(options);
|
||||
return await this.helpers.httpRequestWithAuthentication.call(this, 'uprocApi', options);
|
||||
} catch (error) {
|
||||
throw new NodeApiError(this.getNode(), error);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue