mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-16 01:24:05 -08:00
e77fd5d286
Ensure all errors in `nodes-base` are `ApplicationError` or children of it and contain no variables in the message, to continue normalizing all the backend errors we report to Sentry. Also, skip reporting to Sentry errors from user input and from external APIs. In future we should refine `ApplicationError` to more specific errors. Follow-up to: [#7877](https://github.com/n8n-io/n8n/pull/7877) - [x] Test workflows: https://github.com/n8n-io/n8n/actions/runs/7084627970 - [x] e2e: https://github.com/n8n-io/n8n/actions/runs/7084936861 --------- Co-authored-by: Michael Kret <michael.k@radency.com>
139 lines
3.4 KiB
TypeScript
139 lines
3.4 KiB
TypeScript
import { ApplicationError } from 'n8n-workflow';
|
|
import type { ICredentialDataDecryptedObject, IDataObject } from 'n8n-workflow';
|
|
|
|
import mysql2 from 'mysql2/promise';
|
|
import type { Client, ConnectConfig } from 'ssh2';
|
|
|
|
import type { Mysql2Pool } from '../helpers/interfaces';
|
|
import { formatPrivateKey } from '@utils/utilities';
|
|
|
|
async function createSshConnectConfig(credentials: IDataObject) {
|
|
if (credentials.sshAuthenticateWith === 'password') {
|
|
return {
|
|
host: credentials.sshHost as string,
|
|
port: credentials.sshPort as number,
|
|
username: credentials.sshUser as string,
|
|
password: credentials.sshPassword as string,
|
|
} as ConnectConfig;
|
|
} else {
|
|
const options: ConnectConfig = {
|
|
host: credentials.sshHost as string,
|
|
username: credentials.sshUser as string,
|
|
port: credentials.sshPort as number,
|
|
privateKey: formatPrivateKey(credentials.privateKey as string),
|
|
};
|
|
|
|
if (credentials.passphrase) {
|
|
options.passphrase = credentials.passphrase as string;
|
|
}
|
|
|
|
return options;
|
|
}
|
|
}
|
|
|
|
export async function createPool(
|
|
credentials: ICredentialDataDecryptedObject,
|
|
options?: IDataObject,
|
|
sshClient?: Client,
|
|
): Promise<Mysql2Pool> {
|
|
if (credentials === undefined) {
|
|
throw new ApplicationError('Credentials not selected, select or add new credentials', {
|
|
level: 'warning',
|
|
});
|
|
}
|
|
const {
|
|
ssl,
|
|
caCertificate,
|
|
clientCertificate,
|
|
clientPrivateKey,
|
|
sshTunnel,
|
|
sshHost,
|
|
sshUser,
|
|
sshPassword,
|
|
sshPort,
|
|
sshMysqlPort,
|
|
privateKey,
|
|
passphrase,
|
|
sshAuthenticateWith,
|
|
...baseCredentials
|
|
} = credentials;
|
|
|
|
if (ssl) {
|
|
baseCredentials.ssl = {};
|
|
|
|
if (caCertificate) {
|
|
baseCredentials.ssl.ca = formatPrivateKey(caCertificate as string);
|
|
}
|
|
|
|
if (clientCertificate || clientPrivateKey) {
|
|
baseCredentials.ssl.cert = formatPrivateKey(clientCertificate as string);
|
|
baseCredentials.ssl.key = formatPrivateKey(clientPrivateKey as string);
|
|
}
|
|
}
|
|
|
|
const connectionOptions: mysql2.ConnectionOptions = {
|
|
...baseCredentials,
|
|
multipleStatements: true,
|
|
supportBigNumbers: true,
|
|
};
|
|
|
|
if (options?.nodeVersion && (options.nodeVersion as number) >= 2.1) {
|
|
connectionOptions.dateStrings = true;
|
|
}
|
|
|
|
if (options?.connectionLimit) {
|
|
connectionOptions.connectionLimit = options.connectionLimit as number;
|
|
}
|
|
|
|
if (options?.connectTimeout) {
|
|
connectionOptions.connectTimeout = options.connectTimeout as number;
|
|
}
|
|
|
|
if (options?.largeNumbersOutput === 'text') {
|
|
connectionOptions.bigNumberStrings = true;
|
|
}
|
|
|
|
if (!sshTunnel) {
|
|
return mysql2.createPool(connectionOptions);
|
|
} else {
|
|
if (!sshClient) {
|
|
throw new ApplicationError('SSH Tunnel is enabled but no SSH Client was provided', {
|
|
level: 'warning',
|
|
});
|
|
}
|
|
|
|
const tunnelConfig = await createSshConnectConfig(credentials);
|
|
|
|
const forwardConfig = {
|
|
srcHost: '127.0.0.1',
|
|
srcPort: sshMysqlPort as number,
|
|
dstHost: credentials.host as string,
|
|
dstPort: credentials.port as number,
|
|
};
|
|
|
|
const poolSetup = new Promise<mysql2.Pool>((resolve, reject) => {
|
|
sshClient
|
|
.on('ready', () => {
|
|
sshClient.forwardOut(
|
|
forwardConfig.srcHost,
|
|
forwardConfig.srcPort,
|
|
forwardConfig.dstHost,
|
|
forwardConfig.dstPort,
|
|
(err, stream) => {
|
|
if (err) reject(err);
|
|
const updatedDbServer = {
|
|
...connectionOptions,
|
|
stream,
|
|
};
|
|
const connection = mysql2.createPool(updatedDbServer);
|
|
resolve(connection);
|
|
},
|
|
);
|
|
})
|
|
.connect(tunnelConfig);
|
|
});
|
|
|
|
return poolSetup;
|
|
}
|
|
}
|