import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription, NodeOperationError, NodeOutput, } from 'n8n-workflow'; import { SecloreDRMFileService } from './Services/SecloreDRMFileService'; export class SecloreProtect implements INodeType { description: INodeTypeDescription = { displayName: 'Seclore Protect', name: 'secloreProtect', icon: 'file:seclore.svg', usableAsTool: true, // TODO: make it false/ don't allow it to be used as a tool group: ['transform'], version: 1, subtitle: '={{$parameter["resource"] + ": " + $parameter["operation"]}}', description: 'Protect files using Seclore DRM', defaults: { name: 'Seclore Protect', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'secloreProtectApi', required: true, }, ], properties: [ { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'Protection', value: 'protection', description: 'File protection operations', }, ], default: 'protection', }, { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['protection'], }, }, options: [ { name: 'Protect with Hot Folder', value: 'protectWithHotFolder', description: 'Protect a file using HotFolder ID configuration', action: 'Protect file with hotfolder', }, { name: 'Unprotect', value: 'unprotect', description: 'Unprotect a file using file ID', action: 'Unprotect file', }, ], default: 'protectWithHotFolder', }, { displayName: 'HotFolder ID', name: 'hotfolderId', type: 'string', required: true, default: '1000201', placeholder: '1000201', description: 'The ID of the HotFolder configuration to use for protection', displayOptions: { show: { resource: ['protection'], operation: ['protectWithHotFolder'], }, }, }, { displayName: 'Input Binary Property', name: 'binaryPropertyName', type: 'string', default: 'data', required: true, description: 'Name of the binary property that contains the file to protect', displayOptions: { show: { resource: ['protection'], operation: ['protectWithHotFolder'], }, }, }, { displayName: 'Output Binary Property', name: 'outputBinaryPropertyName', type: 'string', default: 'data', required: true, description: 'Name of the binary property where the protected file will be stored', displayOptions: { show: { resource: ['protection'], operation: ['protectWithHotFolder'], }, }, }, { displayName: 'Correlation ID', name: 'correlationId', type: 'string', default: '', placeholder: 'e.g., req-12345', description: 'Optional correlation ID for request tracking and logging', displayOptions: { show: { resource: ['protection'], operation: ['protectWithHotFolder'], }, }, }, { displayName: 'Retry Count', name: 'retryCount', type: 'number', default: 3, description: 'Number of retry attempts for failed requests', displayOptions: { show: { resource: ['protection'], operation: ['protectWithHotFolder'], }, }, }, // Unprotect operation parameters { displayName: 'File ID', name: 'fileId', type: 'string', required: true, default: '', placeholder: 'e.g., file-12345', description: 'The ID of the file to unprotect', displayOptions: { show: { resource: ['protection'], operation: ['unprotect'], }, }, }, { displayName: 'Output Binary Property', name: 'outputBinaryPropertyName', type: 'string', default: 'data', required: true, description: 'Name of the binary property where the unprotected file will be stored', displayOptions: { show: { resource: ['protection'], operation: ['unprotect'], }, }, }, { displayName: 'Correlation ID', name: 'correlationId', type: 'string', default: '', placeholder: 'e.g., req-12345', description: 'Optional correlation ID for request tracking and logging', displayOptions: { show: { resource: ['protection'], operation: ['unprotect'], }, }, }, { displayName: 'Retry Count', name: 'retryCount', type: 'number', default: 3, description: 'Number of retry attempts for failed requests', displayOptions: { show: { resource: ['protection'], operation: ['unprotect'], }, }, }, ], }; customOperations = { protection: { protectWithHotFolder: this.protectWithHotFolder, unprotect: this.unprotect, }, }; async protectWithHotFolder(this: IExecuteFunctions): Promise { const items = this.getInputData(); const returnData: INodeExecutionData[] = []; // Get credentials const credentials = await this.getCredentials('secloreProtectApi'); const baseUrl = credentials.baseUrl as string; const tenantId = credentials.tenantId as string; const tenantSecret = credentials.tenantSecret as string; // Initialize the file service const fileService = new SecloreDRMFileService(this, baseUrl, tenantId, tenantSecret); for (let i = 0; i < items.length; i++) { console.log('Data'); console.log(items[i]); try { // Get parameters for this item const hotfolderId = this.getNodeParameter('hotfolderId', i) as string; const binaryPropertyName = this.getNodeParameter('binaryPropertyName', i) as string; const outputBinaryPropertyName = this.getNodeParameter( 'outputBinaryPropertyName', i, ) as string; const correlationId = this.getNodeParameter('correlationId', i) as string; const retryCount = this.getNodeParameter('retryCount', i) as number; // Validate required parameters if (!hotfolderId) { throw new NodeOperationError(this.getNode(), 'HotFolder ID is required', { itemIndex: i, }); } console.log('assertBinaryData'); // Get input binary data const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName); console.log('getBinaryDataBuffer'); const fileBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName); console.log('fileBuffer', fileBuffer); console.log('binaryData.fileName', binaryData.fileName); // Upload the file first const uploadResult = await fileService.uploadFile( new Uint8Array(fileBuffer), binaryData.fileName || 'file', correlationId || undefined, retryCount, ); console.log('File upload response', uploadResult); // Protect the uploaded file with HotFolder const protectResult = await fileService.protectWithHotFolder( { hotfolderId, fileStorageId: uploadResult.fileStorageId, }, correlationId || undefined, retryCount, ); console.log('File protect response', protectResult); // Download the protected file const protectedFileData = await fileService.downloadFile( protectResult.fileStorageId, correlationId || undefined, retryCount, ); console.log('Protected file data', protectedFileData); // Create output binary data const outputBinaryData = await this.helpers.prepareBinaryData( Buffer.from(protectedFileData), binaryData.fileName || 'protected_file', binaryData.mimeType, ); // Create return item with binary data and metadata const returnItem: INodeExecutionData = { json: { success: true, originalFileStorageId: uploadResult.fileStorageId, protectedFileStorageId: protectResult.fileStorageId, secloreFileId: protectResult.secloreFileId, hotfolderId, fileName: binaryData.fileName, fileSize: protectedFileData.length, correlationId: correlationId || null, }, binary: { [outputBinaryPropertyName]: outputBinaryData, }, }; returnData.push(returnItem); } catch (error) { // Handle errors gracefully if (this.continueOnFail()) { const returnItem: INodeExecutionData = { json: { success: false, error: error.message, itemIndex: i, }, }; returnData.push(returnItem); } else { throw new NodeOperationError(this.getNode(), error.message, { itemIndex: i, }); } } } return [returnData]; } async unprotect(this: IExecuteFunctions): Promise { const items = this.getInputData(); const returnData: INodeExecutionData[] = []; // Get credentials const credentials = await this.getCredentials('secloreProtectApi'); const baseUrl = credentials.baseUrl as string; const tenantId = credentials.tenantId as string; const tenantSecret = credentials.tenantSecret as string; // Initialize the file service const fileService = new SecloreDRMFileService(this, baseUrl, tenantId, tenantSecret); for (let i = 0; i < items.length; i++) { console.log('Data'); console.log(items[i]); try { // Get parameters for this item const fileId = this.getNodeParameter('fileId', i) as string; const outputBinaryPropertyName = this.getNodeParameter( 'outputBinaryPropertyName', i, ) as string; const correlationId = this.getNodeParameter('correlationId', i) as string; const retryCount = this.getNodeParameter('retryCount', i) as number; // Validate required parameters if (!fileId) { throw new NodeOperationError(this.getNode(), 'File ID is required', { itemIndex: i, }); } console.log('Unprotecting file with ID:', fileId); // Unprotect the file using the file ID // Note: You'll need to implement unprotectFile in your SecloreDRMFileService // For now, using downloadFile as placeholder - replace with actual unprotect method const unprotectedFileData = await fileService.downloadFile( fileId, correlationId || undefined, retryCount, ); console.log('Unprotected file data', unprotectedFileData); // Create output binary data const outputBinaryData = await this.helpers.prepareBinaryData( Buffer.from(unprotectedFileData), 'unprotected_file', 'application/octet-stream', ); // Create return item with binary data and metadata const returnItem: INodeExecutionData = { json: { success: true, fileId, fileSize: unprotectedFileData.length, correlationId: correlationId || null, }, binary: { [outputBinaryPropertyName]: outputBinaryData, }, }; returnData.push(returnItem); } catch (error) { // Handle errors gracefully if (this.continueOnFail()) { const returnItem: INodeExecutionData = { json: { success: false, error: error.message, itemIndex: i, }, }; returnData.push(returnItem); } else { throw new NodeOperationError(this.getNode(), error.message, { itemIndex: i, }); } } } return [returnData]; } }