mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
ef9d4aba90
Co-authored-by: Elias Meire <elias@meire.dev>
174 lines
4.7 KiB
TypeScript
174 lines
4.7 KiB
TypeScript
import { createSecureContext } from 'tls';
|
|
import type {
|
|
ICredentialDataDecryptedObject,
|
|
IDataObject,
|
|
IExecuteFunctions,
|
|
INodeExecutionData,
|
|
} from 'n8n-workflow';
|
|
import { NodeOperationError } from 'n8n-workflow';
|
|
|
|
import get from 'lodash/get';
|
|
import set from 'lodash/set';
|
|
import { MongoClient, ObjectId } from 'mongodb';
|
|
import { formatPrivateKey } from '../../utils/utilities';
|
|
import type {
|
|
IMongoCredentials,
|
|
IMongoCredentialsType,
|
|
IMongoParametricCredentials,
|
|
} from './mongoDb.types';
|
|
|
|
/**
|
|
* Standard way of building the MongoDB connection string, unless overridden with a provided string
|
|
*
|
|
* @param {ICredentialDataDecryptedObject} credentials MongoDB credentials to use, unless conn string is overridden
|
|
*/
|
|
export function buildParameterizedConnString(credentials: IMongoParametricCredentials): string {
|
|
if (credentials.port) {
|
|
return `mongodb://${credentials.user}:${credentials.password}@${credentials.host}:${credentials.port}`;
|
|
} else {
|
|
return `mongodb+srv://${credentials.user}:${credentials.password}@${credentials.host}`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build mongoDb connection string and resolve database name.
|
|
* If a connection string override value is provided, that will be used in place of individual args
|
|
*
|
|
* @param {ICredentialDataDecryptedObject} credentials raw/input MongoDB credentials to use
|
|
*/
|
|
export function buildMongoConnectionParams(
|
|
self: IExecuteFunctions,
|
|
credentials: IMongoCredentialsType,
|
|
): IMongoCredentials {
|
|
const sanitizedDbName =
|
|
credentials.database && credentials.database.trim().length > 0
|
|
? credentials.database.trim()
|
|
: '';
|
|
if (credentials.configurationType === 'connectionString') {
|
|
if (credentials.connectionString && credentials.connectionString.trim().length > 0) {
|
|
return {
|
|
connectionString: credentials.connectionString.trim(),
|
|
database: sanitizedDbName,
|
|
};
|
|
} else {
|
|
throw new NodeOperationError(
|
|
self.getNode(),
|
|
'Cannot override credentials: valid MongoDB connection string not provided ',
|
|
);
|
|
}
|
|
} else {
|
|
return {
|
|
connectionString: buildParameterizedConnString(credentials),
|
|
database: sanitizedDbName,
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verify credentials. If ok, build mongoDb connection string and resolve database name.
|
|
*
|
|
* @param {ICredentialDataDecryptedObject} credentials raw/input MongoDB credentials to use
|
|
*/
|
|
export function validateAndResolveMongoCredentials(
|
|
self: IExecuteFunctions,
|
|
credentials?: ICredentialDataDecryptedObject,
|
|
): IMongoCredentials {
|
|
if (credentials === undefined) {
|
|
throw new NodeOperationError(self.getNode(), 'No credentials got returned!');
|
|
} else {
|
|
return buildMongoConnectionParams(self, credentials as unknown as IMongoCredentialsType);
|
|
}
|
|
}
|
|
|
|
export function prepareItems(
|
|
items: INodeExecutionData[],
|
|
fields: string[],
|
|
updateKey = '',
|
|
useDotNotation = false,
|
|
dateFields: string[] = [],
|
|
) {
|
|
let data = items;
|
|
|
|
if (updateKey) {
|
|
if (!fields.includes(updateKey)) {
|
|
fields.push(updateKey);
|
|
}
|
|
data = items.filter((item) => item.json[updateKey] !== undefined);
|
|
}
|
|
|
|
const preperedItems = data.map(({ json }) => {
|
|
const updateItem: IDataObject = {};
|
|
|
|
for (const field of fields) {
|
|
let fieldData;
|
|
|
|
if (useDotNotation) {
|
|
fieldData = get(json, field, null);
|
|
} else {
|
|
fieldData = json[field] !== undefined ? json[field] : null;
|
|
}
|
|
|
|
if (fieldData && dateFields.includes(field)) {
|
|
fieldData = new Date(fieldData as string);
|
|
}
|
|
|
|
if (useDotNotation) {
|
|
set(updateItem, field, fieldData);
|
|
} else {
|
|
updateItem[field] = fieldData;
|
|
}
|
|
}
|
|
|
|
return updateItem;
|
|
});
|
|
|
|
return preperedItems;
|
|
}
|
|
|
|
export function prepareFields(fields: string) {
|
|
return fields
|
|
.split(',')
|
|
.map((field) => field.trim())
|
|
.filter((field) => !!field);
|
|
}
|
|
|
|
export function stringifyObjectIDs(items: INodeExecutionData[]) {
|
|
items.forEach((item) => {
|
|
if (item._id instanceof ObjectId) {
|
|
item.json._id = item._id.toString();
|
|
}
|
|
if (item.id instanceof ObjectId) {
|
|
item.json.id = item.id.toString();
|
|
}
|
|
});
|
|
|
|
return items;
|
|
}
|
|
|
|
export async function connectMongoClient(connectionString: string, credentials: IDataObject = {}) {
|
|
let client: MongoClient;
|
|
|
|
if (credentials.tls) {
|
|
const ca = credentials.ca ? formatPrivateKey(credentials.ca as string) : undefined;
|
|
const cert = credentials.cert ? formatPrivateKey(credentials.cert as string) : undefined;
|
|
const key = credentials.key ? formatPrivateKey(credentials.key as string) : undefined;
|
|
const passphrase = (credentials.passphrase as string) || undefined;
|
|
|
|
const secureContext = createSecureContext({
|
|
ca,
|
|
cert,
|
|
key,
|
|
passphrase,
|
|
});
|
|
|
|
client = await MongoClient.connect(connectionString, {
|
|
tls: true,
|
|
secureContext,
|
|
});
|
|
} else {
|
|
client = await MongoClient.connect(connectionString);
|
|
}
|
|
|
|
return client;
|
|
}
|