import { IExecuteFunctions } from 'n8n-core'; import { INodeExecutionData, INodeType, INodeTypeDescription, IDataObject, ILoadOptionsFunctions, INodePropertyOptions, } from 'n8n-workflow'; import { createHash, createHmac, createSign, getHashes, HexBase64Latin1Encoding, } from 'crypto'; export class Crypto implements INodeType { description: INodeTypeDescription = { displayName: 'Crypto', name: 'crypto', icon: 'fa:key', group: ['transform'], version: 1, subtitle: '={{$parameter["action"]}}', description: 'Provide cryptographic utilities', defaults: { name: 'Crypto', color: '#408000', }, inputs: ['main'], outputs: ['main'], properties: [ { displayName: 'Action', name: 'action', type: 'options', options: [ { name: 'Hash', description: 'Hash a text in a specified format.', value: 'hash' }, { name: 'Hmac', description: 'Hmac a text in a specified format.', value: 'hmac' }, { name: 'Sign', description: 'Sign a string using a private key.', value: 'sign' }, ], default: 'hash', }, { displayName: 'Type', name: 'type', displayOptions: { show: { action:[ 'hash' ], }, }, type: 'options', options: [ { name: 'MD5', value: 'MD5', }, { name: 'SHA256', value: 'SHA256', }, { name: 'SHA512', value: 'SHA512', }, ], default: 'MD5', description: 'The hash type to use', required: true, }, { displayName: 'Value', name: 'value', displayOptions: { show: { action:[ 'hash' ], }, }, type: 'string', default: '', description: 'The value that should be hashed.', required: true, }, { displayName: 'Property Name', name: 'dataPropertyName', type: 'string', default: 'data', required: true, displayOptions: { show: { action: [ 'hash' ], }, }, description: 'Name of the property to which to write the hash.', }, { displayName: 'Encoding', name: 'encoding', displayOptions: { show: { action:[ 'hash' ], }, }, type: 'options', options: [ { name: 'BASE64', value: 'base64', }, { name: 'HEX', value: 'hex', }, ], default: 'hex', required: true, }, { displayName: 'Type', name: 'type', displayOptions: { show: { action:[ 'hmac' ], }, }, type: 'options', options: [ { name: 'MD5', value: 'MD5', }, { name: 'SHA256', value: 'SHA256', }, { name: 'SHA512', value: 'SHA512', }, ], default: 'MD5', description: 'The hash type to use', required: true, }, { displayName: 'Value', name: 'value', displayOptions: { show: { action:[ 'hmac' ], }, }, type: 'string', default: '', description: 'The value of which the hmac should be created.', required: true, }, { displayName: 'Property Name', name: 'dataPropertyName', type: 'string', default: 'data', required: true, displayOptions: { show: { action: [ 'hmac' ], }, }, description: 'Name of the property to which to write the hmac.', }, { displayName: 'Secret', name: 'secret', displayOptions: { show: { action:[ 'hmac' ], }, }, type: 'string', default: '', required: true, }, { displayName: 'Encoding', name: 'encoding', displayOptions: { show: { action:[ 'hmac', ], }, }, type: 'options', options: [ { name: 'BASE64', value: 'base64', }, { name: 'HEX', value: 'hex', }, ], default: 'hex', required: true, }, { displayName: 'Value', name: 'value', displayOptions: { show: { action:[ 'sign' ], }, }, type: 'string', default: '', description: 'The value that should be signed.', required: true, }, { displayName: 'Property Name', name: 'dataPropertyName', type: 'string', default: 'data', required: true, displayOptions: { show: { action: [ 'sign' ], }, }, description: 'Name of the property to which to write the signed value.', }, { displayName: 'Algorithm', name: 'algorithm', displayOptions: { show: { action:[ 'sign', ], }, }, type: 'options', typeOptions: { loadOptionsMethod: 'getHashes', }, default: '', required: true, }, { displayName: 'Encoding', name: 'encoding', displayOptions: { show: { action:[ 'sign', ], }, }, type: 'options', options: [ { name: 'BASE64', value: 'base64', }, { name: 'HEX', value: 'hex', }, ], default: 'hex', required: true, }, { displayName: 'Private Key', name: 'privateKey', displayOptions: { show: { action:[ 'sign' ], }, }, type: 'string', typeOptions: { alwaysOpenEditWindow: true, }, description: 'Private key to use when signing the string.', default: '', required: true, }, ], }; methods = { loadOptions: { // Get all the hashes to display them to user so that he can // select them easily async getHashes(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const hashes = getHashes(); for (const hash of hashes) { const hashName = hash; const hashId = hash; returnData.push({ name: hashName, value: hashId, }); } return returnData; }, } }; async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); const returnData: IDataObject[] = []; const length = items.length as unknown as number; let responseData; const action = this.getNodeParameter('action', 0) as string; for (let i = 0; i < length; i++) { const dataPropertyName = this.getNodeParameter('dataPropertyName', i) as string; const value = this.getNodeParameter('value', i) as string; if (action === 'hash') { const type = this.getNodeParameter('type', i) as string; const encoding = this.getNodeParameter('encoding', i) as HexBase64Latin1Encoding; const clone = { ...items[i].json }; clone[dataPropertyName] = createHash(type).update(value).digest(encoding); responseData = clone; } if (action === 'hmac') { const type = this.getNodeParameter('type', i) as string; const secret = this.getNodeParameter('secret', i) as string; const encoding = this.getNodeParameter('encoding', i) as HexBase64Latin1Encoding; const clone = { ...items[i].json }; clone[dataPropertyName] = createHmac(type, secret).update(value).digest(encoding); responseData = clone; } if (action === 'sign') { const algorithm = this.getNodeParameter('algorithm', i) as string; const encoding = this.getNodeParameter('encoding', i) as HexBase64Latin1Encoding; const privateKey = this.getNodeParameter('privateKey', i) as string; const clone = { ...items[i].json }; const sign = createSign(algorithm); sign.write(value as string); sign.end(); const signature = sign.sign(privateKey, encoding); clone[dataPropertyName] = signature; responseData = clone; } if (Array.isArray(responseData)) { returnData.push.apply(returnData, responseData as IDataObject[]); } else { returnData.push(responseData as IDataObject); } } return [this.helpers.returnJsonArray(returnData)]; } }