mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 04:04:06 -08:00
feature: add database and non http credentials test
Add credential testing to Postgres, MySQL, MicrosoftSQL, Redis, FTP, SFTP, IMAP, RabbitMQ and MQTT Co-authored-by: Omar Ajoue <krynble@gmail.com>
This commit is contained in:
parent
b5511e5ac7
commit
d82e87979d
|
@ -3,8 +3,12 @@ import {
|
|||
createDeferredPromise,
|
||||
IBinaryData,
|
||||
IBinaryKeyData,
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialsDecrypted,
|
||||
ICredentialTestFunctions,
|
||||
IDataObject,
|
||||
IDeferredPromise,
|
||||
INodeCredentialTestResult,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
|
@ -43,6 +47,7 @@ export class EmailReadImap implements INodeType {
|
|||
{
|
||||
name: 'imap',
|
||||
required: true,
|
||||
testedBy: 'imapConnectionTest',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
@ -171,6 +176,51 @@ export class EmailReadImap implements INodeType {
|
|||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
credentialTest: {
|
||||
async imapConnectionTest(
|
||||
this: ICredentialTestFunctions,
|
||||
credential: ICredentialsDecrypted,
|
||||
): Promise<INodeCredentialTestResult> {
|
||||
const credentials = credential.data as ICredentialDataDecryptedObject;
|
||||
try {
|
||||
const config: ImapSimpleOptions = {
|
||||
imap: {
|
||||
user: credentials.user as string,
|
||||
password: credentials.password as string,
|
||||
host: credentials.host as string,
|
||||
port: credentials.port as number,
|
||||
tls: credentials.secure as boolean,
|
||||
authTimeout: 20000,
|
||||
},
|
||||
};
|
||||
const tlsOptions: IDataObject = {};
|
||||
|
||||
if (credentials.secure) {
|
||||
tlsOptions.servername = credentials.host as string;
|
||||
}
|
||||
if (!_.isEmpty(tlsOptions)) {
|
||||
config.imap.tlsOptions = tlsOptions;
|
||||
}
|
||||
const conn = imapConnect(config).then(async (conn) => {
|
||||
return conn;
|
||||
});
|
||||
(await conn).getBoxes((err, boxes) => {});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return {
|
||||
status: 'Error',
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'OK',
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async trigger(this: ITriggerFunctions): Promise<ITriggerResponse> {
|
||||
const credentials = await this.getCredentials('imap');
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import { IExecuteFunctions } from 'n8n-core';
|
||||
import {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialsDecrypted,
|
||||
ICredentialTestFunctions,
|
||||
IDataObject,
|
||||
INodeCredentialTestResult,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
|
@ -56,6 +59,7 @@ export class Ftp implements INodeType {
|
|||
protocol: ['ftp'],
|
||||
},
|
||||
},
|
||||
testedBy: 'ftpConnectionTest',
|
||||
},
|
||||
{
|
||||
// nodelinter-ignore-next-line
|
||||
|
@ -66,6 +70,7 @@ export class Ftp implements INodeType {
|
|||
protocol: ['sftp'],
|
||||
},
|
||||
},
|
||||
testedBy: 'sftpConnectionTest',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
@ -348,6 +353,63 @@ export class Ftp implements INodeType {
|
|||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
credentialTest: {
|
||||
async ftpConnectionTest(
|
||||
this: ICredentialTestFunctions,
|
||||
credential: ICredentialsDecrypted,
|
||||
): Promise<INodeCredentialTestResult> {
|
||||
const credentials = credential.data as ICredentialDataDecryptedObject;
|
||||
try {
|
||||
let ftp: ftpClient;
|
||||
ftp = new ftpClient();
|
||||
await ftp.connect({
|
||||
host: credentials.host as string,
|
||||
port: credentials.port as number,
|
||||
user: credentials.username as string,
|
||||
password: credentials.password as string,
|
||||
});
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 'Error',
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'OK',
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
},
|
||||
async sftpConnectionTest(
|
||||
this: ICredentialTestFunctions,
|
||||
credential: ICredentialsDecrypted,
|
||||
): Promise<INodeCredentialTestResult> {
|
||||
const credentials = credential.data as ICredentialDataDecryptedObject;
|
||||
try {
|
||||
let sftp: sftpClient;
|
||||
sftp = new sftpClient();
|
||||
await sftp.connect({
|
||||
host: credentials.host as string,
|
||||
port: credentials.port as number,
|
||||
username: credentials.username as string,
|
||||
password: credentials.password as string,
|
||||
privateKey: credentials.privateKey as string | undefined,
|
||||
passphrase: credentials.passphrase as string | undefined,
|
||||
});
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 'Error',
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'OK',
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
// const returnData: IDataObject[] = [];
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
import { IExecuteFunctions } from 'n8n-core';
|
||||
|
||||
import { IDataObject, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
|
||||
import {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialsDecrypted,
|
||||
ICredentialTestFunctions,
|
||||
IDataObject,
|
||||
INodeCredentialTestResult,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
import mqtt from 'mqtt';
|
||||
|
||||
|
@ -23,6 +32,7 @@ export class Mqtt implements INodeType {
|
|||
{
|
||||
name: 'mqtt',
|
||||
required: true,
|
||||
testedBy: 'mqttConnectionTest',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
@ -96,6 +106,83 @@ export class Mqtt implements INodeType {
|
|||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
credentialTest: {
|
||||
async mqttConnectionTest(
|
||||
this: ICredentialTestFunctions,
|
||||
credential: ICredentialsDecrypted,
|
||||
): Promise<INodeCredentialTestResult> {
|
||||
const credentials = credential.data as ICredentialDataDecryptedObject;
|
||||
try {
|
||||
const protocol = (credentials.protocol as string) || 'mqtt';
|
||||
const host = credentials.host as string;
|
||||
const brokerUrl = `${protocol}://${host}`;
|
||||
const port = (credentials.port as number) || 1883;
|
||||
const clientId =
|
||||
(credentials.clientId as string) || `mqttjs_${Math.random().toString(16).substr(2, 8)}`;
|
||||
const clean = credentials.clean as boolean;
|
||||
const ssl = credentials.ssl as boolean;
|
||||
const ca = credentials.ca as string;
|
||||
const cert = credentials.cert as string;
|
||||
const key = credentials.key as string;
|
||||
const rejectUnauthorized = credentials.rejectUnauthorized as boolean;
|
||||
|
||||
let client: mqtt.MqttClient;
|
||||
|
||||
if (ssl === false) {
|
||||
const clientOptions: IClientOptions = {
|
||||
port,
|
||||
clean,
|
||||
clientId,
|
||||
};
|
||||
|
||||
if (credentials.username && credentials.password) {
|
||||
clientOptions.username = credentials.username as string;
|
||||
clientOptions.password = credentials.password as string;
|
||||
}
|
||||
client = mqtt.connect(brokerUrl, clientOptions);
|
||||
} else {
|
||||
const clientOptions: IClientOptions = {
|
||||
port,
|
||||
clean,
|
||||
clientId,
|
||||
ca,
|
||||
cert,
|
||||
key,
|
||||
rejectUnauthorized,
|
||||
};
|
||||
if (credentials.username && credentials.password) {
|
||||
clientOptions.username = credentials.username as string;
|
||||
clientOptions.password = credentials.password as string;
|
||||
}
|
||||
|
||||
client = mqtt.connect(brokerUrl, clientOptions);
|
||||
}
|
||||
// tslint:disable-next-line: no-any
|
||||
await new Promise((resolve, reject): any => {
|
||||
client.on('connect', (test) => {
|
||||
resolve(test);
|
||||
client.end();
|
||||
});
|
||||
client.on('error', (error) => {
|
||||
client.end();
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 'Error',
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'OK',
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const length = items.length;
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import { IExecuteFunctions } from 'n8n-core';
|
||||
|
||||
import {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialsDecrypted,
|
||||
ICredentialTestFunctions,
|
||||
IDataObject,
|
||||
INodeCredentialTestResult,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
|
@ -42,6 +46,7 @@ export class MicrosoftSql implements INodeType {
|
|||
{
|
||||
name: 'microsoftSql',
|
||||
required: true,
|
||||
testedBy: 'microsoftSqlConnectionTest',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
@ -213,6 +218,44 @@ export class MicrosoftSql implements INodeType {
|
|||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
credentialTest: {
|
||||
async microsoftSqlConnectionTest(
|
||||
this: ICredentialTestFunctions,
|
||||
credential: ICredentialsDecrypted,
|
||||
): Promise<INodeCredentialTestResult> {
|
||||
const credentials = credential.data as ICredentialDataDecryptedObject;
|
||||
try {
|
||||
const config = {
|
||||
server: credentials.server as string,
|
||||
port: credentials.port as number,
|
||||
database: credentials.database as string,
|
||||
user: credentials.user as string,
|
||||
password: credentials.password as string,
|
||||
domain: credentials.domain ? (credentials.domain as string) : undefined,
|
||||
connectionTimeout: credentials.connectTimeout as number,
|
||||
requestTimeout: credentials.requestTimeout as number,
|
||||
options: {
|
||||
encrypt: credentials.tls as boolean,
|
||||
enableArithAbort: false,
|
||||
},
|
||||
};
|
||||
const pool = new mssql.ConnectionPool(config);
|
||||
await pool.connect();
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 'Error',
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'OK',
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const credentials = await this.getCredentials('microsoftSql');
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { IExecuteFunctions } from 'n8n-core';
|
||||
import {
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialsDecrypted,
|
||||
ICredentialTestFunctions,
|
||||
IDataObject,
|
||||
INodeCredentialTestResult,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
|
@ -10,6 +13,7 @@ import {
|
|||
import mysql2 from 'mysql2/promise';
|
||||
|
||||
import { copyInputItems } from './GenericFunctions';
|
||||
import { IExecuteFunctions } from 'n8n-core';
|
||||
|
||||
export class MySql implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
|
@ -28,6 +32,7 @@ export class MySql implements INodeType {
|
|||
{
|
||||
name: 'mySql',
|
||||
required: true,
|
||||
testedBy: 'mysqlConnectionTest',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
@ -204,6 +209,46 @@ export class MySql implements INodeType {
|
|||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
credentialTest: {
|
||||
async mysqlConnectionTest(
|
||||
this: ICredentialTestFunctions,
|
||||
credential: ICredentialsDecrypted,
|
||||
): Promise<INodeCredentialTestResult> {
|
||||
const credentials = credential.data as ICredentialDataDecryptedObject;
|
||||
try {
|
||||
const { ssl, caCertificate, clientCertificate, clientPrivateKey, ...baseCredentials } =
|
||||
credentials;
|
||||
|
||||
if (ssl) {
|
||||
baseCredentials.ssl = {};
|
||||
|
||||
if (caCertificate) {
|
||||
baseCredentials.ssl.ca = caCertificate;
|
||||
}
|
||||
|
||||
if (clientCertificate || clientPrivateKey) {
|
||||
baseCredentials.ssl.cert = clientCertificate;
|
||||
baseCredentials.ssl.key = clientPrivateKey;
|
||||
}
|
||||
}
|
||||
|
||||
const connection = await mysql2.createConnection(baseCredentials);
|
||||
connection.end();
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 'Error',
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'OK',
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const credentials = await this.getCredentials('mySql');
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import { IExecuteFunctions } from 'n8n-core';
|
||||
import {
|
||||
ICredentialsDecrypted,
|
||||
ICredentialTestFunctions,
|
||||
IDataObject,
|
||||
INodeCredentialTestResult,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
|
@ -28,6 +31,7 @@ export class Postgres implements INodeType {
|
|||
{
|
||||
name: 'postgres',
|
||||
required: true,
|
||||
testedBy: 'postgresConnectionTest',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
@ -273,6 +277,48 @@ export class Postgres implements INodeType {
|
|||
},
|
||||
],
|
||||
};
|
||||
methods = {
|
||||
credentialTest: {
|
||||
async postgresConnectionTest(
|
||||
this: ICredentialTestFunctions,
|
||||
credential: ICredentialsDecrypted,
|
||||
): Promise<INodeCredentialTestResult> {
|
||||
const credentials = credential.data as IDataObject;
|
||||
try {
|
||||
const pgp = pgPromise();
|
||||
const config: IDataObject = {
|
||||
host: credentials.host as string,
|
||||
port: credentials.port as number,
|
||||
database: credentials.database as string,
|
||||
user: credentials.user as string,
|
||||
password: credentials.password as string,
|
||||
};
|
||||
|
||||
if (credentials.allowUnauthorizedCerts === true) {
|
||||
config.ssl = {
|
||||
rejectUnauthorized: false,
|
||||
};
|
||||
} else {
|
||||
config.ssl = !['disable', undefined].includes(credentials.ssl as string | undefined);
|
||||
config.sslmode = (credentials.ssl as string) || 'disable';
|
||||
}
|
||||
|
||||
const db = pgp(config);
|
||||
await db.connect();
|
||||
await pgp.end();
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 'Error',
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'OK',
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const credentials = await this.getCredentials('postgres');
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
/* eslint-disable n8n-nodes-base/node-filename-against-convention */
|
||||
import { IExecuteFunctions } from 'n8n-core';
|
||||
|
||||
import * as amqplib from 'amqplib';
|
||||
import {
|
||||
ICredentialsDecrypted,
|
||||
ICredentialTestFunctions,
|
||||
IDataObject,
|
||||
INodeCredentialTestResult,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
|
@ -31,6 +34,7 @@ export class RabbitMQ implements INodeType {
|
|||
{
|
||||
name: 'rabbitmq',
|
||||
required: true,
|
||||
testedBy: 'rabbitmqConnectionTest',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
@ -273,6 +277,53 @@ export class RabbitMQ implements INodeType {
|
|||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
credentialTest: {
|
||||
async rabbitmqConnectionTest(
|
||||
this: ICredentialTestFunctions,
|
||||
credential: ICredentialsDecrypted,
|
||||
): Promise<INodeCredentialTestResult> {
|
||||
const credentials = credential.data as IDataObject;
|
||||
try {
|
||||
const credentialKeys = ['hostname', 'port', 'username', 'password', 'vhost'];
|
||||
|
||||
const credentialData: IDataObject = {};
|
||||
credentialKeys.forEach((key) => {
|
||||
credentialData[key] = credentials[key] === '' ? undefined : credentials[key];
|
||||
});
|
||||
|
||||
const optsData: IDataObject = {};
|
||||
if (credentials.ssl === true) {
|
||||
credentialData.protocol = 'amqps';
|
||||
|
||||
optsData.ca =
|
||||
credentials.ca === '' ? undefined : [Buffer.from(credentials.ca as string)];
|
||||
if (credentials.passwordless === true) {
|
||||
optsData.cert =
|
||||
credentials.cert === '' ? undefined : Buffer.from(credentials.cert as string);
|
||||
optsData.key =
|
||||
credentials.key === '' ? undefined : Buffer.from(credentials.key as string);
|
||||
optsData.passphrase =
|
||||
credentials.passphrase === '' ? undefined : credentials.passphrase;
|
||||
optsData.credentials = amqplib.credentials.external();
|
||||
}
|
||||
}
|
||||
const connection = await amqplib.connect(credentialData, optsData);
|
||||
await connection.close();
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 'Error',
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'OK',
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
let channel, options: IDataObject;
|
||||
try {
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import { IExecuteFunctions } from 'n8n-core';
|
||||
import {
|
||||
GenericValue,
|
||||
ICredentialDataDecryptedObject,
|
||||
ICredentialsDecrypted,
|
||||
ICredentialTestFunctions,
|
||||
IDataObject,
|
||||
INodeCredentialTestResult,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
|
@ -30,6 +34,7 @@ export class Redis implements INodeType {
|
|||
{
|
||||
name: 'redis',
|
||||
required: true,
|
||||
testedBy: 'redisConnectionTest',
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
|
@ -489,6 +494,52 @@ export class Redis implements INodeType {
|
|||
],
|
||||
};
|
||||
|
||||
methods = {
|
||||
credentialTest: {
|
||||
async redisConnectionTest(
|
||||
this: ICredentialTestFunctions,
|
||||
credential: ICredentialsDecrypted,
|
||||
): Promise<INodeCredentialTestResult> {
|
||||
const credentials = credential.data as ICredentialDataDecryptedObject;
|
||||
const redisOptions: redis.ClientOpts = {
|
||||
host: credentials.host as string,
|
||||
port: credentials.port as number,
|
||||
db: credentials.database as number,
|
||||
};
|
||||
|
||||
if (credentials.password) {
|
||||
redisOptions.password = credentials.password as string;
|
||||
}
|
||||
try {
|
||||
const client = await redis.createClient(redisOptions);
|
||||
// tslint:disable-next-line: no-any
|
||||
const data = await new Promise((resolve, reject): any => {
|
||||
client.on('connect', async () => {
|
||||
client.ping('ping', (error, pong) => {
|
||||
if (error) reject(error);
|
||||
resolve(pong);
|
||||
client.quit();
|
||||
});
|
||||
});
|
||||
client.on('error', async (err) => {
|
||||
client.quit();
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
return {
|
||||
status: 'Error',
|
||||
message: error.message,
|
||||
};
|
||||
}
|
||||
return {
|
||||
status: 'OK',
|
||||
message: 'Connection successful!',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
// Parses the given value in a number if it is one else returns a string
|
||||
function getParsedValue(value: string): string | number {
|
||||
|
|
Loading…
Reference in a new issue