From 08a7b5b7425663ec6593114921c2e22ab37d039e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Tue, 22 Oct 2024 15:41:41 +0200 Subject: [PATCH] fix(SSH Node): Cleanup temporary binary files as soon as possible (#11305) --- packages/nodes-base/nodes/Ssh/Ssh.node.ts | 100 ++++++++++------------ 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/packages/nodes-base/nodes/Ssh/Ssh.node.ts b/packages/nodes-base/nodes/Ssh/Ssh.node.ts index c344fcf7ae..322e53bd75 100644 --- a/packages/nodes-base/nodes/Ssh/Ssh.node.ts +++ b/packages/nodes-base/nodes/Ssh/Ssh.node.ts @@ -1,4 +1,4 @@ -import { rm, writeFile } from 'fs/promises'; +import { writeFile } from 'fs/promises'; import type { Readable } from 'stream'; import type { ICredentialTestFunctions, @@ -285,8 +285,6 @@ export class Ssh implements INodeType { ): Promise { const credentials = credential.data as IDataObject; const ssh = new NodeSSH(); - const temporaryFiles: string[] = []; - try { if (!credentials.privateKey) { await ssh.connect({ @@ -317,7 +315,6 @@ export class Ssh implements INodeType { }; } finally { ssh.dispose(); - for (const tempFile of temporaryFiles) await rm(tempFile); } return { status: 'OK', @@ -336,8 +333,6 @@ export class Ssh implements INodeType { const operation = this.getNodeParameter('operation', 0); const authentication = this.getNodeParameter('authentication', 0) as string; - const temporaryFiles: string[] = []; - const ssh = new NodeSSH(); try { @@ -396,33 +391,35 @@ export class Ssh implements INodeType { i, ); - const { path } = await tmpFile({ prefix: 'n8n-ssh-' }); - temporaryFiles.push(path); + const binaryFile = await tmpFile({ prefix: 'n8n-ssh-' }); + try { + await ssh.getFile(binaryFile.path, parameterPath); - await ssh.getFile(path, parameterPath); + const newItem: INodeExecutionData = { + json: items[i].json, + binary: {}, + pairedItem: { + item: i, + }, + }; - const newItem: INodeExecutionData = { - json: items[i].json, - binary: {}, - pairedItem: { - item: i, - }, - }; + if (items[i].binary !== undefined && newItem.binary) { + // Create a shallow copy of the binary data so that the old + // data references which do not get changed still stay behind + // but the incoming data does not get changed. + Object.assign(newItem.binary, items[i].binary); + } - if (items[i].binary !== undefined && newItem.binary) { - // Create a shallow copy of the binary data so that the old - // data references which do not get changed still stay behind - // but the incoming data does not get changed. - Object.assign(newItem.binary, items[i].binary); + items[i] = newItem; + + const fileName = this.getNodeParameter('options.fileName', i, '') as string; + items[i].binary![dataPropertyNameDownload] = await this.nodeHelpers.copyBinaryFile( + binaryFile.path, + fileName || parameterPath, + ); + } finally { + await binaryFile.cleanup(); } - - items[i] = newItem; - - const fileName = this.getNodeParameter('options.fileName', i, '') as string; - items[i].binary![dataPropertyNameDownload] = await this.nodeHelpers.copyBinaryFile( - path, - fileName || parameterPath, - ); } if (operation === 'upload') { @@ -444,25 +441,28 @@ export class Ssh implements INodeType { uploadData = Buffer.from(binaryData.data, BINARY_ENCODING); } - const { path } = await tmpFile({ prefix: 'n8n-ssh-' }); - temporaryFiles.push(path); - await writeFile(path, uploadData); + const binaryFile = await tmpFile({ prefix: 'n8n-ssh-' }); + try { + await writeFile(binaryFile.path, uploadData); - await ssh.putFile( - path, - `${parameterPath}${ - parameterPath.charAt(parameterPath.length - 1) === '/' ? '' : '/' - }${fileName || binaryData.fileName}`, - ); + await ssh.putFile( + binaryFile.path, + `${parameterPath}${ + parameterPath.charAt(parameterPath.length - 1) === '/' ? '' : '/' + }${fileName || binaryData.fileName}`, + ); - returnItems.push({ - json: { - success: true, - }, - pairedItem: { - item: i, - }, - }); + returnItems.push({ + json: { + success: true, + }, + pairedItem: { + item: i, + }, + }); + } finally { + await binaryFile.cleanup(); + } } } } catch (error) { @@ -488,16 +488,10 @@ export class Ssh implements INodeType { throw error; } } - } catch (error) { + } finally { ssh.dispose(); - for (const tempFile of temporaryFiles) await rm(tempFile); - throw error; } - for (const tempFile of temporaryFiles) await rm(tempFile); - - ssh.dispose(); - if (resource === 'file' && operation === 'download') { // For file downloads the files get attached to the existing items return [items];