0

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;
}
Solonotix
  • 449
  • 3
  • 15

0 Answers0