(config: SSHConnectionConfig)
| 111 | * - keepaliveCountMax: 3 (same as OpenSSH ServerAliveCountMax) |
| 112 | */ |
| 113 | export async function createSSHConnection(config: SSHConnectionConfig): Promise<Client> { |
| 114 | const host = config.host |
| 115 | |
| 116 | if (!host || host.trim() === '') { |
| 117 | throw new Error('Host is required. Please provide a valid hostname or IP address.') |
| 118 | } |
| 119 | |
| 120 | const hostValidation = await validateDatabaseHost(host, 'host') |
| 121 | if (!hostValidation.isValid) { |
| 122 | throw new Error(hostValidation.error) |
| 123 | } |
| 124 | |
| 125 | const resolvedHost = hostValidation.resolvedIP ?? host.trim() |
| 126 | |
| 127 | return new Promise((resolve, reject) => { |
| 128 | const client = new Client() |
| 129 | const port = config.port || 22 |
| 130 | |
| 131 | const hasPassword = config.password && config.password.trim() !== '' |
| 132 | const hasPrivateKey = config.privateKey && config.privateKey.trim() !== '' |
| 133 | |
| 134 | if (!hasPassword && !hasPrivateKey) { |
| 135 | reject(new Error('Authentication required. Please provide either a password or private key.')) |
| 136 | return |
| 137 | } |
| 138 | |
| 139 | const connectConfig: ConnectConfig = { |
| 140 | host: resolvedHost, |
| 141 | port, |
| 142 | username: config.username, |
| 143 | } |
| 144 | |
| 145 | if (config.readyTimeout !== undefined) { |
| 146 | connectConfig.readyTimeout = config.readyTimeout |
| 147 | } |
| 148 | if (config.keepaliveInterval !== undefined) { |
| 149 | connectConfig.keepaliveInterval = config.keepaliveInterval |
| 150 | } |
| 151 | |
| 152 | if (hasPrivateKey) { |
| 153 | connectConfig.privateKey = config.privateKey! |
| 154 | if (config.passphrase && config.passphrase.trim() !== '') { |
| 155 | connectConfig.passphrase = config.passphrase |
| 156 | } |
| 157 | } else if (hasPassword) { |
| 158 | connectConfig.password = config.password! |
| 159 | } |
| 160 | |
| 161 | client.on('ready', () => { |
| 162 | resolve(client) |
| 163 | }) |
| 164 | |
| 165 | client.on('error', (err) => { |
| 166 | reject(formatSSHError(err, { host, port })) |
| 167 | }) |
| 168 | |
| 169 | try { |
| 170 | client.connect(connectConfig) |
no test coverage detected