@milaboratories/pl-deployments 2.15.1 → 2.15.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ssh/ssh.cjs +14 -11
- package/dist/ssh/ssh.cjs.map +1 -1
- package/dist/ssh/ssh.d.ts.map +1 -1
- package/dist/ssh/ssh.js +15 -12
- package/dist/ssh/ssh.js.map +1 -1
- package/dist/ssh/ssh_errors.cjs +63 -0
- package/dist/ssh/ssh_errors.cjs.map +1 -0
- package/dist/ssh/ssh_errors.d.ts +29 -0
- package/dist/ssh/ssh_errors.d.ts.map +1 -0
- package/dist/ssh/ssh_errors.js +59 -0
- package/dist/ssh/ssh_errors.js.map +1 -0
- package/package.json +7 -7
- package/src/ssh/__tests__/ssh-upload.test.ts +77 -0
- package/src/ssh/ssh.ts +20 -14
- package/src/ssh/ssh_errors.test.ts +90 -0
- package/src/ssh/ssh_errors.ts +69 -0
package/dist/ssh/ssh.cjs
CHANGED
|
@@ -8,6 +8,7 @@ var fsp = require('node:fs/promises');
|
|
|
8
8
|
var upath = require('upath');
|
|
9
9
|
var tsHelpers = require('@milaboratories/ts-helpers');
|
|
10
10
|
var node_crypto = require('node:crypto');
|
|
11
|
+
var ssh_errors = require('./ssh_errors.cjs');
|
|
11
12
|
|
|
12
13
|
const defaultConfig = {
|
|
13
14
|
keepaliveInterval: 60000,
|
|
@@ -270,28 +271,30 @@ class SshClient {
|
|
|
270
271
|
* @returns A promise resolving with `true` if the file was successfully uploaded.
|
|
271
272
|
*/
|
|
272
273
|
async uploadFile(localPath, remotePath) {
|
|
273
|
-
return await
|
|
274
|
-
return
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
274
|
+
return await tsHelpers.retry(async () => {
|
|
275
|
+
return await this.withSftp(async (sftp) => {
|
|
276
|
+
return new Promise((resolve, reject) => {
|
|
277
|
+
sftp.fastPut(localPath, remotePath, (err) => {
|
|
278
|
+
if (err) {
|
|
279
|
+
const newErr = new ssh_errors.SFTPUploadError(err, localPath, remotePath);
|
|
280
|
+
return reject(newErr);
|
|
281
|
+
}
|
|
282
|
+
resolve(true);
|
|
283
|
+
});
|
|
281
284
|
});
|
|
282
285
|
});
|
|
283
|
-
});
|
|
286
|
+
}, tsHelpers.Retry3TimesWithDelay, (e) => ssh_errors.SFTPError.from(e)?.isGenericFailure ?? false);
|
|
284
287
|
}
|
|
285
288
|
async withSftp(callback) {
|
|
286
289
|
return new Promise((resolve, reject) => {
|
|
287
290
|
this.client.sftp((err, sftp) => {
|
|
288
291
|
if (err) {
|
|
289
|
-
return reject(new Error(`ssh.withSftp: sftp err: ${err}
|
|
292
|
+
return reject(new Error(`ssh.withSftp: sftp err: ${err}`, { cause: err }));
|
|
290
293
|
}
|
|
291
294
|
callback(sftp)
|
|
292
295
|
.then(resolve)
|
|
293
296
|
.catch((err) => {
|
|
294
|
-
reject(new Error(`ssh.withSftp.callback: err ${err}
|
|
297
|
+
reject(new Error(`ssh.withSftp.callback: err ${err}`, { cause: err }));
|
|
295
298
|
})
|
|
296
299
|
.finally(() => {
|
|
297
300
|
sftp?.end();
|
package/dist/ssh/ssh.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssh.cjs","sources":["../../src/ssh/ssh.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-misused-promises */\n/* eslint-disable @typescript-eslint/no-base-to-string */\nimport type { ConnectConfig, ClientChannel, SFTPWrapper } from 'ssh2';\nimport ssh, { Client } from 'ssh2';\nimport net from 'node:net';\nimport dns from 'node:dns';\nimport fs from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport upath from 'upath';\nimport { RetryablePromise, type MiLogger } from '@milaboratories/ts-helpers';\nimport { randomBytes } from 'node:crypto';\n\nconst defaultConfig: ConnectConfig = {\n keepaliveInterval: 60000,\n keepaliveCountMax: 10,\n};\n\nexport type SshAuthMethods = 'publickey' | 'password';\nexport type SshAuthMethodsResult = SshAuthMethods[];\nexport type SshDirContent = {\n files: string[];\n directories: string[];\n};\n\nexport class SshClient {\n private config?: ConnectConfig;\n public homeDir?: string;\n private forwardedServers: net.Server[] = [];\n\n constructor(\n private readonly logger: MiLogger,\n private readonly client: Client,\n ) {}\n\n /**\n * Initializes the SshClient and establishes a connection using the provided configuration.\n * @param config - The connection configuration object for the SSH client.\n * @returns A new instance of SshClient with an active connection.\n */\n public static async init(logger: MiLogger, config: ConnectConfig): Promise<SshClient> {\n const withDefaults = {\n ...defaultConfig,\n ...config,\n };\n\n const client = new SshClient(logger, new Client());\n await client.connect(withDefaults);\n\n return client;\n }\n\n public getForwardedServers() {\n return this.forwardedServers;\n }\n\n public getFullHostName() {\n return `${this.config?.host}:${this.config?.port}`;\n }\n\n public getUserName() {\n return this.config?.username;\n }\n\n /**\n * Connects to the SSH server using the specified configuration.\n * @param config - The connection configuration object for the SSH client.\n * @returns A promise that resolves when the connection is established or rejects on error.\n */\n public async connect(config: ConnectConfig) {\n this.config = config;\n return await connect(this.client, config, () => {}, () => {});\n }\n\n /**\n * Executes a command on the SSH server.\n * @param command - The command to execute on the remote server.\n * @returns A promise resolving with the command's stdout and stderr outputs.\n */\n public async exec(command: string): Promise<SshExecResult> {\n return new Promise((resolve, reject) => {\n this.client.exec(command, (err: any, stream: ClientChannel) => {\n if (err) {\n return reject(new Error(`ssh.exec: ${command}: ${err}`));\n }\n\n let stdout = '';\n let stderr = '';\n\n stream.on('close', (code: number) => {\n if (code === 0) {\n resolve({ stdout, stderr });\n } else {\n reject(new Error(`Command ${command} exited with code ${code}, stdout: ${stdout}, stderr: ${stderr}`));\n }\n }).on('data', (data: ArrayBuffer) => {\n stdout += data.toString();\n }).stderr.on('data', (data: ArrayBuffer) => {\n stderr += data.toString();\n });\n });\n });\n }\n\n /**\n * Retrieves the supported authentication methods for a given host and port.\n * @param host - The hostname or IP address of the server.\n * @param port - The port number to connect to on the server.\n * @returns 'publickey' | 'password'[] A promise resolving with a list of supported authentication methods.\n */\n public static async getAuthTypes(host: string, port: number): Promise<SshAuthMethodsResult> {\n return new Promise((resolve) => {\n let stdout = '';\n const conn = new Client();\n\n conn.on('ready', () => {\n conn.end();\n const types = this.extractAuthMethods(stdout);\n resolve(types.length === 0 ? ['publickey', 'password'] : types as SshAuthMethodsResult);\n });\n\n conn.on('error', () => {\n conn.end();\n resolve(['publickey', 'password']);\n });\n\n conn.connect({\n host,\n port,\n username: new Date().getTime().toString(),\n debug: (err) => {\n stdout += `${err}\\n`;\n },\n });\n });\n }\n\n /**\n * Extracts authentication methods from debug logs.\n * @param log - The debug log output containing authentication information.\n * @returns An array of extracted authentication methods.\n */\n private static extractAuthMethods(log: string): string[] {\n const match = log.match(/Inbound: Received USERAUTH_FAILURE \\((.+)\\)/);\n return match && match[1] ? match[1].split(',').map((method) => method.trim()) : [];\n }\n\n /**\n * Sets up port forwarding between a remote port on the SSH server and a local port.\n * A new connection is used for this operation instead of an existing one.\n * @param ports - An object specifying the remote and local port configuration.\n * @param config - Optional connection configuration for the SSH client.\n * @returns { server: net.Server } A promise resolving with the created server instance.\n */\n public async forwardPort(ports: { remotePort: number; localPort: number; localHost?: string }, config?: ConnectConfig): Promise<{ server: net.Server }> {\n const log = `ssh.forward:${ports.localPort}:${ports.remotePort}.id_${randomBytes(1).toString('hex')}`;\n config = config ?? this.config;\n\n // we make this thing persistent so that if the connection\n // drops (it happened in the past because of lots of errors and forwardOut opened channels),\n // we'll recreate it here.\n const persistentClient = new RetryablePromise((p: RetryablePromise<Client>) => {\n return new Promise<Client>((resolve, reject) => {\n const client = new Client();\n\n client.on('ready', () => {\n this.logger.info(`${log}.client.ready`);\n resolve(client);\n });\n\n client.on('error', (err) => {\n this.logger.info(`${log}.client.error: ${err}`);\n p.reset();\n reject(err);\n });\n\n client.on('close', () => {\n this.logger.info(`${log}.client.closed`);\n p.reset();\n });\n\n client.connect(config!);\n });\n });\n\n await persistentClient.ensure(); // warm up a connection\n\n return new Promise((resolve, reject) => {\n const server = net.createServer({ pauseOnConnect: true }, async (localSocket) => {\n const sockLog = `${log}.sock_${randomBytes(1).toString('hex')}`;\n // this.logger.info(`${sockLog}.localSocket: start connection`);\n let conn: Client;\n try {\n conn = await persistentClient.ensure();\n } catch (e: unknown) {\n this.logger.info(`${sockLog}.persistentClient.catch: ${e}`);\n localSocket.end();\n return;\n }\n\n // Remove TCP buffering.\n // Although it means less throughput (bad), it also less latency (good).\n // It could help when we have\n // small messages like in our grpc transactions.\n // And it also could help when we have tcp forwarding to not buffer messages in the middle.\n (conn as any).setNoDelay(true);\n localSocket.setNoDelay(true);\n\n let stream: ClientChannel;\n try {\n stream = await forwardOut(this.logger, conn, '127.0.0.1', 0, '127.0.0.1', ports.remotePort);\n } catch (e: unknown) {\n this.logger.error(`${sockLog}.forwardOut.err: ${e}`);\n localSocket.end();\n return;\n }\n\n localSocket.pipe(stream);\n stream.pipe(localSocket);\n localSocket.resume();\n // this.logger.info(`${sockLog}.forwardOut: connected`);\n\n stream.on('error', (err: unknown) => {\n this.logger.error(`${sockLog}.stream.error: ${err}`);\n localSocket.end();\n stream.end();\n });\n stream.on('close', () => {\n // this.logger.info(`${sockLog}.stream.close: closed`);\n localSocket.end();\n stream.end();\n });\n localSocket.on('close', () => {\n this.logger.info(`${sockLog}.localSocket: closed`);\n localSocket.end();\n stream.end();\n });\n });\n\n server.listen(ports.localPort, '127.0.0.1', () => {\n this.logger.info(`${log}.server: started listening`);\n this.forwardedServers.push(server);\n resolve({ server });\n });\n\n server.on('error', (err) => {\n server.close();\n reject(new Error(`${log}.server: error: ${JSON.stringify(err)}`));\n });\n\n server.on('close', () => {\n this.logger.info(`${log}.server: closed ${JSON.stringify(ports)}`);\n this.forwardedServers = this.forwardedServers.filter((s) => s !== server);\n });\n });\n }\n\n public closeForwardedPorts(): void {\n this.logger.info('[SSH] Closing all forwarded ports...');\n this.forwardedServers.forEach((server) => {\n const rawAddress = server.address();\n if (rawAddress && typeof rawAddress !== 'string') {\n const address: net.AddressInfo = rawAddress;\n this.logger.info(`[SSH] Closing port forward for server ${address.address}:${address.port}`);\n }\n\n server.close();\n });\n this.forwardedServers = [];\n }\n\n /**\n * Checks if a specified host is available by performing a DNS lookup.\n * @param hostname - The hostname or IP address to check.\n * @returns A promise resolving with `true` if the host is reachable, otherwise `false`.\n */\n public static async checkHostAvailability(hostname: string): Promise<boolean> {\n return new Promise((resolve) => {\n dns.lookup(hostname, (err) => {\n resolve(!err);\n });\n });\n }\n\n /**\n * Determines whether a private key requires a passphrase for use.\n * @param privateKey - The private key content to check.\n * @returns A promise resolving with `true` if a passphrase is required, otherwise `false`.\n */\n public static async isPassphraseRequiredForKey(privateKey: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n try {\n const keyOrError = ssh.utils.parseKey(privateKey);\n if (keyOrError instanceof Error) {\n resolve(true);\n }\n return resolve(false);\n } catch (err: unknown) {\n console.log('Error parsing privateKey');\n reject(new Error(`ssh.isPassphraseRequiredForKey: err ${err}`));\n }\n });\n }\n\n /**\n * Uploads a local file to a remote server via SFTP.\n * This function creates new SFTP connection\n * @param localPath - The local file path.\n * @param remotePath - The remote file path on the server.\n * @returns A promise resolving with `true` if the file was successfully uploaded.\n */\n public async uploadFile(localPath: string, remotePath: string): Promise<boolean> {\n return await this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.fastPut(localPath, remotePath, (err) => {\n if (err) {\n const newErr = new Error(\n `ssh.uploadFile: err: ${err}, localPath: ${localPath}, remotePath: ${remotePath}`);\n return reject(newErr);\n }\n resolve(true);\n });\n });\n });\n }\n\n public async withSftp<R>(callback: (sftp: SFTPWrapper) => Promise<R>): Promise<R> {\n return new Promise((resolve, reject) => {\n this.client.sftp((err, sftp) => {\n if (err) {\n return reject(new Error(`ssh.withSftp: sftp err: ${err}`));\n }\n\n callback(sftp)\n .then(resolve)\n .catch((err) => {\n reject(new Error(`ssh.withSftp.callback: err ${err}`));\n })\n .finally(() => {\n sftp?.end();\n });\n });\n });\n }\n\n public async writeFileOnTheServer(remotePath: string, data: string | Buffer, mode: number = 0o660) {\n return this.withSftp(async (sftp) => {\n return this.writeFile(sftp, remotePath, data, mode);\n });\n }\n\n public async getForderStructure(sftp: SFTPWrapper, remotePath: string, data: SshDirContent = { files: [], directories: [] }): Promise<SshDirContent> {\n return new Promise((resolve, reject) => {\n sftp.readdir(remotePath, async (err, items) => {\n if (err) {\n return reject(err);\n }\n\n for (const item of items) {\n const itemPath = `${remotePath}/${item.filename}`;\n if (item.attrs.isDirectory()) {\n data.directories.push(itemPath);\n try {\n await this.getForderStructure(sftp, itemPath, data);\n } catch (error) {\n return reject(error instanceof Error ? error : new Error(String(error)));\n }\n } else {\n data.files.push(itemPath);\n }\n }\n resolve(data);\n });\n });\n }\n\n public rmdir(sftp: SFTPWrapper, path: string) {\n return new Promise((resolve, reject) => {\n sftp.rmdir(path, (err) => err ? reject(err) : resolve(true));\n });\n }\n\n public unlink(sftp: SFTPWrapper, path: string) {\n return new Promise((resolve, reject) => {\n sftp.unlink(path, (err) => err ? reject(err) : resolve(true));\n });\n }\n\n public async deleteFolder(path: string) {\n return this.withSftp(async (sftp) => {\n try {\n const list = await this.getForderStructure(sftp, path);\n this.logger.info(`ssh.deleteFolder list of files and directories`);\n this.logger.info(`ssh.deleteFolder list of files: ${list.files}`);\n this.logger.info(`ssh.deleteFolder list of directories: ${list.directories}`);\n\n for (const filePath of list.files) {\n this.logger.info(`ssh.deleteFolder unlink file ${filePath}`);\n await this.unlink(sftp, filePath);\n }\n\n list.directories.sort((a, b) => b.length - a.length);\n\n for (const directoryPath of list.directories) {\n this.logger.info(`ssh.deleteFolder rmdir ${directoryPath}`);\n await this.rmdir(sftp, directoryPath);\n }\n\n await this.rmdir(sftp, path);\n return true;\n } catch (e: unknown) {\n this.logger.error(e);\n const message = e instanceof Error ? e.message : '';\n throw new Error(`ssh.deleteFolder: path: ${path}, message: ${message}`);\n }\n });\n }\n\n public async readFile(remotePath: string): Promise<string> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.readFile(remotePath, (err, buffer) => {\n if (err) {\n return reject(new Error(`ssh.readFile: ${err}`));\n }\n resolve(buffer.toString());\n });\n });\n });\n }\n\n async chmod(path: string, mode: number) {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.chmod(path, mode, (err) => {\n if (err) {\n return reject(new Error(`ssh.chmod: ${err}, path: ${path}, mode: ${mode}`));\n }\n return resolve(undefined);\n });\n });\n });\n }\n\n async checkFileExists(remotePath: string) {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.stat(remotePath, (err: Error | undefined, stats) => {\n if (err) {\n if ((err as unknown as { code?: number })?.code === 2) {\n return resolve(false);\n }\n return reject(new Error(`ssh.checkFileExists: err ${err}`));\n }\n resolve(stats.isFile());\n });\n });\n });\n }\n\n async checkPathExists(remotePath: string): Promise<{ exists: boolean; isFile: boolean; isDirectory: boolean }> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.stat(remotePath, (err, stats) => {\n if (err) {\n if ((err as Error & { code: number }).code === 2) {\n return resolve({ exists: false, isFile: false, isDirectory: false });\n }\n return reject(new Error(`ssh.checkPathExists: ${err}`));\n }\n resolve({\n exists: true,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n });\n });\n });\n });\n }\n\n private async writeFile(sftp: SFTPWrapper, remotePath: string, data: string | Buffer, mode: number = 0o660): Promise<boolean> {\n return new Promise((resolve, reject) => {\n sftp.writeFile(remotePath, data, { mode }, (err) => {\n if (err) {\n return reject(new Error(`ssh.writeFile: err ${err}, remotePath: ${remotePath}`));\n }\n resolve(true);\n });\n });\n }\n\n public uploadFileUsingExistingSftp(sftp: SFTPWrapper, localPath: string, remotePath: string, mode: number = 0o660) {\n return new Promise((resolve, reject) => {\n void readFile(localPath).then(async (result: Buffer) => {\n return this.writeFile(sftp, remotePath, result, mode)\n .then(() => {\n resolve(undefined);\n })\n .catch((err) => {\n const msg = `uploadFileUsingExistingSftp: ${err}`;\n this.logger.error(msg);\n reject(new Error(msg));\n });\n });\n });\n }\n\n private async __uploadDirectory(sftp: SFTPWrapper, localDir: string, remoteDir: string, mode: number = 0o660): Promise<void> {\n return new Promise((resolve, reject) => {\n fs.readdir(localDir, async (err, files) => {\n if (err) {\n return reject(new Error(`ssh.__uploadDir: err ${err}, localDir: ${localDir}, remoteDir: ${remoteDir}`));\n }\n\n try {\n await this.__createRemoteDirectory(sftp, remoteDir);\n for (const file of files) {\n const localPath = upath.join(localDir, file);\n const remotePath = `${remoteDir}/${file}`;\n\n if (fs.lstatSync(localPath).isDirectory()) {\n await this.__uploadDirectory(sftp, localPath, remotePath, mode);\n } else {\n await this.uploadFileUsingExistingSftp(sftp, localPath, remotePath, mode);\n }\n }\n\n resolve();\n } catch (err) {\n const msg = `ssh.__uploadDir: catched err ${err}`;\n this.logger.error(msg);\n reject(new Error(msg));\n }\n });\n });\n }\n\n /**\n * Uploads a local directory and its contents (including subdirectories) to the remote server via SFTP.\n * @param localDir - The path to the local directory to upload.\n * @param remoteDir - The path to the remote directory on the server.\n * @returns A promise that resolves when the directory and its contents are uploaded.\n */\n public async uploadDirectory(localDir: string, remoteDir: string, mode: number = 0o660): Promise<void> {\n return new Promise((resolve, reject) => {\n void this.withSftp(async (sftp: SFTPWrapper) => {\n try {\n await this.__uploadDirectory(sftp, localDir, remoteDir, mode);\n resolve();\n } catch (e: unknown) {\n reject(new Error(`ssh.uploadDirectory: ${e}`));\n }\n });\n });\n }\n\n /**\n * Ensures that a remote directory and all its parent directories exist.\n * @param sftp - The SFTP wrapper.\n * @param remotePath - The path to the remote directory.\n * @returns A promise that resolves when the directory is created.\n */\n private __createRemoteDirectory(sftp: SFTPWrapper, remotePath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const directories = remotePath.split('/');\n let currentPath = '';\n\n const createNext = (index: number) => {\n if (index >= directories.length) {\n return resolve();\n }\n\n currentPath += `${directories[index]}/`;\n\n sftp.stat(currentPath, (err) => {\n if (err) {\n sftp.mkdir(currentPath, (err) => {\n if (err) {\n return reject(new Error(`ssh.__createRemDir: err ${err}, remotePath: ${remotePath}`));\n }\n createNext(index + 1);\n });\n } else {\n createNext(index + 1);\n }\n });\n };\n\n createNext(0);\n });\n }\n\n /**\n * Ensures that a remote directory and all its parent directories exist.\n * @param sftp - The SFTP wrapper.\n * @param remotePath - The path to the remote directory.\n * @returns A promise that resolves when the directory is created.\n */\n public ensureRemoteDirCreated(remotePath: string, mode: number = 0o755): Promise<void> {\n return this.withSftp(async (sftp) => {\n const directories = remotePath.split('/');\n let currentPath = '';\n\n for (const directory of directories) {\n currentPath += `${directory}/`;\n\n try {\n await new Promise<void>((resolve, reject) => {\n sftp.stat(currentPath, (err) => {\n if (!err) return resolve();\n\n sftp.mkdir(currentPath, { mode }, (err) => {\n if (err) {\n return reject(new Error(`ssh.createRemoteDir: err ${err}, remotePath: ${remotePath}`));\n }\n resolve();\n });\n });\n });\n } catch (error) {\n console.error(`Failed to create directory: ${currentPath}`, error);\n throw error;\n }\n }\n });\n }\n\n /**\n * Downloads a file from the remote server to a local path via SFTP.\n * @param remotePath - The remote file path on the server.\n * @param localPath - The local file path to save the file.\n * @returns A promise resolving with `true` if the file was successfully downloaded.\n */\n public async downloadFile(remotePath: string, localPath: string): Promise<boolean> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.fastGet(remotePath, localPath, (err) => {\n if (err) {\n return reject(new Error(`ssh.downloadFile: err ${err}, remotePath: ${remotePath}, localPath: ${localPath}`));\n }\n resolve(true);\n });\n });\n });\n }\n\n /**\n * Closes the SSH client connection and forwarded ports.\n */\n public close(): void {\n this.closeForwardedPorts();\n this.client.end();\n }\n}\n\nexport type SshExecResult = { stdout: string; stderr: string };\n\nasync function connect(\n client: Client,\n config: ConnectConfig,\n onError: (e: unknown) => void,\n onClose: () => void,\n): Promise<Client> {\n return new Promise((resolve, reject) => {\n client.on('ready', () => {\n resolve(client);\n });\n\n client.on('error', (err: unknown) => {\n onError(err);\n reject(new Error(`ssh.connect: ${err}`));\n });\n\n client.on('close', () => {\n onClose();\n });\n\n client.connect(config);\n\n // Remove TCP buffering.\n // Although it means less throughput (bad), it also means less latency (good).\n // It could help when we have\n // small messages like in our grpc transactions.\n // And it also could help when we have tcp forwarding to not buffer messages in the middle.\n (client as any).setNoDelay(true);\n });\n}\n\nasync function forwardOut(logger: MiLogger, conn: Client, localHost: string, localPort: number, remoteHost: string, remotePort: number): Promise<ClientChannel> {\n return new Promise((resolve, reject) => {\n conn.forwardOut(localHost, localPort, remoteHost, remotePort, (err, stream) => {\n if (err) {\n logger.error(`forwardOut.error: ${err}`);\n return reject(err);\n }\n\n return resolve(stream);\n });\n });\n}\n"],"names":["Client","randomBytes","RetryablePromise","readFile"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ssh.cjs","sources":["../../src/ssh/ssh.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-misused-promises */\n/* eslint-disable @typescript-eslint/no-base-to-string */\nimport type { ConnectConfig, ClientChannel, SFTPWrapper } from 'ssh2';\nimport ssh, { Client } from 'ssh2';\nimport net from 'node:net';\nimport dns from 'node:dns';\nimport fs from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport upath from 'upath';\nimport { RetryablePromise, retry, type MiLogger, Retry3TimesWithDelay } from '@milaboratories/ts-helpers';\nimport { randomBytes } from 'node:crypto';\nimport { SFTPUploadError, SFTPError } from './ssh_errors';\n\nconst defaultConfig: ConnectConfig = {\n keepaliveInterval: 60000,\n keepaliveCountMax: 10,\n};\n\nexport type SshAuthMethods = 'publickey' | 'password';\nexport type SshAuthMethodsResult = SshAuthMethods[];\nexport type SshDirContent = {\n files: string[];\n directories: string[];\n};\n\nexport class SshClient {\n private config?: ConnectConfig;\n public homeDir?: string;\n private forwardedServers: net.Server[] = [];\n\n constructor(\n private readonly logger: MiLogger,\n private readonly client: Client,\n ) {}\n\n /**\n * Initializes the SshClient and establishes a connection using the provided configuration.\n * @param config - The connection configuration object for the SSH client.\n * @returns A new instance of SshClient with an active connection.\n */\n public static async init(logger: MiLogger, config: ConnectConfig): Promise<SshClient> {\n const withDefaults = {\n ...defaultConfig,\n ...config,\n };\n\n const client = new SshClient(logger, new Client());\n await client.connect(withDefaults);\n\n return client;\n }\n\n public getForwardedServers() {\n return this.forwardedServers;\n }\n\n public getFullHostName() {\n return `${this.config?.host}:${this.config?.port}`;\n }\n\n public getUserName() {\n return this.config?.username;\n }\n\n /**\n * Connects to the SSH server using the specified configuration.\n * @param config - The connection configuration object for the SSH client.\n * @returns A promise that resolves when the connection is established or rejects on error.\n */\n public async connect(config: ConnectConfig) {\n this.config = config;\n return await connect(this.client, config, () => {}, () => {});\n }\n\n /**\n * Executes a command on the SSH server.\n * @param command - The command to execute on the remote server.\n * @returns A promise resolving with the command's stdout and stderr outputs.\n */\n public async exec(command: string): Promise<SshExecResult> {\n return new Promise((resolve, reject) => {\n this.client.exec(command, (err: any, stream: ClientChannel) => {\n if (err) {\n return reject(new Error(`ssh.exec: ${command}: ${err}`));\n }\n\n let stdout = '';\n let stderr = '';\n\n stream.on('close', (code: number) => {\n if (code === 0) {\n resolve({ stdout, stderr });\n } else {\n reject(new Error(`Command ${command} exited with code ${code}, stdout: ${stdout}, stderr: ${stderr}`));\n }\n }).on('data', (data: ArrayBuffer) => {\n stdout += data.toString();\n }).stderr.on('data', (data: ArrayBuffer) => {\n stderr += data.toString();\n });\n });\n });\n }\n\n /**\n * Retrieves the supported authentication methods for a given host and port.\n * @param host - The hostname or IP address of the server.\n * @param port - The port number to connect to on the server.\n * @returns 'publickey' | 'password'[] A promise resolving with a list of supported authentication methods.\n */\n public static async getAuthTypes(host: string, port: number): Promise<SshAuthMethodsResult> {\n return new Promise((resolve) => {\n let stdout = '';\n const conn = new Client();\n\n conn.on('ready', () => {\n conn.end();\n const types = this.extractAuthMethods(stdout);\n resolve(types.length === 0 ? ['publickey', 'password'] : types as SshAuthMethodsResult);\n });\n\n conn.on('error', () => {\n conn.end();\n resolve(['publickey', 'password']);\n });\n\n conn.connect({\n host,\n port,\n username: new Date().getTime().toString(),\n debug: (err) => {\n stdout += `${err}\\n`;\n },\n });\n });\n }\n\n /**\n * Extracts authentication methods from debug logs.\n * @param log - The debug log output containing authentication information.\n * @returns An array of extracted authentication methods.\n */\n private static extractAuthMethods(log: string): string[] {\n const match = log.match(/Inbound: Received USERAUTH_FAILURE \\((.+)\\)/);\n return match && match[1] ? match[1].split(',').map((method) => method.trim()) : [];\n }\n\n /**\n * Sets up port forwarding between a remote port on the SSH server and a local port.\n * A new connection is used for this operation instead of an existing one.\n * @param ports - An object specifying the remote and local port configuration.\n * @param config - Optional connection configuration for the SSH client.\n * @returns { server: net.Server } A promise resolving with the created server instance.\n */\n public async forwardPort(ports: { remotePort: number; localPort: number; localHost?: string }, config?: ConnectConfig): Promise<{ server: net.Server }> {\n const log = `ssh.forward:${ports.localPort}:${ports.remotePort}.id_${randomBytes(1).toString('hex')}`;\n config = config ?? this.config;\n\n // we make this thing persistent so that if the connection\n // drops (it happened in the past because of lots of errors and forwardOut opened channels),\n // we'll recreate it here.\n const persistentClient = new RetryablePromise((p: RetryablePromise<Client>) => {\n return new Promise<Client>((resolve, reject) => {\n const client = new Client();\n\n client.on('ready', () => {\n this.logger.info(`${log}.client.ready`);\n resolve(client);\n });\n\n client.on('error', (err) => {\n this.logger.info(`${log}.client.error: ${err}`);\n p.reset();\n reject(err);\n });\n\n client.on('close', () => {\n this.logger.info(`${log}.client.closed`);\n p.reset();\n });\n\n client.connect(config!);\n });\n });\n\n await persistentClient.ensure(); // warm up a connection\n\n return new Promise((resolve, reject) => {\n const server = net.createServer({ pauseOnConnect: true }, async (localSocket) => {\n const sockLog = `${log}.sock_${randomBytes(1).toString('hex')}`;\n // this.logger.info(`${sockLog}.localSocket: start connection`);\n let conn: Client;\n try {\n conn = await persistentClient.ensure();\n } catch (e: unknown) {\n this.logger.info(`${sockLog}.persistentClient.catch: ${e}`);\n localSocket.end();\n return;\n }\n\n // Remove TCP buffering.\n // Although it means less throughput (bad), it also less latency (good).\n // It could help when we have\n // small messages like in our grpc transactions.\n // And it also could help when we have tcp forwarding to not buffer messages in the middle.\n (conn as any).setNoDelay(true);\n localSocket.setNoDelay(true);\n\n let stream: ClientChannel;\n try {\n stream = await forwardOut(this.logger, conn, '127.0.0.1', 0, '127.0.0.1', ports.remotePort);\n } catch (e: unknown) {\n this.logger.error(`${sockLog}.forwardOut.err: ${e}`);\n localSocket.end();\n return;\n }\n\n localSocket.pipe(stream);\n stream.pipe(localSocket);\n localSocket.resume();\n // this.logger.info(`${sockLog}.forwardOut: connected`);\n\n stream.on('error', (err: unknown) => {\n this.logger.error(`${sockLog}.stream.error: ${err}`);\n localSocket.end();\n stream.end();\n });\n stream.on('close', () => {\n // this.logger.info(`${sockLog}.stream.close: closed`);\n localSocket.end();\n stream.end();\n });\n localSocket.on('close', () => {\n this.logger.info(`${sockLog}.localSocket: closed`);\n localSocket.end();\n stream.end();\n });\n });\n\n server.listen(ports.localPort, '127.0.0.1', () => {\n this.logger.info(`${log}.server: started listening`);\n this.forwardedServers.push(server);\n resolve({ server });\n });\n\n server.on('error', (err) => {\n server.close();\n reject(new Error(`${log}.server: error: ${JSON.stringify(err)}`));\n });\n\n server.on('close', () => {\n this.logger.info(`${log}.server: closed ${JSON.stringify(ports)}`);\n this.forwardedServers = this.forwardedServers.filter((s) => s !== server);\n });\n });\n }\n\n public closeForwardedPorts(): void {\n this.logger.info('[SSH] Closing all forwarded ports...');\n this.forwardedServers.forEach((server) => {\n const rawAddress = server.address();\n if (rawAddress && typeof rawAddress !== 'string') {\n const address: net.AddressInfo = rawAddress;\n this.logger.info(`[SSH] Closing port forward for server ${address.address}:${address.port}`);\n }\n\n server.close();\n });\n this.forwardedServers = [];\n }\n\n /**\n * Checks if a specified host is available by performing a DNS lookup.\n * @param hostname - The hostname or IP address to check.\n * @returns A promise resolving with `true` if the host is reachable, otherwise `false`.\n */\n public static async checkHostAvailability(hostname: string): Promise<boolean> {\n return new Promise((resolve) => {\n dns.lookup(hostname, (err) => {\n resolve(!err);\n });\n });\n }\n\n /**\n * Determines whether a private key requires a passphrase for use.\n * @param privateKey - The private key content to check.\n * @returns A promise resolving with `true` if a passphrase is required, otherwise `false`.\n */\n public static async isPassphraseRequiredForKey(privateKey: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n try {\n const keyOrError = ssh.utils.parseKey(privateKey);\n if (keyOrError instanceof Error) {\n resolve(true);\n }\n return resolve(false);\n } catch (err: unknown) {\n console.log('Error parsing privateKey');\n reject(new Error(`ssh.isPassphraseRequiredForKey: err ${err}`));\n }\n });\n }\n\n /**\n * Uploads a local file to a remote server via SFTP.\n * This function creates new SFTP connection\n * @param localPath - The local file path.\n * @param remotePath - The remote file path on the server.\n * @returns A promise resolving with `true` if the file was successfully uploaded.\n */\n public async uploadFile(localPath: string, remotePath: string): Promise<boolean> {\n return await retry<boolean>(\n async () => {\n return await this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.fastPut(localPath, remotePath, (err) => {\n if (err) {\n const newErr = new SFTPUploadError(err, localPath, remotePath);\n return reject(newErr);\n }\n resolve(true);\n });\n });\n });\n },\n Retry3TimesWithDelay,\n (e: any) => SFTPError.from(e)?.isGenericFailure ?? false, // retry unknown upload errors\n );\n }\n\n public async withSftp<R>(callback: (sftp: SFTPWrapper) => Promise<R>): Promise<R> {\n return new Promise((resolve, reject) => {\n this.client.sftp((err, sftp) => {\n if (err) {\n return reject(new Error(`ssh.withSftp: sftp err: ${err}`, { cause: err }));\n }\n\n callback(sftp)\n .then(resolve)\n .catch((err) => {\n reject(new Error(`ssh.withSftp.callback: err ${err}`, { cause: err }));\n })\n .finally(() => {\n sftp?.end();\n });\n });\n });\n }\n\n public async writeFileOnTheServer(remotePath: string, data: string | Buffer, mode: number = 0o660) {\n return this.withSftp(async (sftp) => {\n return this.writeFile(sftp, remotePath, data, mode);\n });\n }\n\n public async getForderStructure(sftp: SFTPWrapper, remotePath: string, data: SshDirContent = { files: [], directories: [] }): Promise<SshDirContent> {\n return new Promise((resolve, reject) => {\n sftp.readdir(remotePath, async (err, items) => {\n if (err) {\n return reject(err);\n }\n\n for (const item of items) {\n const itemPath = `${remotePath}/${item.filename}`;\n if (item.attrs.isDirectory()) {\n data.directories.push(itemPath);\n try {\n await this.getForderStructure(sftp, itemPath, data);\n } catch (error) {\n return reject(error instanceof Error ? error : new Error(String(error)));\n }\n } else {\n data.files.push(itemPath);\n }\n }\n resolve(data);\n });\n });\n }\n\n public rmdir(sftp: SFTPWrapper, path: string) {\n return new Promise((resolve, reject) => {\n sftp.rmdir(path, (err) => err ? reject(err) : resolve(true));\n });\n }\n\n public unlink(sftp: SFTPWrapper, path: string) {\n return new Promise((resolve, reject) => {\n sftp.unlink(path, (err) => err ? reject(err) : resolve(true));\n });\n }\n\n public async deleteFolder(path: string) {\n return this.withSftp(async (sftp) => {\n try {\n const list = await this.getForderStructure(sftp, path);\n this.logger.info(`ssh.deleteFolder list of files and directories`);\n this.logger.info(`ssh.deleteFolder list of files: ${list.files}`);\n this.logger.info(`ssh.deleteFolder list of directories: ${list.directories}`);\n\n for (const filePath of list.files) {\n this.logger.info(`ssh.deleteFolder unlink file ${filePath}`);\n await this.unlink(sftp, filePath);\n }\n\n list.directories.sort((a, b) => b.length - a.length);\n\n for (const directoryPath of list.directories) {\n this.logger.info(`ssh.deleteFolder rmdir ${directoryPath}`);\n await this.rmdir(sftp, directoryPath);\n }\n\n await this.rmdir(sftp, path);\n return true;\n } catch (e: unknown) {\n this.logger.error(e);\n const message = e instanceof Error ? e.message : '';\n throw new Error(`ssh.deleteFolder: path: ${path}, message: ${message}`);\n }\n });\n }\n\n public async readFile(remotePath: string): Promise<string> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.readFile(remotePath, (err, buffer) => {\n if (err) {\n return reject(new Error(`ssh.readFile: ${err}`));\n }\n resolve(buffer.toString());\n });\n });\n });\n }\n\n async chmod(path: string, mode: number) {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.chmod(path, mode, (err) => {\n if (err) {\n return reject(new Error(`ssh.chmod: ${err}, path: ${path}, mode: ${mode}`));\n }\n return resolve(undefined);\n });\n });\n });\n }\n\n async checkFileExists(remotePath: string) {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.stat(remotePath, (err: Error | undefined, stats) => {\n if (err) {\n if ((err as unknown as { code?: number })?.code === 2) {\n return resolve(false);\n }\n return reject(new Error(`ssh.checkFileExists: err ${err}`));\n }\n resolve(stats.isFile());\n });\n });\n });\n }\n\n async checkPathExists(remotePath: string): Promise<{ exists: boolean; isFile: boolean; isDirectory: boolean }> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.stat(remotePath, (err, stats) => {\n if (err) {\n if ((err as Error & { code: number }).code === 2) {\n return resolve({ exists: false, isFile: false, isDirectory: false });\n }\n return reject(new Error(`ssh.checkPathExists: ${err}`));\n }\n resolve({\n exists: true,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n });\n });\n });\n });\n }\n\n private async writeFile(sftp: SFTPWrapper, remotePath: string, data: string | Buffer, mode: number = 0o660): Promise<boolean> {\n return new Promise((resolve, reject) => {\n sftp.writeFile(remotePath, data, { mode }, (err) => {\n if (err) {\n return reject(new Error(`ssh.writeFile: err ${err}, remotePath: ${remotePath}`));\n }\n resolve(true);\n });\n });\n }\n\n public uploadFileUsingExistingSftp(sftp: SFTPWrapper, localPath: string, remotePath: string, mode: number = 0o660) {\n return new Promise((resolve, reject) => {\n void readFile(localPath).then(async (result: Buffer) => {\n return this.writeFile(sftp, remotePath, result, mode)\n .then(() => {\n resolve(undefined);\n })\n .catch((err) => {\n const msg = `uploadFileUsingExistingSftp: ${err}`;\n this.logger.error(msg);\n reject(new Error(msg));\n });\n });\n });\n }\n\n private async __uploadDirectory(sftp: SFTPWrapper, localDir: string, remoteDir: string, mode: number = 0o660): Promise<void> {\n return new Promise((resolve, reject) => {\n fs.readdir(localDir, async (err, files) => {\n if (err) {\n return reject(new Error(`ssh.__uploadDir: err ${err}, localDir: ${localDir}, remoteDir: ${remoteDir}`));\n }\n\n try {\n await this.__createRemoteDirectory(sftp, remoteDir);\n for (const file of files) {\n const localPath = upath.join(localDir, file);\n const remotePath = `${remoteDir}/${file}`;\n\n if (fs.lstatSync(localPath).isDirectory()) {\n await this.__uploadDirectory(sftp, localPath, remotePath, mode);\n } else {\n await this.uploadFileUsingExistingSftp(sftp, localPath, remotePath, mode);\n }\n }\n\n resolve();\n } catch (err) {\n const msg = `ssh.__uploadDir: catched err ${err}`;\n this.logger.error(msg);\n reject(new Error(msg));\n }\n });\n });\n }\n\n /**\n * Uploads a local directory and its contents (including subdirectories) to the remote server via SFTP.\n * @param localDir - The path to the local directory to upload.\n * @param remoteDir - The path to the remote directory on the server.\n * @returns A promise that resolves when the directory and its contents are uploaded.\n */\n public async uploadDirectory(localDir: string, remoteDir: string, mode: number = 0o660): Promise<void> {\n return new Promise((resolve, reject) => {\n void this.withSftp(async (sftp: SFTPWrapper) => {\n try {\n await this.__uploadDirectory(sftp, localDir, remoteDir, mode);\n resolve();\n } catch (e: unknown) {\n reject(new Error(`ssh.uploadDirectory: ${e}`));\n }\n });\n });\n }\n\n /**\n * Ensures that a remote directory and all its parent directories exist.\n * @param sftp - The SFTP wrapper.\n * @param remotePath - The path to the remote directory.\n * @returns A promise that resolves when the directory is created.\n */\n private __createRemoteDirectory(sftp: SFTPWrapper, remotePath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const directories = remotePath.split('/');\n let currentPath = '';\n\n const createNext = (index: number) => {\n if (index >= directories.length) {\n return resolve();\n }\n\n currentPath += `${directories[index]}/`;\n\n sftp.stat(currentPath, (err) => {\n if (err) {\n sftp.mkdir(currentPath, (err) => {\n if (err) {\n return reject(new Error(`ssh.__createRemDir: err ${err}, remotePath: ${remotePath}`));\n }\n createNext(index + 1);\n });\n } else {\n createNext(index + 1);\n }\n });\n };\n\n createNext(0);\n });\n }\n\n /**\n * Ensures that a remote directory and all its parent directories exist.\n * @param sftp - The SFTP wrapper.\n * @param remotePath - The path to the remote directory.\n * @returns A promise that resolves when the directory is created.\n */\n public ensureRemoteDirCreated(remotePath: string, mode: number = 0o755): Promise<void> {\n return this.withSftp(async (sftp) => {\n const directories = remotePath.split('/');\n let currentPath = '';\n\n for (const directory of directories) {\n currentPath += `${directory}/`;\n\n try {\n await new Promise<void>((resolve, reject) => {\n sftp.stat(currentPath, (err) => {\n if (!err) return resolve();\n\n sftp.mkdir(currentPath, { mode }, (err) => {\n if (err) {\n return reject(new Error(`ssh.createRemoteDir: err ${err}, remotePath: ${remotePath}`));\n }\n resolve();\n });\n });\n });\n } catch (error) {\n console.error(`Failed to create directory: ${currentPath}`, error);\n throw error;\n }\n }\n });\n }\n\n /**\n * Downloads a file from the remote server to a local path via SFTP.\n * @param remotePath - The remote file path on the server.\n * @param localPath - The local file path to save the file.\n * @returns A promise resolving with `true` if the file was successfully downloaded.\n */\n public async downloadFile(remotePath: string, localPath: string): Promise<boolean> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.fastGet(remotePath, localPath, (err) => {\n if (err) {\n return reject(new Error(`ssh.downloadFile: err ${err}, remotePath: ${remotePath}, localPath: ${localPath}`));\n }\n resolve(true);\n });\n });\n });\n }\n\n /**\n * Closes the SSH client connection and forwarded ports.\n */\n public close(): void {\n this.closeForwardedPorts();\n this.client.end();\n }\n}\n\nexport type SshExecResult = { stdout: string; stderr: string };\n\nasync function connect(\n client: Client,\n config: ConnectConfig,\n onError: (e: unknown) => void,\n onClose: () => void,\n): Promise<Client> {\n return new Promise((resolve, reject) => {\n client.on('ready', () => {\n resolve(client);\n });\n\n client.on('error', (err: unknown) => {\n onError(err);\n reject(new Error(`ssh.connect: ${err}`));\n });\n\n client.on('close', () => {\n onClose();\n });\n\n client.connect(config);\n\n // Remove TCP buffering.\n // Although it means less throughput (bad), it also means less latency (good).\n // It could help when we have\n // small messages like in our grpc transactions.\n // And it also could help when we have tcp forwarding to not buffer messages in the middle.\n (client as any).setNoDelay(true);\n });\n}\n\nasync function forwardOut(logger: MiLogger, conn: Client, localHost: string, localPort: number, remoteHost: string, remotePort: number): Promise<ClientChannel> {\n return new Promise((resolve, reject) => {\n conn.forwardOut(localHost, localPort, remoteHost, remotePort, (err, stream) => {\n if (err) {\n logger.error(`forwardOut.error: ${err}`);\n return reject(err);\n }\n\n return resolve(stream);\n });\n });\n}\n"],"names":["Client","randomBytes","RetryablePromise","retry","SFTPUploadError","Retry3TimesWithDelay","SFTPError","readFile"],"mappings":"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"}
|
package/dist/ssh/ssh.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssh.d.ts","sourceRoot":"","sources":["../../src/ssh/ssh.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAiB,WAAW,EAAE,MAAM,MAAM,CAAC;AACtE,OAAO,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,GAAG,MAAM,UAAU,CAAC;AAK3B,OAAO,
|
|
1
|
+
{"version":3,"file":"ssh.d.ts","sourceRoot":"","sources":["../../src/ssh/ssh.ts"],"names":[],"mappings":"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"}
|
package/dist/ssh/ssh.js
CHANGED
|
@@ -4,8 +4,9 @@ import dns from 'node:dns';
|
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import { readFile } from 'node:fs/promises';
|
|
6
6
|
import upath from 'upath';
|
|
7
|
-
import { RetryablePromise } from '@milaboratories/ts-helpers';
|
|
7
|
+
import { RetryablePromise, retry, Retry3TimesWithDelay } from '@milaboratories/ts-helpers';
|
|
8
8
|
import { randomBytes } from 'node:crypto';
|
|
9
|
+
import { SFTPUploadError, SFTPError } from './ssh_errors.js';
|
|
9
10
|
|
|
10
11
|
const defaultConfig = {
|
|
11
12
|
keepaliveInterval: 60000,
|
|
@@ -268,28 +269,30 @@ class SshClient {
|
|
|
268
269
|
* @returns A promise resolving with `true` if the file was successfully uploaded.
|
|
269
270
|
*/
|
|
270
271
|
async uploadFile(localPath, remotePath) {
|
|
271
|
-
return await
|
|
272
|
-
return
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
272
|
+
return await retry(async () => {
|
|
273
|
+
return await this.withSftp(async (sftp) => {
|
|
274
|
+
return new Promise((resolve, reject) => {
|
|
275
|
+
sftp.fastPut(localPath, remotePath, (err) => {
|
|
276
|
+
if (err) {
|
|
277
|
+
const newErr = new SFTPUploadError(err, localPath, remotePath);
|
|
278
|
+
return reject(newErr);
|
|
279
|
+
}
|
|
280
|
+
resolve(true);
|
|
281
|
+
});
|
|
279
282
|
});
|
|
280
283
|
});
|
|
281
|
-
});
|
|
284
|
+
}, Retry3TimesWithDelay, (e) => SFTPError.from(e)?.isGenericFailure ?? false);
|
|
282
285
|
}
|
|
283
286
|
async withSftp(callback) {
|
|
284
287
|
return new Promise((resolve, reject) => {
|
|
285
288
|
this.client.sftp((err, sftp) => {
|
|
286
289
|
if (err) {
|
|
287
|
-
return reject(new Error(`ssh.withSftp: sftp err: ${err}
|
|
290
|
+
return reject(new Error(`ssh.withSftp: sftp err: ${err}`, { cause: err }));
|
|
288
291
|
}
|
|
289
292
|
callback(sftp)
|
|
290
293
|
.then(resolve)
|
|
291
294
|
.catch((err) => {
|
|
292
|
-
reject(new Error(`ssh.withSftp.callback: err ${err}
|
|
295
|
+
reject(new Error(`ssh.withSftp.callback: err ${err}`, { cause: err }));
|
|
293
296
|
})
|
|
294
297
|
.finally(() => {
|
|
295
298
|
sftp?.end();
|
package/dist/ssh/ssh.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssh.js","sources":["../../src/ssh/ssh.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-misused-promises */\n/* eslint-disable @typescript-eslint/no-base-to-string */\nimport type { ConnectConfig, ClientChannel, SFTPWrapper } from 'ssh2';\nimport ssh, { Client } from 'ssh2';\nimport net from 'node:net';\nimport dns from 'node:dns';\nimport fs from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport upath from 'upath';\nimport { RetryablePromise, type MiLogger } from '@milaboratories/ts-helpers';\nimport { randomBytes } from 'node:crypto';\n\nconst defaultConfig: ConnectConfig = {\n keepaliveInterval: 60000,\n keepaliveCountMax: 10,\n};\n\nexport type SshAuthMethods = 'publickey' | 'password';\nexport type SshAuthMethodsResult = SshAuthMethods[];\nexport type SshDirContent = {\n files: string[];\n directories: string[];\n};\n\nexport class SshClient {\n private config?: ConnectConfig;\n public homeDir?: string;\n private forwardedServers: net.Server[] = [];\n\n constructor(\n private readonly logger: MiLogger,\n private readonly client: Client,\n ) {}\n\n /**\n * Initializes the SshClient and establishes a connection using the provided configuration.\n * @param config - The connection configuration object for the SSH client.\n * @returns A new instance of SshClient with an active connection.\n */\n public static async init(logger: MiLogger, config: ConnectConfig): Promise<SshClient> {\n const withDefaults = {\n ...defaultConfig,\n ...config,\n };\n\n const client = new SshClient(logger, new Client());\n await client.connect(withDefaults);\n\n return client;\n }\n\n public getForwardedServers() {\n return this.forwardedServers;\n }\n\n public getFullHostName() {\n return `${this.config?.host}:${this.config?.port}`;\n }\n\n public getUserName() {\n return this.config?.username;\n }\n\n /**\n * Connects to the SSH server using the specified configuration.\n * @param config - The connection configuration object for the SSH client.\n * @returns A promise that resolves when the connection is established or rejects on error.\n */\n public async connect(config: ConnectConfig) {\n this.config = config;\n return await connect(this.client, config, () => {}, () => {});\n }\n\n /**\n * Executes a command on the SSH server.\n * @param command - The command to execute on the remote server.\n * @returns A promise resolving with the command's stdout and stderr outputs.\n */\n public async exec(command: string): Promise<SshExecResult> {\n return new Promise((resolve, reject) => {\n this.client.exec(command, (err: any, stream: ClientChannel) => {\n if (err) {\n return reject(new Error(`ssh.exec: ${command}: ${err}`));\n }\n\n let stdout = '';\n let stderr = '';\n\n stream.on('close', (code: number) => {\n if (code === 0) {\n resolve({ stdout, stderr });\n } else {\n reject(new Error(`Command ${command} exited with code ${code}, stdout: ${stdout}, stderr: ${stderr}`));\n }\n }).on('data', (data: ArrayBuffer) => {\n stdout += data.toString();\n }).stderr.on('data', (data: ArrayBuffer) => {\n stderr += data.toString();\n });\n });\n });\n }\n\n /**\n * Retrieves the supported authentication methods for a given host and port.\n * @param host - The hostname or IP address of the server.\n * @param port - The port number to connect to on the server.\n * @returns 'publickey' | 'password'[] A promise resolving with a list of supported authentication methods.\n */\n public static async getAuthTypes(host: string, port: number): Promise<SshAuthMethodsResult> {\n return new Promise((resolve) => {\n let stdout = '';\n const conn = new Client();\n\n conn.on('ready', () => {\n conn.end();\n const types = this.extractAuthMethods(stdout);\n resolve(types.length === 0 ? ['publickey', 'password'] : types as SshAuthMethodsResult);\n });\n\n conn.on('error', () => {\n conn.end();\n resolve(['publickey', 'password']);\n });\n\n conn.connect({\n host,\n port,\n username: new Date().getTime().toString(),\n debug: (err) => {\n stdout += `${err}\\n`;\n },\n });\n });\n }\n\n /**\n * Extracts authentication methods from debug logs.\n * @param log - The debug log output containing authentication information.\n * @returns An array of extracted authentication methods.\n */\n private static extractAuthMethods(log: string): string[] {\n const match = log.match(/Inbound: Received USERAUTH_FAILURE \\((.+)\\)/);\n return match && match[1] ? match[1].split(',').map((method) => method.trim()) : [];\n }\n\n /**\n * Sets up port forwarding between a remote port on the SSH server and a local port.\n * A new connection is used for this operation instead of an existing one.\n * @param ports - An object specifying the remote and local port configuration.\n * @param config - Optional connection configuration for the SSH client.\n * @returns { server: net.Server } A promise resolving with the created server instance.\n */\n public async forwardPort(ports: { remotePort: number; localPort: number; localHost?: string }, config?: ConnectConfig): Promise<{ server: net.Server }> {\n const log = `ssh.forward:${ports.localPort}:${ports.remotePort}.id_${randomBytes(1).toString('hex')}`;\n config = config ?? this.config;\n\n // we make this thing persistent so that if the connection\n // drops (it happened in the past because of lots of errors and forwardOut opened channels),\n // we'll recreate it here.\n const persistentClient = new RetryablePromise((p: RetryablePromise<Client>) => {\n return new Promise<Client>((resolve, reject) => {\n const client = new Client();\n\n client.on('ready', () => {\n this.logger.info(`${log}.client.ready`);\n resolve(client);\n });\n\n client.on('error', (err) => {\n this.logger.info(`${log}.client.error: ${err}`);\n p.reset();\n reject(err);\n });\n\n client.on('close', () => {\n this.logger.info(`${log}.client.closed`);\n p.reset();\n });\n\n client.connect(config!);\n });\n });\n\n await persistentClient.ensure(); // warm up a connection\n\n return new Promise((resolve, reject) => {\n const server = net.createServer({ pauseOnConnect: true }, async (localSocket) => {\n const sockLog = `${log}.sock_${randomBytes(1).toString('hex')}`;\n // this.logger.info(`${sockLog}.localSocket: start connection`);\n let conn: Client;\n try {\n conn = await persistentClient.ensure();\n } catch (e: unknown) {\n this.logger.info(`${sockLog}.persistentClient.catch: ${e}`);\n localSocket.end();\n return;\n }\n\n // Remove TCP buffering.\n // Although it means less throughput (bad), it also less latency (good).\n // It could help when we have\n // small messages like in our grpc transactions.\n // And it also could help when we have tcp forwarding to not buffer messages in the middle.\n (conn as any).setNoDelay(true);\n localSocket.setNoDelay(true);\n\n let stream: ClientChannel;\n try {\n stream = await forwardOut(this.logger, conn, '127.0.0.1', 0, '127.0.0.1', ports.remotePort);\n } catch (e: unknown) {\n this.logger.error(`${sockLog}.forwardOut.err: ${e}`);\n localSocket.end();\n return;\n }\n\n localSocket.pipe(stream);\n stream.pipe(localSocket);\n localSocket.resume();\n // this.logger.info(`${sockLog}.forwardOut: connected`);\n\n stream.on('error', (err: unknown) => {\n this.logger.error(`${sockLog}.stream.error: ${err}`);\n localSocket.end();\n stream.end();\n });\n stream.on('close', () => {\n // this.logger.info(`${sockLog}.stream.close: closed`);\n localSocket.end();\n stream.end();\n });\n localSocket.on('close', () => {\n this.logger.info(`${sockLog}.localSocket: closed`);\n localSocket.end();\n stream.end();\n });\n });\n\n server.listen(ports.localPort, '127.0.0.1', () => {\n this.logger.info(`${log}.server: started listening`);\n this.forwardedServers.push(server);\n resolve({ server });\n });\n\n server.on('error', (err) => {\n server.close();\n reject(new Error(`${log}.server: error: ${JSON.stringify(err)}`));\n });\n\n server.on('close', () => {\n this.logger.info(`${log}.server: closed ${JSON.stringify(ports)}`);\n this.forwardedServers = this.forwardedServers.filter((s) => s !== server);\n });\n });\n }\n\n public closeForwardedPorts(): void {\n this.logger.info('[SSH] Closing all forwarded ports...');\n this.forwardedServers.forEach((server) => {\n const rawAddress = server.address();\n if (rawAddress && typeof rawAddress !== 'string') {\n const address: net.AddressInfo = rawAddress;\n this.logger.info(`[SSH] Closing port forward for server ${address.address}:${address.port}`);\n }\n\n server.close();\n });\n this.forwardedServers = [];\n }\n\n /**\n * Checks if a specified host is available by performing a DNS lookup.\n * @param hostname - The hostname or IP address to check.\n * @returns A promise resolving with `true` if the host is reachable, otherwise `false`.\n */\n public static async checkHostAvailability(hostname: string): Promise<boolean> {\n return new Promise((resolve) => {\n dns.lookup(hostname, (err) => {\n resolve(!err);\n });\n });\n }\n\n /**\n * Determines whether a private key requires a passphrase for use.\n * @param privateKey - The private key content to check.\n * @returns A promise resolving with `true` if a passphrase is required, otherwise `false`.\n */\n public static async isPassphraseRequiredForKey(privateKey: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n try {\n const keyOrError = ssh.utils.parseKey(privateKey);\n if (keyOrError instanceof Error) {\n resolve(true);\n }\n return resolve(false);\n } catch (err: unknown) {\n console.log('Error parsing privateKey');\n reject(new Error(`ssh.isPassphraseRequiredForKey: err ${err}`));\n }\n });\n }\n\n /**\n * Uploads a local file to a remote server via SFTP.\n * This function creates new SFTP connection\n * @param localPath - The local file path.\n * @param remotePath - The remote file path on the server.\n * @returns A promise resolving with `true` if the file was successfully uploaded.\n */\n public async uploadFile(localPath: string, remotePath: string): Promise<boolean> {\n return await this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.fastPut(localPath, remotePath, (err) => {\n if (err) {\n const newErr = new Error(\n `ssh.uploadFile: err: ${err}, localPath: ${localPath}, remotePath: ${remotePath}`);\n return reject(newErr);\n }\n resolve(true);\n });\n });\n });\n }\n\n public async withSftp<R>(callback: (sftp: SFTPWrapper) => Promise<R>): Promise<R> {\n return new Promise((resolve, reject) => {\n this.client.sftp((err, sftp) => {\n if (err) {\n return reject(new Error(`ssh.withSftp: sftp err: ${err}`));\n }\n\n callback(sftp)\n .then(resolve)\n .catch((err) => {\n reject(new Error(`ssh.withSftp.callback: err ${err}`));\n })\n .finally(() => {\n sftp?.end();\n });\n });\n });\n }\n\n public async writeFileOnTheServer(remotePath: string, data: string | Buffer, mode: number = 0o660) {\n return this.withSftp(async (sftp) => {\n return this.writeFile(sftp, remotePath, data, mode);\n });\n }\n\n public async getForderStructure(sftp: SFTPWrapper, remotePath: string, data: SshDirContent = { files: [], directories: [] }): Promise<SshDirContent> {\n return new Promise((resolve, reject) => {\n sftp.readdir(remotePath, async (err, items) => {\n if (err) {\n return reject(err);\n }\n\n for (const item of items) {\n const itemPath = `${remotePath}/${item.filename}`;\n if (item.attrs.isDirectory()) {\n data.directories.push(itemPath);\n try {\n await this.getForderStructure(sftp, itemPath, data);\n } catch (error) {\n return reject(error instanceof Error ? error : new Error(String(error)));\n }\n } else {\n data.files.push(itemPath);\n }\n }\n resolve(data);\n });\n });\n }\n\n public rmdir(sftp: SFTPWrapper, path: string) {\n return new Promise((resolve, reject) => {\n sftp.rmdir(path, (err) => err ? reject(err) : resolve(true));\n });\n }\n\n public unlink(sftp: SFTPWrapper, path: string) {\n return new Promise((resolve, reject) => {\n sftp.unlink(path, (err) => err ? reject(err) : resolve(true));\n });\n }\n\n public async deleteFolder(path: string) {\n return this.withSftp(async (sftp) => {\n try {\n const list = await this.getForderStructure(sftp, path);\n this.logger.info(`ssh.deleteFolder list of files and directories`);\n this.logger.info(`ssh.deleteFolder list of files: ${list.files}`);\n this.logger.info(`ssh.deleteFolder list of directories: ${list.directories}`);\n\n for (const filePath of list.files) {\n this.logger.info(`ssh.deleteFolder unlink file ${filePath}`);\n await this.unlink(sftp, filePath);\n }\n\n list.directories.sort((a, b) => b.length - a.length);\n\n for (const directoryPath of list.directories) {\n this.logger.info(`ssh.deleteFolder rmdir ${directoryPath}`);\n await this.rmdir(sftp, directoryPath);\n }\n\n await this.rmdir(sftp, path);\n return true;\n } catch (e: unknown) {\n this.logger.error(e);\n const message = e instanceof Error ? e.message : '';\n throw new Error(`ssh.deleteFolder: path: ${path}, message: ${message}`);\n }\n });\n }\n\n public async readFile(remotePath: string): Promise<string> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.readFile(remotePath, (err, buffer) => {\n if (err) {\n return reject(new Error(`ssh.readFile: ${err}`));\n }\n resolve(buffer.toString());\n });\n });\n });\n }\n\n async chmod(path: string, mode: number) {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.chmod(path, mode, (err) => {\n if (err) {\n return reject(new Error(`ssh.chmod: ${err}, path: ${path}, mode: ${mode}`));\n }\n return resolve(undefined);\n });\n });\n });\n }\n\n async checkFileExists(remotePath: string) {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.stat(remotePath, (err: Error | undefined, stats) => {\n if (err) {\n if ((err as unknown as { code?: number })?.code === 2) {\n return resolve(false);\n }\n return reject(new Error(`ssh.checkFileExists: err ${err}`));\n }\n resolve(stats.isFile());\n });\n });\n });\n }\n\n async checkPathExists(remotePath: string): Promise<{ exists: boolean; isFile: boolean; isDirectory: boolean }> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.stat(remotePath, (err, stats) => {\n if (err) {\n if ((err as Error & { code: number }).code === 2) {\n return resolve({ exists: false, isFile: false, isDirectory: false });\n }\n return reject(new Error(`ssh.checkPathExists: ${err}`));\n }\n resolve({\n exists: true,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n });\n });\n });\n });\n }\n\n private async writeFile(sftp: SFTPWrapper, remotePath: string, data: string | Buffer, mode: number = 0o660): Promise<boolean> {\n return new Promise((resolve, reject) => {\n sftp.writeFile(remotePath, data, { mode }, (err) => {\n if (err) {\n return reject(new Error(`ssh.writeFile: err ${err}, remotePath: ${remotePath}`));\n }\n resolve(true);\n });\n });\n }\n\n public uploadFileUsingExistingSftp(sftp: SFTPWrapper, localPath: string, remotePath: string, mode: number = 0o660) {\n return new Promise((resolve, reject) => {\n void readFile(localPath).then(async (result: Buffer) => {\n return this.writeFile(sftp, remotePath, result, mode)\n .then(() => {\n resolve(undefined);\n })\n .catch((err) => {\n const msg = `uploadFileUsingExistingSftp: ${err}`;\n this.logger.error(msg);\n reject(new Error(msg));\n });\n });\n });\n }\n\n private async __uploadDirectory(sftp: SFTPWrapper, localDir: string, remoteDir: string, mode: number = 0o660): Promise<void> {\n return new Promise((resolve, reject) => {\n fs.readdir(localDir, async (err, files) => {\n if (err) {\n return reject(new Error(`ssh.__uploadDir: err ${err}, localDir: ${localDir}, remoteDir: ${remoteDir}`));\n }\n\n try {\n await this.__createRemoteDirectory(sftp, remoteDir);\n for (const file of files) {\n const localPath = upath.join(localDir, file);\n const remotePath = `${remoteDir}/${file}`;\n\n if (fs.lstatSync(localPath).isDirectory()) {\n await this.__uploadDirectory(sftp, localPath, remotePath, mode);\n } else {\n await this.uploadFileUsingExistingSftp(sftp, localPath, remotePath, mode);\n }\n }\n\n resolve();\n } catch (err) {\n const msg = `ssh.__uploadDir: catched err ${err}`;\n this.logger.error(msg);\n reject(new Error(msg));\n }\n });\n });\n }\n\n /**\n * Uploads a local directory and its contents (including subdirectories) to the remote server via SFTP.\n * @param localDir - The path to the local directory to upload.\n * @param remoteDir - The path to the remote directory on the server.\n * @returns A promise that resolves when the directory and its contents are uploaded.\n */\n public async uploadDirectory(localDir: string, remoteDir: string, mode: number = 0o660): Promise<void> {\n return new Promise((resolve, reject) => {\n void this.withSftp(async (sftp: SFTPWrapper) => {\n try {\n await this.__uploadDirectory(sftp, localDir, remoteDir, mode);\n resolve();\n } catch (e: unknown) {\n reject(new Error(`ssh.uploadDirectory: ${e}`));\n }\n });\n });\n }\n\n /**\n * Ensures that a remote directory and all its parent directories exist.\n * @param sftp - The SFTP wrapper.\n * @param remotePath - The path to the remote directory.\n * @returns A promise that resolves when the directory is created.\n */\n private __createRemoteDirectory(sftp: SFTPWrapper, remotePath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const directories = remotePath.split('/');\n let currentPath = '';\n\n const createNext = (index: number) => {\n if (index >= directories.length) {\n return resolve();\n }\n\n currentPath += `${directories[index]}/`;\n\n sftp.stat(currentPath, (err) => {\n if (err) {\n sftp.mkdir(currentPath, (err) => {\n if (err) {\n return reject(new Error(`ssh.__createRemDir: err ${err}, remotePath: ${remotePath}`));\n }\n createNext(index + 1);\n });\n } else {\n createNext(index + 1);\n }\n });\n };\n\n createNext(0);\n });\n }\n\n /**\n * Ensures that a remote directory and all its parent directories exist.\n * @param sftp - The SFTP wrapper.\n * @param remotePath - The path to the remote directory.\n * @returns A promise that resolves when the directory is created.\n */\n public ensureRemoteDirCreated(remotePath: string, mode: number = 0o755): Promise<void> {\n return this.withSftp(async (sftp) => {\n const directories = remotePath.split('/');\n let currentPath = '';\n\n for (const directory of directories) {\n currentPath += `${directory}/`;\n\n try {\n await new Promise<void>((resolve, reject) => {\n sftp.stat(currentPath, (err) => {\n if (!err) return resolve();\n\n sftp.mkdir(currentPath, { mode }, (err) => {\n if (err) {\n return reject(new Error(`ssh.createRemoteDir: err ${err}, remotePath: ${remotePath}`));\n }\n resolve();\n });\n });\n });\n } catch (error) {\n console.error(`Failed to create directory: ${currentPath}`, error);\n throw error;\n }\n }\n });\n }\n\n /**\n * Downloads a file from the remote server to a local path via SFTP.\n * @param remotePath - The remote file path on the server.\n * @param localPath - The local file path to save the file.\n * @returns A promise resolving with `true` if the file was successfully downloaded.\n */\n public async downloadFile(remotePath: string, localPath: string): Promise<boolean> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.fastGet(remotePath, localPath, (err) => {\n if (err) {\n return reject(new Error(`ssh.downloadFile: err ${err}, remotePath: ${remotePath}, localPath: ${localPath}`));\n }\n resolve(true);\n });\n });\n });\n }\n\n /**\n * Closes the SSH client connection and forwarded ports.\n */\n public close(): void {\n this.closeForwardedPorts();\n this.client.end();\n }\n}\n\nexport type SshExecResult = { stdout: string; stderr: string };\n\nasync function connect(\n client: Client,\n config: ConnectConfig,\n onError: (e: unknown) => void,\n onClose: () => void,\n): Promise<Client> {\n return new Promise((resolve, reject) => {\n client.on('ready', () => {\n resolve(client);\n });\n\n client.on('error', (err: unknown) => {\n onError(err);\n reject(new Error(`ssh.connect: ${err}`));\n });\n\n client.on('close', () => {\n onClose();\n });\n\n client.connect(config);\n\n // Remove TCP buffering.\n // Although it means less throughput (bad), it also means less latency (good).\n // It could help when we have\n // small messages like in our grpc transactions.\n // And it also could help when we have tcp forwarding to not buffer messages in the middle.\n (client as any).setNoDelay(true);\n });\n}\n\nasync function forwardOut(logger: MiLogger, conn: Client, localHost: string, localPort: number, remoteHost: string, remotePort: number): Promise<ClientChannel> {\n return new Promise((resolve, reject) => {\n conn.forwardOut(localHost, localPort, remoteHost, remotePort, (err, stream) => {\n if (err) {\n logger.error(`forwardOut.error: ${err}`);\n return reject(err);\n }\n\n return resolve(stream);\n });\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ssh.js","sources":["../../src/ssh/ssh.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-misused-promises */\n/* eslint-disable @typescript-eslint/no-base-to-string */\nimport type { ConnectConfig, ClientChannel, SFTPWrapper } from 'ssh2';\nimport ssh, { Client } from 'ssh2';\nimport net from 'node:net';\nimport dns from 'node:dns';\nimport fs from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport upath from 'upath';\nimport { RetryablePromise, retry, type MiLogger, Retry3TimesWithDelay } from '@milaboratories/ts-helpers';\nimport { randomBytes } from 'node:crypto';\nimport { SFTPUploadError, SFTPError } from './ssh_errors';\n\nconst defaultConfig: ConnectConfig = {\n keepaliveInterval: 60000,\n keepaliveCountMax: 10,\n};\n\nexport type SshAuthMethods = 'publickey' | 'password';\nexport type SshAuthMethodsResult = SshAuthMethods[];\nexport type SshDirContent = {\n files: string[];\n directories: string[];\n};\n\nexport class SshClient {\n private config?: ConnectConfig;\n public homeDir?: string;\n private forwardedServers: net.Server[] = [];\n\n constructor(\n private readonly logger: MiLogger,\n private readonly client: Client,\n ) {}\n\n /**\n * Initializes the SshClient and establishes a connection using the provided configuration.\n * @param config - The connection configuration object for the SSH client.\n * @returns A new instance of SshClient with an active connection.\n */\n public static async init(logger: MiLogger, config: ConnectConfig): Promise<SshClient> {\n const withDefaults = {\n ...defaultConfig,\n ...config,\n };\n\n const client = new SshClient(logger, new Client());\n await client.connect(withDefaults);\n\n return client;\n }\n\n public getForwardedServers() {\n return this.forwardedServers;\n }\n\n public getFullHostName() {\n return `${this.config?.host}:${this.config?.port}`;\n }\n\n public getUserName() {\n return this.config?.username;\n }\n\n /**\n * Connects to the SSH server using the specified configuration.\n * @param config - The connection configuration object for the SSH client.\n * @returns A promise that resolves when the connection is established or rejects on error.\n */\n public async connect(config: ConnectConfig) {\n this.config = config;\n return await connect(this.client, config, () => {}, () => {});\n }\n\n /**\n * Executes a command on the SSH server.\n * @param command - The command to execute on the remote server.\n * @returns A promise resolving with the command's stdout and stderr outputs.\n */\n public async exec(command: string): Promise<SshExecResult> {\n return new Promise((resolve, reject) => {\n this.client.exec(command, (err: any, stream: ClientChannel) => {\n if (err) {\n return reject(new Error(`ssh.exec: ${command}: ${err}`));\n }\n\n let stdout = '';\n let stderr = '';\n\n stream.on('close', (code: number) => {\n if (code === 0) {\n resolve({ stdout, stderr });\n } else {\n reject(new Error(`Command ${command} exited with code ${code}, stdout: ${stdout}, stderr: ${stderr}`));\n }\n }).on('data', (data: ArrayBuffer) => {\n stdout += data.toString();\n }).stderr.on('data', (data: ArrayBuffer) => {\n stderr += data.toString();\n });\n });\n });\n }\n\n /**\n * Retrieves the supported authentication methods for a given host and port.\n * @param host - The hostname or IP address of the server.\n * @param port - The port number to connect to on the server.\n * @returns 'publickey' | 'password'[] A promise resolving with a list of supported authentication methods.\n */\n public static async getAuthTypes(host: string, port: number): Promise<SshAuthMethodsResult> {\n return new Promise((resolve) => {\n let stdout = '';\n const conn = new Client();\n\n conn.on('ready', () => {\n conn.end();\n const types = this.extractAuthMethods(stdout);\n resolve(types.length === 0 ? ['publickey', 'password'] : types as SshAuthMethodsResult);\n });\n\n conn.on('error', () => {\n conn.end();\n resolve(['publickey', 'password']);\n });\n\n conn.connect({\n host,\n port,\n username: new Date().getTime().toString(),\n debug: (err) => {\n stdout += `${err}\\n`;\n },\n });\n });\n }\n\n /**\n * Extracts authentication methods from debug logs.\n * @param log - The debug log output containing authentication information.\n * @returns An array of extracted authentication methods.\n */\n private static extractAuthMethods(log: string): string[] {\n const match = log.match(/Inbound: Received USERAUTH_FAILURE \\((.+)\\)/);\n return match && match[1] ? match[1].split(',').map((method) => method.trim()) : [];\n }\n\n /**\n * Sets up port forwarding between a remote port on the SSH server and a local port.\n * A new connection is used for this operation instead of an existing one.\n * @param ports - An object specifying the remote and local port configuration.\n * @param config - Optional connection configuration for the SSH client.\n * @returns { server: net.Server } A promise resolving with the created server instance.\n */\n public async forwardPort(ports: { remotePort: number; localPort: number; localHost?: string }, config?: ConnectConfig): Promise<{ server: net.Server }> {\n const log = `ssh.forward:${ports.localPort}:${ports.remotePort}.id_${randomBytes(1).toString('hex')}`;\n config = config ?? this.config;\n\n // we make this thing persistent so that if the connection\n // drops (it happened in the past because of lots of errors and forwardOut opened channels),\n // we'll recreate it here.\n const persistentClient = new RetryablePromise((p: RetryablePromise<Client>) => {\n return new Promise<Client>((resolve, reject) => {\n const client = new Client();\n\n client.on('ready', () => {\n this.logger.info(`${log}.client.ready`);\n resolve(client);\n });\n\n client.on('error', (err) => {\n this.logger.info(`${log}.client.error: ${err}`);\n p.reset();\n reject(err);\n });\n\n client.on('close', () => {\n this.logger.info(`${log}.client.closed`);\n p.reset();\n });\n\n client.connect(config!);\n });\n });\n\n await persistentClient.ensure(); // warm up a connection\n\n return new Promise((resolve, reject) => {\n const server = net.createServer({ pauseOnConnect: true }, async (localSocket) => {\n const sockLog = `${log}.sock_${randomBytes(1).toString('hex')}`;\n // this.logger.info(`${sockLog}.localSocket: start connection`);\n let conn: Client;\n try {\n conn = await persistentClient.ensure();\n } catch (e: unknown) {\n this.logger.info(`${sockLog}.persistentClient.catch: ${e}`);\n localSocket.end();\n return;\n }\n\n // Remove TCP buffering.\n // Although it means less throughput (bad), it also less latency (good).\n // It could help when we have\n // small messages like in our grpc transactions.\n // And it also could help when we have tcp forwarding to not buffer messages in the middle.\n (conn as any).setNoDelay(true);\n localSocket.setNoDelay(true);\n\n let stream: ClientChannel;\n try {\n stream = await forwardOut(this.logger, conn, '127.0.0.1', 0, '127.0.0.1', ports.remotePort);\n } catch (e: unknown) {\n this.logger.error(`${sockLog}.forwardOut.err: ${e}`);\n localSocket.end();\n return;\n }\n\n localSocket.pipe(stream);\n stream.pipe(localSocket);\n localSocket.resume();\n // this.logger.info(`${sockLog}.forwardOut: connected`);\n\n stream.on('error', (err: unknown) => {\n this.logger.error(`${sockLog}.stream.error: ${err}`);\n localSocket.end();\n stream.end();\n });\n stream.on('close', () => {\n // this.logger.info(`${sockLog}.stream.close: closed`);\n localSocket.end();\n stream.end();\n });\n localSocket.on('close', () => {\n this.logger.info(`${sockLog}.localSocket: closed`);\n localSocket.end();\n stream.end();\n });\n });\n\n server.listen(ports.localPort, '127.0.0.1', () => {\n this.logger.info(`${log}.server: started listening`);\n this.forwardedServers.push(server);\n resolve({ server });\n });\n\n server.on('error', (err) => {\n server.close();\n reject(new Error(`${log}.server: error: ${JSON.stringify(err)}`));\n });\n\n server.on('close', () => {\n this.logger.info(`${log}.server: closed ${JSON.stringify(ports)}`);\n this.forwardedServers = this.forwardedServers.filter((s) => s !== server);\n });\n });\n }\n\n public closeForwardedPorts(): void {\n this.logger.info('[SSH] Closing all forwarded ports...');\n this.forwardedServers.forEach((server) => {\n const rawAddress = server.address();\n if (rawAddress && typeof rawAddress !== 'string') {\n const address: net.AddressInfo = rawAddress;\n this.logger.info(`[SSH] Closing port forward for server ${address.address}:${address.port}`);\n }\n\n server.close();\n });\n this.forwardedServers = [];\n }\n\n /**\n * Checks if a specified host is available by performing a DNS lookup.\n * @param hostname - The hostname or IP address to check.\n * @returns A promise resolving with `true` if the host is reachable, otherwise `false`.\n */\n public static async checkHostAvailability(hostname: string): Promise<boolean> {\n return new Promise((resolve) => {\n dns.lookup(hostname, (err) => {\n resolve(!err);\n });\n });\n }\n\n /**\n * Determines whether a private key requires a passphrase for use.\n * @param privateKey - The private key content to check.\n * @returns A promise resolving with `true` if a passphrase is required, otherwise `false`.\n */\n public static async isPassphraseRequiredForKey(privateKey: string): Promise<boolean> {\n return new Promise((resolve, reject) => {\n try {\n const keyOrError = ssh.utils.parseKey(privateKey);\n if (keyOrError instanceof Error) {\n resolve(true);\n }\n return resolve(false);\n } catch (err: unknown) {\n console.log('Error parsing privateKey');\n reject(new Error(`ssh.isPassphraseRequiredForKey: err ${err}`));\n }\n });\n }\n\n /**\n * Uploads a local file to a remote server via SFTP.\n * This function creates new SFTP connection\n * @param localPath - The local file path.\n * @param remotePath - The remote file path on the server.\n * @returns A promise resolving with `true` if the file was successfully uploaded.\n */\n public async uploadFile(localPath: string, remotePath: string): Promise<boolean> {\n return await retry<boolean>(\n async () => {\n return await this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.fastPut(localPath, remotePath, (err) => {\n if (err) {\n const newErr = new SFTPUploadError(err, localPath, remotePath);\n return reject(newErr);\n }\n resolve(true);\n });\n });\n });\n },\n Retry3TimesWithDelay,\n (e: any) => SFTPError.from(e)?.isGenericFailure ?? false, // retry unknown upload errors\n );\n }\n\n public async withSftp<R>(callback: (sftp: SFTPWrapper) => Promise<R>): Promise<R> {\n return new Promise((resolve, reject) => {\n this.client.sftp((err, sftp) => {\n if (err) {\n return reject(new Error(`ssh.withSftp: sftp err: ${err}`, { cause: err }));\n }\n\n callback(sftp)\n .then(resolve)\n .catch((err) => {\n reject(new Error(`ssh.withSftp.callback: err ${err}`, { cause: err }));\n })\n .finally(() => {\n sftp?.end();\n });\n });\n });\n }\n\n public async writeFileOnTheServer(remotePath: string, data: string | Buffer, mode: number = 0o660) {\n return this.withSftp(async (sftp) => {\n return this.writeFile(sftp, remotePath, data, mode);\n });\n }\n\n public async getForderStructure(sftp: SFTPWrapper, remotePath: string, data: SshDirContent = { files: [], directories: [] }): Promise<SshDirContent> {\n return new Promise((resolve, reject) => {\n sftp.readdir(remotePath, async (err, items) => {\n if (err) {\n return reject(err);\n }\n\n for (const item of items) {\n const itemPath = `${remotePath}/${item.filename}`;\n if (item.attrs.isDirectory()) {\n data.directories.push(itemPath);\n try {\n await this.getForderStructure(sftp, itemPath, data);\n } catch (error) {\n return reject(error instanceof Error ? error : new Error(String(error)));\n }\n } else {\n data.files.push(itemPath);\n }\n }\n resolve(data);\n });\n });\n }\n\n public rmdir(sftp: SFTPWrapper, path: string) {\n return new Promise((resolve, reject) => {\n sftp.rmdir(path, (err) => err ? reject(err) : resolve(true));\n });\n }\n\n public unlink(sftp: SFTPWrapper, path: string) {\n return new Promise((resolve, reject) => {\n sftp.unlink(path, (err) => err ? reject(err) : resolve(true));\n });\n }\n\n public async deleteFolder(path: string) {\n return this.withSftp(async (sftp) => {\n try {\n const list = await this.getForderStructure(sftp, path);\n this.logger.info(`ssh.deleteFolder list of files and directories`);\n this.logger.info(`ssh.deleteFolder list of files: ${list.files}`);\n this.logger.info(`ssh.deleteFolder list of directories: ${list.directories}`);\n\n for (const filePath of list.files) {\n this.logger.info(`ssh.deleteFolder unlink file ${filePath}`);\n await this.unlink(sftp, filePath);\n }\n\n list.directories.sort((a, b) => b.length - a.length);\n\n for (const directoryPath of list.directories) {\n this.logger.info(`ssh.deleteFolder rmdir ${directoryPath}`);\n await this.rmdir(sftp, directoryPath);\n }\n\n await this.rmdir(sftp, path);\n return true;\n } catch (e: unknown) {\n this.logger.error(e);\n const message = e instanceof Error ? e.message : '';\n throw new Error(`ssh.deleteFolder: path: ${path}, message: ${message}`);\n }\n });\n }\n\n public async readFile(remotePath: string): Promise<string> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.readFile(remotePath, (err, buffer) => {\n if (err) {\n return reject(new Error(`ssh.readFile: ${err}`));\n }\n resolve(buffer.toString());\n });\n });\n });\n }\n\n async chmod(path: string, mode: number) {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.chmod(path, mode, (err) => {\n if (err) {\n return reject(new Error(`ssh.chmod: ${err}, path: ${path}, mode: ${mode}`));\n }\n return resolve(undefined);\n });\n });\n });\n }\n\n async checkFileExists(remotePath: string) {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.stat(remotePath, (err: Error | undefined, stats) => {\n if (err) {\n if ((err as unknown as { code?: number })?.code === 2) {\n return resolve(false);\n }\n return reject(new Error(`ssh.checkFileExists: err ${err}`));\n }\n resolve(stats.isFile());\n });\n });\n });\n }\n\n async checkPathExists(remotePath: string): Promise<{ exists: boolean; isFile: boolean; isDirectory: boolean }> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.stat(remotePath, (err, stats) => {\n if (err) {\n if ((err as Error & { code: number }).code === 2) {\n return resolve({ exists: false, isFile: false, isDirectory: false });\n }\n return reject(new Error(`ssh.checkPathExists: ${err}`));\n }\n resolve({\n exists: true,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n });\n });\n });\n });\n }\n\n private async writeFile(sftp: SFTPWrapper, remotePath: string, data: string | Buffer, mode: number = 0o660): Promise<boolean> {\n return new Promise((resolve, reject) => {\n sftp.writeFile(remotePath, data, { mode }, (err) => {\n if (err) {\n return reject(new Error(`ssh.writeFile: err ${err}, remotePath: ${remotePath}`));\n }\n resolve(true);\n });\n });\n }\n\n public uploadFileUsingExistingSftp(sftp: SFTPWrapper, localPath: string, remotePath: string, mode: number = 0o660) {\n return new Promise((resolve, reject) => {\n void readFile(localPath).then(async (result: Buffer) => {\n return this.writeFile(sftp, remotePath, result, mode)\n .then(() => {\n resolve(undefined);\n })\n .catch((err) => {\n const msg = `uploadFileUsingExistingSftp: ${err}`;\n this.logger.error(msg);\n reject(new Error(msg));\n });\n });\n });\n }\n\n private async __uploadDirectory(sftp: SFTPWrapper, localDir: string, remoteDir: string, mode: number = 0o660): Promise<void> {\n return new Promise((resolve, reject) => {\n fs.readdir(localDir, async (err, files) => {\n if (err) {\n return reject(new Error(`ssh.__uploadDir: err ${err}, localDir: ${localDir}, remoteDir: ${remoteDir}`));\n }\n\n try {\n await this.__createRemoteDirectory(sftp, remoteDir);\n for (const file of files) {\n const localPath = upath.join(localDir, file);\n const remotePath = `${remoteDir}/${file}`;\n\n if (fs.lstatSync(localPath).isDirectory()) {\n await this.__uploadDirectory(sftp, localPath, remotePath, mode);\n } else {\n await this.uploadFileUsingExistingSftp(sftp, localPath, remotePath, mode);\n }\n }\n\n resolve();\n } catch (err) {\n const msg = `ssh.__uploadDir: catched err ${err}`;\n this.logger.error(msg);\n reject(new Error(msg));\n }\n });\n });\n }\n\n /**\n * Uploads a local directory and its contents (including subdirectories) to the remote server via SFTP.\n * @param localDir - The path to the local directory to upload.\n * @param remoteDir - The path to the remote directory on the server.\n * @returns A promise that resolves when the directory and its contents are uploaded.\n */\n public async uploadDirectory(localDir: string, remoteDir: string, mode: number = 0o660): Promise<void> {\n return new Promise((resolve, reject) => {\n void this.withSftp(async (sftp: SFTPWrapper) => {\n try {\n await this.__uploadDirectory(sftp, localDir, remoteDir, mode);\n resolve();\n } catch (e: unknown) {\n reject(new Error(`ssh.uploadDirectory: ${e}`));\n }\n });\n });\n }\n\n /**\n * Ensures that a remote directory and all its parent directories exist.\n * @param sftp - The SFTP wrapper.\n * @param remotePath - The path to the remote directory.\n * @returns A promise that resolves when the directory is created.\n */\n private __createRemoteDirectory(sftp: SFTPWrapper, remotePath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const directories = remotePath.split('/');\n let currentPath = '';\n\n const createNext = (index: number) => {\n if (index >= directories.length) {\n return resolve();\n }\n\n currentPath += `${directories[index]}/`;\n\n sftp.stat(currentPath, (err) => {\n if (err) {\n sftp.mkdir(currentPath, (err) => {\n if (err) {\n return reject(new Error(`ssh.__createRemDir: err ${err}, remotePath: ${remotePath}`));\n }\n createNext(index + 1);\n });\n } else {\n createNext(index + 1);\n }\n });\n };\n\n createNext(0);\n });\n }\n\n /**\n * Ensures that a remote directory and all its parent directories exist.\n * @param sftp - The SFTP wrapper.\n * @param remotePath - The path to the remote directory.\n * @returns A promise that resolves when the directory is created.\n */\n public ensureRemoteDirCreated(remotePath: string, mode: number = 0o755): Promise<void> {\n return this.withSftp(async (sftp) => {\n const directories = remotePath.split('/');\n let currentPath = '';\n\n for (const directory of directories) {\n currentPath += `${directory}/`;\n\n try {\n await new Promise<void>((resolve, reject) => {\n sftp.stat(currentPath, (err) => {\n if (!err) return resolve();\n\n sftp.mkdir(currentPath, { mode }, (err) => {\n if (err) {\n return reject(new Error(`ssh.createRemoteDir: err ${err}, remotePath: ${remotePath}`));\n }\n resolve();\n });\n });\n });\n } catch (error) {\n console.error(`Failed to create directory: ${currentPath}`, error);\n throw error;\n }\n }\n });\n }\n\n /**\n * Downloads a file from the remote server to a local path via SFTP.\n * @param remotePath - The remote file path on the server.\n * @param localPath - The local file path to save the file.\n * @returns A promise resolving with `true` if the file was successfully downloaded.\n */\n public async downloadFile(remotePath: string, localPath: string): Promise<boolean> {\n return this.withSftp(async (sftp) => {\n return new Promise((resolve, reject) => {\n sftp.fastGet(remotePath, localPath, (err) => {\n if (err) {\n return reject(new Error(`ssh.downloadFile: err ${err}, remotePath: ${remotePath}, localPath: ${localPath}`));\n }\n resolve(true);\n });\n });\n });\n }\n\n /**\n * Closes the SSH client connection and forwarded ports.\n */\n public close(): void {\n this.closeForwardedPorts();\n this.client.end();\n }\n}\n\nexport type SshExecResult = { stdout: string; stderr: string };\n\nasync function connect(\n client: Client,\n config: ConnectConfig,\n onError: (e: unknown) => void,\n onClose: () => void,\n): Promise<Client> {\n return new Promise((resolve, reject) => {\n client.on('ready', () => {\n resolve(client);\n });\n\n client.on('error', (err: unknown) => {\n onError(err);\n reject(new Error(`ssh.connect: ${err}`));\n });\n\n client.on('close', () => {\n onClose();\n });\n\n client.connect(config);\n\n // Remove TCP buffering.\n // Although it means less throughput (bad), it also means less latency (good).\n // It could help when we have\n // small messages like in our grpc transactions.\n // And it also could help when we have tcp forwarding to not buffer messages in the middle.\n (client as any).setNoDelay(true);\n });\n}\n\nasync function forwardOut(logger: MiLogger, conn: Client, localHost: string, localPort: number, remoteHost: string, remotePort: number): Promise<ClientChannel> {\n return new Promise((resolve, reject) => {\n conn.forwardOut(localHost, localPort, remoteHost, remotePort, (err, stream) => {\n if (err) {\n logger.error(`forwardOut.error: ${err}`);\n return reject(err);\n }\n\n return resolve(stream);\n });\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tsHelpers = require('@milaboratories/ts-helpers');
|
|
4
|
+
|
|
5
|
+
const MAX_UNWRAP_DEPTH = 10;
|
|
6
|
+
class SSHError extends Error {
|
|
7
|
+
name = 'SSHError';
|
|
8
|
+
constructor(messageOrErr, opts) {
|
|
9
|
+
if (messageOrErr instanceof Error) {
|
|
10
|
+
super(`SSHError: ${messageOrErr.message}`, { cause: opts?.cause ?? messageOrErr });
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
super(`SSHError: ${messageOrErr}`, opts);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
static from(err) {
|
|
17
|
+
return tsHelpers.findNamedErrorInCauses(err, SSHError, MAX_UNWRAP_DEPTH);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
class SFTPError extends SSHError {
|
|
21
|
+
code;
|
|
22
|
+
name = 'SFTPError';
|
|
23
|
+
constructor(code, // raw SFTP error code, i.e. from OpenSSH server
|
|
24
|
+
opts) {
|
|
25
|
+
super(code, opts);
|
|
26
|
+
this.code = code;
|
|
27
|
+
}
|
|
28
|
+
static wrap(err) {
|
|
29
|
+
if (!err)
|
|
30
|
+
return undefined;
|
|
31
|
+
const sftpErr = SFTPError.from(err);
|
|
32
|
+
if (sftpErr)
|
|
33
|
+
return sftpErr;
|
|
34
|
+
return new SFTPError(err.message, { cause: err });
|
|
35
|
+
}
|
|
36
|
+
static from(err) {
|
|
37
|
+
return tsHelpers.findNamedErrorInCauses(err, SFTPError, MAX_UNWRAP_DEPTH);
|
|
38
|
+
}
|
|
39
|
+
get isGenericFailure() {
|
|
40
|
+
// OpenSSH server returns this message in case of general failure.
|
|
41
|
+
// See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-server.c#L244
|
|
42
|
+
// See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-common.c#L195
|
|
43
|
+
return this.code === 'Failure';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
class SFTPUploadError extends SSHError {
|
|
47
|
+
localPath;
|
|
48
|
+
remotePath;
|
|
49
|
+
name = 'SFTPUploadError';
|
|
50
|
+
constructor(err, localPath, remotePath) {
|
|
51
|
+
super(`ssh.uploadFile: ${err.message}, localPath: ${localPath}, remotePath: ${remotePath}`, { cause: SFTPError.wrap(err) });
|
|
52
|
+
this.localPath = localPath;
|
|
53
|
+
this.remotePath = remotePath;
|
|
54
|
+
}
|
|
55
|
+
static from(err) {
|
|
56
|
+
return tsHelpers.findNamedErrorInCauses(err, SFTPUploadError, MAX_UNWRAP_DEPTH);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
exports.SFTPError = SFTPError;
|
|
61
|
+
exports.SFTPUploadError = SFTPUploadError;
|
|
62
|
+
exports.SSHError = SSHError;
|
|
63
|
+
//# sourceMappingURL=ssh_errors.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh_errors.cjs","sources":["../../src/ssh/ssh_errors.ts"],"sourcesContent":["import { findNamedErrorInCauses } from '@milaboratories/ts-helpers';\n\nconst MAX_UNWRAP_DEPTH = 10;\n\nexport class SSHError extends Error {\n name = 'SSHError';\n\n constructor(message: string, opts?: { cause: Error });\n constructor(err: Error);\n constructor(messageOrErr: string | Error, opts?: { cause: Error }) {\n if (messageOrErr instanceof Error) {\n super(`SSHError: ${messageOrErr.message}`, { cause: opts?.cause ?? messageOrErr });\n } else {\n super(`SSHError: ${messageOrErr}`, opts);\n }\n }\n\n static from(err: unknown): SSHError | undefined {\n return findNamedErrorInCauses(err, SSHError, MAX_UNWRAP_DEPTH);\n }\n}\n\nexport class SFTPError extends SSHError {\n name = 'SFTPError';\n\n constructor(\n public readonly code: string, // raw SFTP error code, i.e. from OpenSSH server\n opts?: { cause: Error },\n ) {\n super(code, opts);\n }\n\n /** Optionally wraps an error into SFTPError, if it is not already of this type */\n static wrap(err: Error): SFTPError;\n static wrap(err: undefined): undefined;\n static wrap(err: Error | undefined): SFTPError | undefined {\n if (!err) return undefined;\n const sftpErr = SFTPError.from(err);\n if (sftpErr) return sftpErr;\n return new SFTPError(err.message, { cause: err });\n }\n\n static from(err: unknown): SFTPError | undefined {\n return findNamedErrorInCauses(err, SFTPError, MAX_UNWRAP_DEPTH);\n }\n\n public get isGenericFailure(): boolean {\n // OpenSSH server returns this message in case of general failure.\n // See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-server.c#L244\n // See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-common.c#L195\n return this.code === 'Failure';\n }\n}\n\nexport class SFTPUploadError extends SSHError {\n name = 'SFTPUploadError';\n\n constructor(\n err: Error,\n public readonly localPath: string,\n public readonly remotePath: string,\n ) {\n super(`ssh.uploadFile: ${err.message}, localPath: ${localPath}, remotePath: ${remotePath}`, { cause: SFTPError.wrap(err) });\n }\n\n static from(err: unknown): SFTPUploadError | undefined {\n return findNamedErrorInCauses(err, SFTPUploadError, MAX_UNWRAP_DEPTH);\n }\n}\n"],"names":["findNamedErrorInCauses"],"mappings":";;;;AAEA,MAAM,gBAAgB,GAAG,EAAE;AAErB,MAAO,QAAS,SAAQ,KAAK,CAAA;IACjC,IAAI,GAAG,UAAU;IAIjB,WAAA,CAAY,YAA4B,EAAE,IAAuB,EAAA;AAC/D,QAAA,IAAI,YAAY,YAAY,KAAK,EAAE;AACjC,YAAA,KAAK,CAAC,CAAA,UAAA,EAAa,YAAY,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,YAAY,EAAE,CAAC;QACpF;aAAO;AACL,YAAA,KAAK,CAAC,CAAA,UAAA,EAAa,YAAY,EAAE,EAAE,IAAI,CAAC;QAC1C;IACF;IAEA,OAAO,IAAI,CAAC,GAAY,EAAA;QACtB,OAAOA,gCAAsB,CAAC,GAAG,EAAE,QAAQ,EAAE,gBAAgB,CAAC;IAChE;AACD;AAEK,MAAO,SAAU,SAAQ,QAAQ,CAAA;AAInB,IAAA,IAAA;IAHlB,IAAI,GAAG,WAAW;IAElB,WAAA,CACkB,IAAY;IAC5B,IAAuB,EAAA;AAEvB,QAAA,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC;QAHD,IAAA,CAAA,IAAI,GAAJ,IAAI;IAItB;IAKA,OAAO,IAAI,CAAC,GAAsB,EAAA;AAChC,QAAA,IAAI,CAAC,GAAG;AAAE,YAAA,OAAO,SAAS;QAC1B,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;AACnC,QAAA,IAAI,OAAO;AAAE,YAAA,OAAO,OAAO;AAC3B,QAAA,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACnD;IAEA,OAAO,IAAI,CAAC,GAAY,EAAA;QACtB,OAAOA,gCAAsB,CAAC,GAAG,EAAE,SAAS,EAAE,gBAAgB,CAAC;IACjE;AAEA,IAAA,IAAW,gBAAgB,GAAA;;;;AAIzB,QAAA,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS;IAChC;AACD;AAEK,MAAO,eAAgB,SAAQ,QAAQ,CAAA;AAKzB,IAAA,SAAA;AACA,IAAA,UAAA;IALlB,IAAI,GAAG,iBAAiB;AAExB,IAAA,WAAA,CACE,GAAU,EACM,SAAiB,EACjB,UAAkB,EAAA;QAElC,KAAK,CAAC,mBAAmB,GAAG,CAAC,OAAO,CAAA,aAAA,EAAgB,SAAS,CAAA,cAAA,EAAiB,UAAU,CAAA,CAAE,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAH3G,IAAA,CAAA,SAAS,GAAT,SAAS;QACT,IAAA,CAAA,UAAU,GAAV,UAAU;IAG5B;IAEA,OAAO,IAAI,CAAC,GAAY,EAAA;QACtB,OAAOA,gCAAsB,CAAC,GAAG,EAAE,eAAe,EAAE,gBAAgB,CAAC;IACvE;AACD;;;;;;"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export declare class SSHError extends Error {
|
|
2
|
+
name: string;
|
|
3
|
+
constructor(message: string, opts?: {
|
|
4
|
+
cause: Error;
|
|
5
|
+
});
|
|
6
|
+
constructor(err: Error);
|
|
7
|
+
static from(err: unknown): SSHError | undefined;
|
|
8
|
+
}
|
|
9
|
+
export declare class SFTPError extends SSHError {
|
|
10
|
+
readonly code: string;
|
|
11
|
+
name: string;
|
|
12
|
+
constructor(code: string, // raw SFTP error code, i.e. from OpenSSH server
|
|
13
|
+
opts?: {
|
|
14
|
+
cause: Error;
|
|
15
|
+
});
|
|
16
|
+
/** Optionally wraps an error into SFTPError, if it is not already of this type */
|
|
17
|
+
static wrap(err: Error): SFTPError;
|
|
18
|
+
static wrap(err: undefined): undefined;
|
|
19
|
+
static from(err: unknown): SFTPError | undefined;
|
|
20
|
+
get isGenericFailure(): boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare class SFTPUploadError extends SSHError {
|
|
23
|
+
readonly localPath: string;
|
|
24
|
+
readonly remotePath: string;
|
|
25
|
+
name: string;
|
|
26
|
+
constructor(err: Error, localPath: string, remotePath: string);
|
|
27
|
+
static from(err: unknown): SFTPUploadError | undefined;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=ssh_errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh_errors.d.ts","sourceRoot":"","sources":["../../src/ssh/ssh_errors.ts"],"names":[],"mappings":"AAIA,qBAAa,QAAS,SAAQ,KAAK;IACjC,IAAI,SAAc;gBAEN,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE;gBACxC,GAAG,EAAE,KAAK;IAStB,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS;CAGhD;AAED,qBAAa,SAAU,SAAQ,QAAQ;aAInB,IAAI,EAAE,MAAM;IAH9B,IAAI,SAAe;gBAGD,IAAI,EAAE,MAAM,EAAE,gDAAgD;IAC9E,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE;IAKzB,kFAAkF;IAClF,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,GAAG,SAAS;IAClC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,GAAG,SAAS;IAQtC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS;IAIhD,IAAW,gBAAgB,IAAI,OAAO,CAKrC;CACF;AAED,qBAAa,eAAgB,SAAQ,QAAQ;aAKzB,SAAS,EAAE,MAAM;aACjB,UAAU,EAAE,MAAM;IALpC,IAAI,SAAqB;gBAGvB,GAAG,EAAE,KAAK,EACM,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM;IAKpC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,GAAG,SAAS;CAGvD"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { findNamedErrorInCauses } from '@milaboratories/ts-helpers';
|
|
2
|
+
|
|
3
|
+
const MAX_UNWRAP_DEPTH = 10;
|
|
4
|
+
class SSHError extends Error {
|
|
5
|
+
name = 'SSHError';
|
|
6
|
+
constructor(messageOrErr, opts) {
|
|
7
|
+
if (messageOrErr instanceof Error) {
|
|
8
|
+
super(`SSHError: ${messageOrErr.message}`, { cause: opts?.cause ?? messageOrErr });
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
super(`SSHError: ${messageOrErr}`, opts);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
static from(err) {
|
|
15
|
+
return findNamedErrorInCauses(err, SSHError, MAX_UNWRAP_DEPTH);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
class SFTPError extends SSHError {
|
|
19
|
+
code;
|
|
20
|
+
name = 'SFTPError';
|
|
21
|
+
constructor(code, // raw SFTP error code, i.e. from OpenSSH server
|
|
22
|
+
opts) {
|
|
23
|
+
super(code, opts);
|
|
24
|
+
this.code = code;
|
|
25
|
+
}
|
|
26
|
+
static wrap(err) {
|
|
27
|
+
if (!err)
|
|
28
|
+
return undefined;
|
|
29
|
+
const sftpErr = SFTPError.from(err);
|
|
30
|
+
if (sftpErr)
|
|
31
|
+
return sftpErr;
|
|
32
|
+
return new SFTPError(err.message, { cause: err });
|
|
33
|
+
}
|
|
34
|
+
static from(err) {
|
|
35
|
+
return findNamedErrorInCauses(err, SFTPError, MAX_UNWRAP_DEPTH);
|
|
36
|
+
}
|
|
37
|
+
get isGenericFailure() {
|
|
38
|
+
// OpenSSH server returns this message in case of general failure.
|
|
39
|
+
// See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-server.c#L244
|
|
40
|
+
// See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-common.c#L195
|
|
41
|
+
return this.code === 'Failure';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
class SFTPUploadError extends SSHError {
|
|
45
|
+
localPath;
|
|
46
|
+
remotePath;
|
|
47
|
+
name = 'SFTPUploadError';
|
|
48
|
+
constructor(err, localPath, remotePath) {
|
|
49
|
+
super(`ssh.uploadFile: ${err.message}, localPath: ${localPath}, remotePath: ${remotePath}`, { cause: SFTPError.wrap(err) });
|
|
50
|
+
this.localPath = localPath;
|
|
51
|
+
this.remotePath = remotePath;
|
|
52
|
+
}
|
|
53
|
+
static from(err) {
|
|
54
|
+
return findNamedErrorInCauses(err, SFTPUploadError, MAX_UNWRAP_DEPTH);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { SFTPError, SFTPUploadError, SSHError };
|
|
59
|
+
//# sourceMappingURL=ssh_errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh_errors.js","sources":["../../src/ssh/ssh_errors.ts"],"sourcesContent":["import { findNamedErrorInCauses } from '@milaboratories/ts-helpers';\n\nconst MAX_UNWRAP_DEPTH = 10;\n\nexport class SSHError extends Error {\n name = 'SSHError';\n\n constructor(message: string, opts?: { cause: Error });\n constructor(err: Error);\n constructor(messageOrErr: string | Error, opts?: { cause: Error }) {\n if (messageOrErr instanceof Error) {\n super(`SSHError: ${messageOrErr.message}`, { cause: opts?.cause ?? messageOrErr });\n } else {\n super(`SSHError: ${messageOrErr}`, opts);\n }\n }\n\n static from(err: unknown): SSHError | undefined {\n return findNamedErrorInCauses(err, SSHError, MAX_UNWRAP_DEPTH);\n }\n}\n\nexport class SFTPError extends SSHError {\n name = 'SFTPError';\n\n constructor(\n public readonly code: string, // raw SFTP error code, i.e. from OpenSSH server\n opts?: { cause: Error },\n ) {\n super(code, opts);\n }\n\n /** Optionally wraps an error into SFTPError, if it is not already of this type */\n static wrap(err: Error): SFTPError;\n static wrap(err: undefined): undefined;\n static wrap(err: Error | undefined): SFTPError | undefined {\n if (!err) return undefined;\n const sftpErr = SFTPError.from(err);\n if (sftpErr) return sftpErr;\n return new SFTPError(err.message, { cause: err });\n }\n\n static from(err: unknown): SFTPError | undefined {\n return findNamedErrorInCauses(err, SFTPError, MAX_UNWRAP_DEPTH);\n }\n\n public get isGenericFailure(): boolean {\n // OpenSSH server returns this message in case of general failure.\n // See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-server.c#L244\n // See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-common.c#L195\n return this.code === 'Failure';\n }\n}\n\nexport class SFTPUploadError extends SSHError {\n name = 'SFTPUploadError';\n\n constructor(\n err: Error,\n public readonly localPath: string,\n public readonly remotePath: string,\n ) {\n super(`ssh.uploadFile: ${err.message}, localPath: ${localPath}, remotePath: ${remotePath}`, { cause: SFTPError.wrap(err) });\n }\n\n static from(err: unknown): SFTPUploadError | undefined {\n return findNamedErrorInCauses(err, SFTPUploadError, MAX_UNWRAP_DEPTH);\n }\n}\n"],"names":[],"mappings":";;AAEA,MAAM,gBAAgB,GAAG,EAAE;AAErB,MAAO,QAAS,SAAQ,KAAK,CAAA;IACjC,IAAI,GAAG,UAAU;IAIjB,WAAA,CAAY,YAA4B,EAAE,IAAuB,EAAA;AAC/D,QAAA,IAAI,YAAY,YAAY,KAAK,EAAE;AACjC,YAAA,KAAK,CAAC,CAAA,UAAA,EAAa,YAAY,CAAC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,YAAY,EAAE,CAAC;QACpF;aAAO;AACL,YAAA,KAAK,CAAC,CAAA,UAAA,EAAa,YAAY,EAAE,EAAE,IAAI,CAAC;QAC1C;IACF;IAEA,OAAO,IAAI,CAAC,GAAY,EAAA;QACtB,OAAO,sBAAsB,CAAC,GAAG,EAAE,QAAQ,EAAE,gBAAgB,CAAC;IAChE;AACD;AAEK,MAAO,SAAU,SAAQ,QAAQ,CAAA;AAInB,IAAA,IAAA;IAHlB,IAAI,GAAG,WAAW;IAElB,WAAA,CACkB,IAAY;IAC5B,IAAuB,EAAA;AAEvB,QAAA,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC;QAHD,IAAA,CAAA,IAAI,GAAJ,IAAI;IAItB;IAKA,OAAO,IAAI,CAAC,GAAsB,EAAA;AAChC,QAAA,IAAI,CAAC,GAAG;AAAE,YAAA,OAAO,SAAS;QAC1B,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;AACnC,QAAA,IAAI,OAAO;AAAE,YAAA,OAAO,OAAO;AAC3B,QAAA,OAAO,IAAI,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACnD;IAEA,OAAO,IAAI,CAAC,GAAY,EAAA;QACtB,OAAO,sBAAsB,CAAC,GAAG,EAAE,SAAS,EAAE,gBAAgB,CAAC;IACjE;AAEA,IAAA,IAAW,gBAAgB,GAAA;;;;AAIzB,QAAA,OAAO,IAAI,CAAC,IAAI,KAAK,SAAS;IAChC;AACD;AAEK,MAAO,eAAgB,SAAQ,QAAQ,CAAA;AAKzB,IAAA,SAAA;AACA,IAAA,UAAA;IALlB,IAAI,GAAG,iBAAiB;AAExB,IAAA,WAAA,CACE,GAAU,EACM,SAAiB,EACjB,UAAkB,EAAA;QAElC,KAAK,CAAC,mBAAmB,GAAG,CAAC,OAAO,CAAA,aAAA,EAAgB,SAAS,CAAA,cAAA,EAAiB,UAAU,CAAA,CAAE,EAAE,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAH3G,IAAA,CAAA,SAAS,GAAT,SAAS;QACT,IAAA,CAAA,UAAU,GAAV,UAAU;IAG5B;IAEA,OAAO,IAAI,CAAC,GAAY,EAAA;QACtB,OAAO,sBAAsB,CAAC,GAAG,EAAE,eAAe,EAAE,gBAAgB,CAAC;IACvE;AACD;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@milaboratories/pl-deployments",
|
|
3
|
-
"version": "2.15.
|
|
3
|
+
"version": "2.15.3",
|
|
4
4
|
"pl-version": "1.44.1",
|
|
5
5
|
"description": "MiLaboratories Platforma Backend code service run wrapper",
|
|
6
6
|
"engines": {
|
|
@@ -38,10 +38,10 @@
|
|
|
38
38
|
"typescript": "~5.6.3",
|
|
39
39
|
"utility-types": "^3.11.0",
|
|
40
40
|
"vitest": "^4.0.16",
|
|
41
|
-
"@milaboratories/build-configs": "1.2.
|
|
41
|
+
"@milaboratories/build-configs": "1.2.2",
|
|
42
42
|
"@milaboratories/eslint-config": "1.0.5",
|
|
43
|
-
"@milaboratories/ts-
|
|
44
|
-
"@milaboratories/ts-
|
|
43
|
+
"@milaboratories/ts-builder": "1.2.2",
|
|
44
|
+
"@milaboratories/ts-configs": "1.2.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"decompress": "^4.2.1",
|
|
@@ -51,10 +51,10 @@
|
|
|
51
51
|
"upath": "^2.0.1",
|
|
52
52
|
"yaml": "^2.8.0",
|
|
53
53
|
"zod": "~3.23.8",
|
|
54
|
+
"@milaboratories/pl-config": "1.7.10",
|
|
54
55
|
"@milaboratories/pl-http": "1.2.0",
|
|
55
|
-
"@milaboratories/
|
|
56
|
-
"@milaboratories/pl-model-common": "1.
|
|
57
|
-
"@milaboratories/ts-helpers": "1.5.4"
|
|
56
|
+
"@milaboratories/ts-helpers": "1.6.0",
|
|
57
|
+
"@milaboratories/pl-model-common": "1.24.0"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"type-check": "ts-builder types --target node",
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describe, test, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { SshClient } from '../ssh';
|
|
3
|
+
import { SFTPError } from '../ssh_errors';
|
|
4
|
+
import { ConsoleLoggerAdapter } from '@milaboratories/ts-helpers';
|
|
5
|
+
import type { SFTPWrapper } from 'ssh2';
|
|
6
|
+
import { writeFile, unlink } from 'node:fs/promises';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
|
|
10
|
+
describe('mocked SSHClient', () => {
|
|
11
|
+
let testFilePath: string;
|
|
12
|
+
let remoteFilePath: string;
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
// Create a temporary test file
|
|
16
|
+
testFilePath = join(tmpdir(), `test-upload-${Date.now()}.txt`);
|
|
17
|
+
await writeFile(testFilePath, 'test content');
|
|
18
|
+
remoteFilePath = `/tmp/test-upload-${Date.now()}.txt`;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(async () => {
|
|
22
|
+
// Cleanup test file
|
|
23
|
+
try {
|
|
24
|
+
await unlink(testFilePath);
|
|
25
|
+
} catch {
|
|
26
|
+
// Ignore cleanup errors
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('should retry upload in case of a failure', async () => {
|
|
31
|
+
const logger = new ConsoleLoggerAdapter();
|
|
32
|
+
|
|
33
|
+
// Track upload attempts
|
|
34
|
+
let uploadAttempt = 0;
|
|
35
|
+
|
|
36
|
+
// Create a mock SFTP wrapper
|
|
37
|
+
const mockSftp = {
|
|
38
|
+
fastPut: vi.fn((localPath: string, remotePath: string, callback: (err: Error | null) => void) => {
|
|
39
|
+
uploadAttempt++;
|
|
40
|
+
|
|
41
|
+
if (uploadAttempt === 1) {
|
|
42
|
+
// First attempt: return 'Failure' error (generic failure that triggers retry)
|
|
43
|
+
const failureError = new Error('Failure');
|
|
44
|
+
callback(failureError);
|
|
45
|
+
} else if (uploadAttempt === 2) {
|
|
46
|
+
// Second attempt: accept upload (callback succeeds, but file is dropped/not saved per requirements)
|
|
47
|
+
// The test expects successful upload, so we simulate success
|
|
48
|
+
callback(null);
|
|
49
|
+
} else {
|
|
50
|
+
callback(new Error('Unexpected error, too many attempts'));
|
|
51
|
+
}
|
|
52
|
+
}),
|
|
53
|
+
end: vi.fn(),
|
|
54
|
+
} as unknown as SFTPWrapper;
|
|
55
|
+
|
|
56
|
+
// Create a mock SSH2 Client
|
|
57
|
+
const mockSsh2Client = {
|
|
58
|
+
sftp: vi.fn((callback: (err: Error | null, sftp: SFTPWrapper) => void) => {
|
|
59
|
+
callback(null, mockSftp);
|
|
60
|
+
}),
|
|
61
|
+
end: vi.fn(),
|
|
62
|
+
} as any;
|
|
63
|
+
|
|
64
|
+
// Create SshClient instance with mocked client
|
|
65
|
+
// We bypass the init method and directly use constructor since we're mocking
|
|
66
|
+
const sshClient = new SshClient(logger, mockSsh2Client);
|
|
67
|
+
|
|
68
|
+
// The upload should succeed on the second attempt
|
|
69
|
+
const result = await sshClient.uploadFile(testFilePath, remoteFilePath);
|
|
70
|
+
|
|
71
|
+
expect(result).toBe(true);
|
|
72
|
+
expect(uploadAttempt).toBe(2); // Should succeed on 2nd attempt
|
|
73
|
+
expect(mockSftp.fastPut).toHaveBeenCalledTimes(2);
|
|
74
|
+
expect(mockSftp.fastPut).toHaveBeenNthCalledWith(1, testFilePath, remoteFilePath, expect.any(Function));
|
|
75
|
+
expect(mockSftp.fastPut).toHaveBeenNthCalledWith(2, testFilePath, remoteFilePath, expect.any(Function));
|
|
76
|
+
});
|
|
77
|
+
});
|
package/src/ssh/ssh.ts
CHANGED
|
@@ -7,8 +7,9 @@ import dns from 'node:dns';
|
|
|
7
7
|
import fs from 'node:fs';
|
|
8
8
|
import { readFile } from 'node:fs/promises';
|
|
9
9
|
import upath from 'upath';
|
|
10
|
-
import { RetryablePromise, type MiLogger } from '@milaboratories/ts-helpers';
|
|
10
|
+
import { RetryablePromise, retry, type MiLogger, Retry3TimesWithDelay } from '@milaboratories/ts-helpers';
|
|
11
11
|
import { randomBytes } from 'node:crypto';
|
|
12
|
+
import { SFTPUploadError, SFTPError } from './ssh_errors';
|
|
12
13
|
|
|
13
14
|
const defaultConfig: ConnectConfig = {
|
|
14
15
|
keepaliveInterval: 60000,
|
|
@@ -309,31 +310,36 @@ export class SshClient {
|
|
|
309
310
|
* @returns A promise resolving with `true` if the file was successfully uploaded.
|
|
310
311
|
*/
|
|
311
312
|
public async uploadFile(localPath: string, remotePath: string): Promise<boolean> {
|
|
312
|
-
return await
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
313
|
+
return await retry<boolean>(
|
|
314
|
+
async () => {
|
|
315
|
+
return await this.withSftp(async (sftp) => {
|
|
316
|
+
return new Promise((resolve, reject) => {
|
|
317
|
+
sftp.fastPut(localPath, remotePath, (err) => {
|
|
318
|
+
if (err) {
|
|
319
|
+
const newErr = new SFTPUploadError(err, localPath, remotePath);
|
|
320
|
+
return reject(newErr);
|
|
321
|
+
}
|
|
322
|
+
resolve(true);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
321
325
|
});
|
|
322
|
-
}
|
|
323
|
-
|
|
326
|
+
},
|
|
327
|
+
Retry3TimesWithDelay,
|
|
328
|
+
(e: any) => SFTPError.from(e)?.isGenericFailure ?? false, // retry unknown upload errors
|
|
329
|
+
);
|
|
324
330
|
}
|
|
325
331
|
|
|
326
332
|
public async withSftp<R>(callback: (sftp: SFTPWrapper) => Promise<R>): Promise<R> {
|
|
327
333
|
return new Promise((resolve, reject) => {
|
|
328
334
|
this.client.sftp((err, sftp) => {
|
|
329
335
|
if (err) {
|
|
330
|
-
return reject(new Error(`ssh.withSftp: sftp err: ${err}
|
|
336
|
+
return reject(new Error(`ssh.withSftp: sftp err: ${err}`, { cause: err }));
|
|
331
337
|
}
|
|
332
338
|
|
|
333
339
|
callback(sftp)
|
|
334
340
|
.then(resolve)
|
|
335
341
|
.catch((err) => {
|
|
336
|
-
reject(new Error(`ssh.withSftp.callback: err ${err}
|
|
342
|
+
reject(new Error(`ssh.withSftp.callback: err ${err}`, { cause: err }));
|
|
337
343
|
})
|
|
338
344
|
.finally(() => {
|
|
339
345
|
sftp?.end();
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, test, expect } from 'vitest';
|
|
2
|
+
import { SFTPError, SSHError, SFTPUploadError } from './ssh_errors';
|
|
3
|
+
|
|
4
|
+
test('error chain unwrapping works', () => {
|
|
5
|
+
const err = new Error('Failure');
|
|
6
|
+
const uploadErr = new SFTPUploadError(err, 'localPath', 'remotePath');
|
|
7
|
+
const finalErr = new Error(`Problem: ${uploadErr.message}`, { cause: uploadErr });
|
|
8
|
+
|
|
9
|
+
expect(SFTPUploadError.from(finalErr)).toBe(uploadErr);
|
|
10
|
+
expect(SFTPError.from(finalErr)).toBeDefined();
|
|
11
|
+
expect(SSHError.from(finalErr)).toBeDefined();
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
describe('SSHError', () => {
|
|
15
|
+
test('should add prefix to error message', () => {
|
|
16
|
+
const err = new SSHError('Test error');
|
|
17
|
+
expect(err.message).toBe('SSHError: Test error');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('should respect cause option', () => {
|
|
21
|
+
const cause = new Error('Cause error');
|
|
22
|
+
const err = new SSHError('Test error', { cause });
|
|
23
|
+
expect(err.cause).toBe(cause);
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('should preserve original error as cause', () => {
|
|
27
|
+
const cause = new Error('Cause error');
|
|
28
|
+
const err = new SSHError(cause);
|
|
29
|
+
expect(err.cause).toBe(cause);
|
|
30
|
+
})
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('SFTPError.wrap()', () => {
|
|
34
|
+
test('should return undefined when err is undefined', () => {
|
|
35
|
+
const result = SFTPError.wrap(undefined);
|
|
36
|
+
expect(result).toBeUndefined();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should return the same error when err is already an SFTPError', () => {
|
|
40
|
+
const sftpErr = new SFTPError('Failure');
|
|
41
|
+
const result = SFTPError.wrap(sftpErr);
|
|
42
|
+
expect(result).toBe(sftpErr);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('should wrap a regular Error in SFTPError', () => {
|
|
46
|
+
const regularErr = new Error('Some error message');
|
|
47
|
+
const result = SFTPError.wrap(regularErr);
|
|
48
|
+
|
|
49
|
+
expect(result).toBeInstanceOf(SFTPError);
|
|
50
|
+
expect(result).not.toBe(regularErr);
|
|
51
|
+
expect(result?.code).toBe('Some error message');
|
|
52
|
+
expect(result?.cause).toBe(regularErr);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('should return existing SFTPError when err has SFTPError in cause chain', () => {
|
|
56
|
+
const originalSftpErr = new SFTPError('Permission denied');
|
|
57
|
+
const wrappedErr = new Error('Outer error', { cause: originalSftpErr });
|
|
58
|
+
const result = SFTPError.wrap(wrappedErr);
|
|
59
|
+
|
|
60
|
+
expect(result).toBe(originalSftpErr);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('should wrap SSHError that is not SFTPError', () => {
|
|
64
|
+
const sshErr = new SSHError('SSH connection failed');
|
|
65
|
+
const result = SFTPError.wrap(sshErr);
|
|
66
|
+
|
|
67
|
+
expect(result).toBeInstanceOf(SFTPError);
|
|
68
|
+
expect(result).not.toBe(sshErr);
|
|
69
|
+
expect(result?.code).toBe('SSHError: SSH connection failed');
|
|
70
|
+
expect(result?.cause).toBe(sshErr);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('should wrap error with SFTPError deep in cause chain', () => {
|
|
74
|
+
const originalSftpErr = new SFTPError('File not found');
|
|
75
|
+
const intermediateErr1 = new Error('Intermediate 1', { cause: originalSftpErr });
|
|
76
|
+
const intermediateErr2 = new Error('Intermediate 2', { cause: intermediateErr1 });
|
|
77
|
+
const finalErr = new Error('Final error', { cause: intermediateErr2 });
|
|
78
|
+
const result = SFTPError.wrap(finalErr);
|
|
79
|
+
|
|
80
|
+
expect(result).toBe(originalSftpErr);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('should preserve error message when wrapping', () => {
|
|
84
|
+
const err = new Error('Custom error message');
|
|
85
|
+
const result = SFTPError.wrap(err);
|
|
86
|
+
|
|
87
|
+
expect(result?.code).toBe('Custom error message');
|
|
88
|
+
expect(result?.message).toContain('Custom error message');
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { findNamedErrorInCauses } from '@milaboratories/ts-helpers';
|
|
2
|
+
|
|
3
|
+
const MAX_UNWRAP_DEPTH = 10;
|
|
4
|
+
|
|
5
|
+
export class SSHError extends Error {
|
|
6
|
+
name = 'SSHError';
|
|
7
|
+
|
|
8
|
+
constructor(message: string, opts?: { cause: Error });
|
|
9
|
+
constructor(err: Error);
|
|
10
|
+
constructor(messageOrErr: string | Error, opts?: { cause: Error }) {
|
|
11
|
+
if (messageOrErr instanceof Error) {
|
|
12
|
+
super(`SSHError: ${messageOrErr.message}`, { cause: opts?.cause ?? messageOrErr });
|
|
13
|
+
} else {
|
|
14
|
+
super(`SSHError: ${messageOrErr}`, opts);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static from(err: unknown): SSHError | undefined {
|
|
19
|
+
return findNamedErrorInCauses(err, SSHError, MAX_UNWRAP_DEPTH);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class SFTPError extends SSHError {
|
|
24
|
+
name = 'SFTPError';
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
public readonly code: string, // raw SFTP error code, i.e. from OpenSSH server
|
|
28
|
+
opts?: { cause: Error },
|
|
29
|
+
) {
|
|
30
|
+
super(code, opts);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Optionally wraps an error into SFTPError, if it is not already of this type */
|
|
34
|
+
static wrap(err: Error): SFTPError;
|
|
35
|
+
static wrap(err: undefined): undefined;
|
|
36
|
+
static wrap(err: Error | undefined): SFTPError | undefined {
|
|
37
|
+
if (!err) return undefined;
|
|
38
|
+
const sftpErr = SFTPError.from(err);
|
|
39
|
+
if (sftpErr) return sftpErr;
|
|
40
|
+
return new SFTPError(err.message, { cause: err });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
static from(err: unknown): SFTPError | undefined {
|
|
44
|
+
return findNamedErrorInCauses(err, SFTPError, MAX_UNWRAP_DEPTH);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public get isGenericFailure(): boolean {
|
|
48
|
+
// OpenSSH server returns this message in case of general failure.
|
|
49
|
+
// See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-server.c#L244
|
|
50
|
+
// See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-common.c#L195
|
|
51
|
+
return this.code === 'Failure';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class SFTPUploadError extends SSHError {
|
|
56
|
+
name = 'SFTPUploadError';
|
|
57
|
+
|
|
58
|
+
constructor(
|
|
59
|
+
err: Error,
|
|
60
|
+
public readonly localPath: string,
|
|
61
|
+
public readonly remotePath: string,
|
|
62
|
+
) {
|
|
63
|
+
super(`ssh.uploadFile: ${err.message}, localPath: ${localPath}, remotePath: ${remotePath}`, { cause: SFTPError.wrap(err) });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static from(err: unknown): SFTPUploadError | undefined {
|
|
67
|
+
return findNamedErrorInCauses(err, SFTPUploadError, MAX_UNWRAP_DEPTH);
|
|
68
|
+
}
|
|
69
|
+
}
|