Skip to content
This repository was archived by the owner on Aug 26, 2025. It is now read-only.

Commit 29066b8

Browse files
authored
Merge pull request #6 from Stocard/encrypted_private_key
Adds support for encrypted private keys.
2 parents 80f6c4c + 66a9ca3 commit 29066b8

File tree

2 files changed

+22
-3
lines changed

2 files changed

+22
-3
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ Options are an object with following properties:
8787
* `agentForward` (optional): Is a `boolean` which uses the `ssh-agent` for connection (defaults to `false`.
8888
* `endHost` (required): The host you want to end up on (connect to)
8989
* `bastionHost` (optional): You can specify a bastion host if you want
90+
* `passphrase` (optional): You can specify the passphrase when you have an encrypted private key. If you don't specify the passphrase and you use an encrypted private key, you get prompted in the command line.
9091

9192
#### `connection.executeCommand(command: string): Promise<void>`
9293

src/Connection.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ import * as net from 'net'
2020
import * as fs from 'fs'
2121
import * as os from 'os'
2222
import * as path from 'path'
23+
import * as readline from 'readline'
2324

2425
interface Options {
2526
username?: string
2627
privateKey?: string | Buffer,
2728
agentForward? : boolean,
28-
bastionHost?: string
29+
bastionHost?: string,
30+
passphrase?: string
2931
endHost: string
3032
}
3133

@@ -124,15 +126,16 @@ class SSHConnection {
124126

125127
private async connect(host: string, stream?: NodeJS.ReadableStream): Promise<Client> {
126128
const connection = new Client()
127-
return new Promise<Client>((resolve) => {
129+
return new Promise<Client>(async (resolve) => {
128130
const options = {
129131
host,
130132
username: this.options.username,
131133
privateKey: this.options.privateKey
132134
}
133135
if (this.options.agentForward) {
134136
options['agentForward'] = true
135-
const agentSock = process.env['SSH_AUTH_SOCK'] // guaranteed to give the ssh agent sock if the agent is running
137+
// guaranteed to give the ssh agent sock if the agent is running
138+
const agentSock = process.env['SSH_AUTH_SOCK']
136139
if (agentSock === undefined) {
137140
throw new Error('SSH Agent is not running and not set in the SSH_AUTH_SOCK env variable')
138141
}
@@ -141,6 +144,9 @@ class SSHConnection {
141144
if (stream) {
142145
options['sock'] = stream
143146
}
147+
if (options.privateKey && options.privateKey.toString().toLowerCase().includes('encrypted')) {
148+
options['passphrase'] = (this.options.passphrase) ? this.options.passphrase : await this.getPassphrase()
149+
}
144150
connection.connect(options)
145151
connection.on('ready', () => {
146152
this.connections.push(connection)
@@ -149,6 +155,18 @@ class SSHConnection {
149155
})
150156
}
151157

158+
private async getPassphrase() {
159+
return new Promise((resolve) => {
160+
const rl = readline.createInterface({
161+
input: process.stdin,
162+
output: process.stdout
163+
})
164+
rl.question('Please type in the passphrase for your private key', (answer) => {
165+
return resolve(answer)
166+
})
167+
})
168+
}
169+
152170
async forward(options: ForwardingOptions) {
153171
const connection = await this.establish()
154172
return new Promise((resolve, reject) => {

0 commit comments

Comments
 (0)