diff --git a/packages/nodes-base/nodes/Ssh/Ssh.node.ts b/packages/nodes-base/nodes/Ssh/Ssh.node.ts index 33d0aa1350..3a852eb437 100644 --- a/packages/nodes-base/nodes/Ssh/Ssh.node.ts +++ b/packages/nodes-base/nodes/Ssh/Ssh.node.ts @@ -1,6 +1,9 @@ import type { + ICredentialTestFunctions, + ICredentialsDecrypted, IDataObject, IExecuteFunctions, + INodeCredentialTestResult, INodeExecutionData, INodeType, INodeTypeDescription, @@ -63,6 +66,7 @@ export class Ssh implements INodeType { { name: 'sshPassword', required: true, + testedBy: 'sshConnectionTest', displayOptions: { show: { authentication: ['password'], @@ -272,6 +276,60 @@ export class Ssh implements INodeType { ], }; + methods = { + credentialTest: { + async sshConnectionTest( + this: ICredentialTestFunctions, + credential: ICredentialsDecrypted, + ): Promise { + const credentials = credential.data as IDataObject; + const ssh = new NodeSSH(); + const temporaryFiles: string[] = []; + + try { + if (!credentials.privateKey) { + await ssh.connect({ + host: credentials.host as string, + username: credentials.username as string, + port: credentials.port as number, + password: credentials.password as string, + }); + } else { + const { path } = await tmpFile({ prefix: 'n8n-ssh-' }); + temporaryFiles.push(path); + await writeFile(path, credentials.privateKey as string); + + const options: Config = { + host: credentials.host as string, + username: credentials.username as string, + port: credentials.port as number, + privateKey: path, + }; + + if (credentials.passphrase) { + options.passphrase = credentials.passphrase as string; + } + + await ssh.connect(options); + } + } catch (error) { + const message = `SSH connection failed: ${error.message}`; + return { + status: 'Error', + message, + }; + } finally { + ssh.dispose(); + for (const tempFile of temporaryFiles) await rm(tempFile); + } + return { + status: 'OK', + message: 'Connection successful!', + }; + }, + }, + }; + async execute(this: IExecuteFunctions): Promise { const items = this.getInputData();