/** * @node crypto * @name Crypto * @category crypto * @version 1.0.0 * @description Hash data, generate HMACs, and perform cryptographic operations for data integrity and message authentication * @icon lock */ const configSchema = { type: 'object', properties: { operation: { type: 'string', title: 'Operation', enum: ['hash', 'hmac', 'random', 'encrypt', 'decrypt'], enumLabels: ['Hash', 'HMAC', 'Random Generation', 'Encrypt (Coming Soon)', 'Decrypt (Coming Soon)'], default: 'hash', description: 'Cryptographic operation to perform' }, algorithm: { type: 'string', title: 'Algorithm', enum: ['md5', 'sha1', 'sha256', 'sha384', 'sha512'], enumLabels: ['MD5', 'SHA-1', 'SHA-256', 'SHA-384', 'SHA-512'], default: 'sha256', description: 'Hash algorithm to use', showWhen: { field: 'operation', value: ['hash', 'hmac'] } }, outputFormat: { type: 'string', title: 'Output Format', enum: ['hex', 'base64'], enumLabels: ['Hexadecimal', 'Base64'], default: 'hex', description: 'Format of the output hash or HMAC', showWhen: { field: 'operation', value: ['hash', 'hmac'] } }, secretKey: { type: 'string', title: 'Secret Key', description: 'Secret key for HMAC generation. Supports {{variable}} interpolation.', showWhen: { field: 'operation', value: 'hmac' } }, randomLength: { type: 'number', title: 'Random Bytes Length', default: 32, description: 'Number of random bytes to generate (1-1024)', showWhen: { field: 'operation', value: 'random' } }, randomFormat: { type: 'string', title: 'Random Output Format', enum: ['hex', 'base64', 'uuid'], enumLabels: ['Hexadecimal', 'Base64', 'UUID v4'], default: 'hex', description: 'Format of the random output', showWhen: { field: 'operation', value: 'random' } } }, required: ['operation'] }; const inputSchema = { type: 'object', properties: { data: { type: 'any', description: 'Data to hash or process. Can be a string or will be JSON stringified.' }, secretKey: { type: 'string', description: 'Override secret key for HMAC from input' } } }; const outputSchema = { type: 'object', properties: { result: { type: 'string', description: 'The cryptographic operation result' }, algorithm: { type: 'string', description: 'Algorithm used for the operation' }, operation: { type: 'string', description: 'Operation that was performed' }, format: { type: 'string', description: 'Output format (hex or base64)' }, inputLength: { type: 'number', description: 'Length of the input data in bytes' } } }; function interpolate(template, data) { if (typeof template !== 'string') return template; return template.replace(/\{\{([^}]+)\}\}/g, (match, key) => { const keys = key.trim().split('.'); let value = data; for (const k of keys) { if (value && typeof value === 'object' && k in value) { value = value[k]; } else { return match; } } return value !== undefined ? String(value) : match; }); } async function execute(config, input, context) { const operation = config.operation || 'hash'; if (operation === 'encrypt' || operation === 'decrypt') { throw new Error('Encrypt and Decrypt operations are not yet implemented. Coming soon.'); } if (operation === 'random') { const format = config.randomFormat || 'hex'; if (format === 'uuid') { const uuid = smartbotic.crypto.randomUUID(); smartbotic.log.info('Generated random UUID'); return { result: uuid, operation: 'random', format: 'uuid' }; } const length = config.randomLength || 32; if (length < 1 || length > 1024) { throw new Error('Random length must be between 1 and 1024'); } const randomHex = smartbotic.crypto.randomBytes(length); let result = randomHex; if (format === 'base64') { let binary = ''; for (let i = 0; i < randomHex.length; i += 2) { binary += String.fromCharCode(parseInt(randomHex.substr(i, 2), 16)); } result = smartbotic.utils.base64Encode(binary); } smartbotic.log.info('Generated ' + length + ' random bytes in ' + format + ' format'); return { result: result, operation: 'random', format: format, inputLength: length }; } const inputData = input.data !== undefined ? input.data : input; let dataStr; if (typeof inputData === 'string') { dataStr = inputData; } else if (inputData === null || inputData === undefined) { throw new Error('No data provided for ' + operation + ' operation'); } else { dataStr = JSON.stringify(inputData); } const algorithm = config.algorithm || 'sha256'; const outputFormat = config.outputFormat || 'hex'; if (operation === 'hash') { smartbotic.log.info('Hashing ' + dataStr.length + ' bytes with ' + algorithm.toUpperCase()); const result = smartbotic.crypto.hash(dataStr, algorithm, outputFormat); return { result: result, algorithm: algorithm, operation: 'hash', format: outputFormat, inputLength: dataStr.length }; } if (operation === 'hmac') { let secretKey = input.secretKey || config.secretKey; if (secretKey && typeof secretKey === 'string') { secretKey = interpolate(secretKey, input); } if (!secretKey) { throw new Error('Secret key is required for HMAC operation'); } smartbotic.log.info('Generating HMAC-' + algorithm.toUpperCase() + ' for ' + dataStr.length + ' bytes'); const result = smartbotic.crypto.hmac(dataStr, secretKey, algorithm, outputFormat); return { result: result, algorithm: algorithm, operation: 'hmac', format: outputFormat, inputLength: dataStr.length }; } throw new Error('Unknown operation: ' + operation); } module.exports = { configSchema, inputSchema, outputSchema, execute };