Background
I support an automated testing library for my company, and it has a thin wrapper around the sftp-promises
class SFTPClient
. Sometime in the recent past ssh2
(a dependency of sftp-promises
) required that the caller provide a list of supported OpenSSL properties. I found an answer on StackOverflow at the time, copy-pasted the configuration, and deleted items that threw errors until it ran. I'm no longer the sole owner of the project, and the project is migrating to a cloud provider, so I want to improve this configuration to detect supported algorithms.
Question
Using Node.js, how can I determine the values for the algorithms
configuration property of the SFTPClient
class provided by sftp-promises
?
I can easily see that the property config.algorithms.cipher
can be derived from the following:
import { getCiphers } from 'node:crypto';
import { IAlgorithm } from '../interfaces';
const algorithms: IAlgorithms = {
cipher: getCiphers()
};
However, this leaves compress
, hmac
, kex
, and serverHostKey
as properties I am hard-coding, and I'm not sure how I can derive these values at build-time, and more importantly at run-time since this will be running on other machines.
Code
Here is an edited version of the code
import SFTPClient from 'sftp-promises';
import { IFtpClientConfig, IFtpClientConfigAlgorithms } from '../interfaces';
export class FtpClient {
private lastLocalFileName?: string;
private lastLocalFilePath: string;
private lastRemoteFileName?: string;
private lastRemotePath?: string;
constructor(config: IFtpClientConfig, downloadDir: string) {
config.algorithms ||= FtpClient.algorithms;
this.client = new SFTPClient(config);
this.lastLocalFilePath = downloadDir;
}
static get algorithms(): IFtpClientConfigAlgorithms {
return {
kex: [
'diffie-hellman-group1-sha1',
'ecdh-sha2-nistp256',
'ecdh-sha2-nistp384',
'ecdh-sha2-nistp521',
'diffie-hellman-group-exchange-sha256',
'diffie-hellman-group14-sha1'
],
cipher: [
'3des-cbc',
'aes128-ctr',
'aes192-ctr',
'aes256-ctr',
'aes128-gcm@openssh.com',
'aes256-gcm@openssh.com'
],
serverHostKey: ['ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521'],
hmac: ['hmac-sha2-256', 'hmac-sha2-512', 'hmac-sha1']
};
}
}
And the backing interfaces to understand the shape of the data:
// interfaces/ftp-client/index.ts
export { IAlgorithms as IFtpClientConfigAlgorithms } from './IAlgorithms';
export {
IAuthHandler as IFtpClientConfigAuthHandler,
IAuthHandlerAgent as IFtpClientConfigAuthHandlerAgent,
IAuthHandlerCallback as IFtpClientConfigAuthHandlerCallback,
IAuthHandlerHostBased as IFtpClientConfigAuthHandlerHostBased,
IAuthHandlerInteractive as IFtpClientConfigAuthHandlerInteractive,
IAuthHandlerNone as IFtpClientConfigAuthHandlerNone,
IAuthHandlerObject as IFtpClientConfigAuthHandlerObject,
IAuthHandlerPassword as IFtpClientConfigAuthHandlerPassword,
IAuthHandlerPublicKey as IFtpClientConfigAuthHandlerPublicKey,
IAuthHandlerString as IFtpClientConfigAuthHandlerString
} from './IAuthHandler';
export { IConfig as IFtpClientConfig } from './IConfig';
// interfaces/ftp-client/IAlgorithms.ts
export interface IAlgorithms {
cipher?: string[];
compress?: string[];
hmac?: string[];
kex?: string[];
serverHostKey?: string[];
}
// interfaces/ftp-client/IConfig.ts
import { BaseAgent } from 'ssh2';
import { IAlgorithms } from './IAlgorithms';
import { IAuthHandler } from './IAuthHandler';
export interface IConfig {
agent?: string | BaseAgent;
agentFwd?: boolean;
algorithms?: IAlgorithms;
authHandler?: IAuthHandler;
debug?: boolean;
forceIPv4?: boolean;
forceIPv6?: boolean;
host?: string;
hostHashAlgo?: string;
hostHashCb?: CallableFunction;
keepaliveCountMax?: number;
keepaliveInterval?: number;
localAddress?: string;
localPort?: string | number;
password?: string;
port?: string | number;
privateKey?: string | Buffer;
readyTimeout?: number;
strictVendor?: unknown;
tryKeyboard?: boolean;
username?: string;
}