net-ssh 4.0.0.alpha3 → 4.0.0.alpha4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +1 -1
- data.tar.gz.sig +0 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +1148 -0
- data/.travis.yml +26 -5
- data/CHANGES.txt +9 -0
- data/Gemfile.norbnacl +5 -0
- data/Gemfile.norbnacl.lock +40 -0
- data/README.rdoc +0 -2
- data/Rakefile +10 -0
- data/appveyor.yml +18 -0
- data/lib/net/ssh.rb +15 -2
- data/lib/net/ssh/authentication/agent/java_pageant.rb +1 -1
- data/lib/net/ssh/authentication/agent/socket.rb +5 -5
- data/lib/net/ssh/authentication/ed25519.rb +9 -14
- data/lib/net/ssh/authentication/key_manager.rb +3 -3
- data/lib/net/ssh/authentication/methods/abstract.rb +4 -0
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +10 -10
- data/lib/net/ssh/authentication/methods/password.rb +14 -3
- data/lib/net/ssh/authentication/session.rb +2 -1
- data/lib/net/ssh/config.rb +12 -1
- data/lib/net/ssh/connection/event_loop.rb +110 -0
- data/lib/net/ssh/connection/keepalive.rb +2 -2
- data/lib/net/ssh/connection/session.rb +57 -27
- data/lib/net/ssh/key_factory.rb +48 -50
- data/lib/net/ssh/prompt.rb +48 -77
- data/lib/net/ssh/service/forward.rb +1 -1
- data/lib/net/ssh/test/channel.rb +7 -0
- data/lib/net/ssh/test/packet.rb +18 -2
- data/lib/net/ssh/test/script.rb +16 -2
- data/lib/net/ssh/test/socket.rb +1 -1
- data/lib/net/ssh/transport/algorithms.rb +6 -0
- data/lib/net/ssh/transport/session.rb +1 -0
- data/lib/net/ssh/version.rb +1 -1
- data/net-ssh.gemspec +7 -5
- metadata +25 -6
- metadata.gz.sig +0 -0
- data/setup.rb +0 -1585
data/.travis.yml
CHANGED
@@ -1,21 +1,42 @@
|
|
1
1
|
language: ruby
|
2
|
-
sudo:
|
2
|
+
sudo: true
|
3
|
+
dist: trusty
|
4
|
+
|
3
5
|
rvm:
|
4
6
|
- 2.0
|
5
7
|
- 2.1
|
6
8
|
- 2.2
|
7
9
|
- 2.3.0
|
8
|
-
- jruby-
|
9
|
-
- rbx-3.
|
10
|
+
- jruby-9.0.5.0
|
11
|
+
- rbx-3.25
|
10
12
|
- ruby-head
|
13
|
+
env:
|
14
|
+
NET_SSH_RUN_INTEGRATION_TESTS=1
|
11
15
|
|
12
16
|
matrix:
|
17
|
+
exclude:
|
18
|
+
- rvm: rbx-3.25
|
19
|
+
- rvm: jruby-9.0.5.0
|
20
|
+
include:
|
21
|
+
- rvm: rbx-3.25
|
22
|
+
env: NET_SSH_RUN_INTEGRATION_TESTS=
|
23
|
+
- rvm: jruby-9.0.5.0
|
24
|
+
env: JRUBY_OPTS='--client -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -Xcext.enabled=false -J-Xss2m -Xcompile.invokedynamic=false' NET_SSH_RUN_INTEGRATION_TESTS=
|
13
25
|
allow_failures:
|
14
26
|
- rvm: ruby-head
|
15
|
-
- rvm: rbx-3.
|
27
|
+
- rvm: rbx-3.25
|
28
|
+
- rvm: jruby-9.0.5.0
|
16
29
|
|
17
30
|
install:
|
31
|
+
- export JRUBY_OPTS='--client -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -Xcext.enabled=false -J-Xss2m -Xcompile.invokedynamic=false'
|
32
|
+
- sudo pip install ansible
|
18
33
|
- gem install bundler -v "= 1.11.2"
|
19
34
|
- bundle _1.11.2_ install
|
35
|
+
- sudo ansible-galaxy install rvm_io.rvm1-ruby
|
36
|
+
- ansible-playbook ./test/integration/playbook.yml -i "localhost," --become -c local -e 'no_rvm=true' -e 'myuser=travis' -e 'mygroup=travis' -e 'homedir=/home/travis'
|
20
37
|
|
21
|
-
script:
|
38
|
+
script:
|
39
|
+
- bundle _1.11.2_ exec rake test
|
40
|
+
- BUNDLE_GEMFILE=./Gemfile.norbnacl bundle _1.11.2_ exec rake test
|
41
|
+
- bundle _1.11.2_ exec rake test_test
|
42
|
+
- bundle _1.11.2_ exec rubocop
|
data/CHANGES.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
=== 4.0.0.alpha4
|
2
|
+
|
3
|
+
* Experimental event loop abstraction [Miklos Fazekas]
|
4
|
+
* RbNacl dependency is optional [Miklos Fazekas]
|
5
|
+
* agent_socket_factory option [Alon Goldboim]
|
6
|
+
* client sends KEXINIT, it doesn't have to wait for server [Miklos Fazekas]
|
7
|
+
* better error message when option is nil [Kane Morgan]
|
8
|
+
* prompting can be customized [Miklos Fazekas]
|
9
|
+
|
1
10
|
=== 4.0.0.alpha3
|
2
11
|
|
3
12
|
* added max_select_wait_time [Eugene Kenny]
|
data/Gemfile.norbnacl
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
net-ssh (4.0.0.alpha3)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.2.0)
|
10
|
+
metaclass (0.0.4)
|
11
|
+
minitest (5.8.4)
|
12
|
+
mocha (1.1.0)
|
13
|
+
metaclass (~> 0.0.1)
|
14
|
+
parser (2.3.1.0)
|
15
|
+
ast (~> 2.2)
|
16
|
+
powerpack (0.1.1)
|
17
|
+
rainbow (2.1.0)
|
18
|
+
rake (11.1.2)
|
19
|
+
rubocop (0.39.0)
|
20
|
+
parser (>= 2.3.0.7, < 3.0)
|
21
|
+
powerpack (~> 0.1)
|
22
|
+
rainbow (>= 1.99.1, < 3.0)
|
23
|
+
ruby-progressbar (~> 1.7)
|
24
|
+
unicode-display_width (~> 1.0, >= 1.0.1)
|
25
|
+
ruby-progressbar (1.8.0)
|
26
|
+
unicode-display_width (1.0.5)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
|
31
|
+
DEPENDENCIES
|
32
|
+
bundler (~> 1.11.2)
|
33
|
+
minitest (~> 5.0)
|
34
|
+
mocha (>= 1.1.0)
|
35
|
+
net-ssh!
|
36
|
+
rake (~> 11.1)
|
37
|
+
rubocop (~> 0.39.0)
|
38
|
+
|
39
|
+
BUNDLED WITH
|
40
|
+
1.11.2
|
data/README.rdoc
CHANGED
@@ -79,8 +79,6 @@ The only requirement you might be missing is the OpenSSL bindings for Ruby. Thes
|
|
79
79
|
|
80
80
|
If that spits out something like "OpenSSL 0.9.8g 19 Oct 2007", then you're set. If you get an error, then you'll need to see about rebuilding ruby with OpenSSL support, or (if your platform supports it) installing the OpenSSL bindings separately.
|
81
81
|
|
82
|
-
Additionally: if you are going to be having Net::SSH prompt you for things like passwords or certificate passphrases, you'll want to have either the Highline (recommended) or Termios (unix systems only) gem installed, so that the passwords don't echo in clear text.
|
83
|
-
|
84
82
|
Lastly, if you want to run the tests or use any of the Rake tasks, you'll need Mocha and other dependencies listed in Gemfile
|
85
83
|
|
86
84
|
|
data/Rakefile
CHANGED
@@ -75,5 +75,15 @@ Rake::TestTask.new do |t|
|
|
75
75
|
t.libs << "test/integration" if ENV['NET_SSH_RUN_INTEGRATION_TESTS']
|
76
76
|
test_files = FileList['test/**/test_*.rb']
|
77
77
|
test_files -= FileList['test/integration/**/test_*.rb'] unless ENV['NET_SSH_RUN_INTEGRATION_TESTS']
|
78
|
+
test_files -= FileList['test/test/**/test_*.rb']
|
79
|
+
t.test_files = test_files
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "Run tests of Net::SSH:Test"
|
83
|
+
Rake::TestTask.new do |t|
|
84
|
+
t.name = "test_test"
|
85
|
+
# we need to run test/test separatedly as it hacks io + other modules
|
86
|
+
t.libs = ["lib", "test"]
|
87
|
+
test_files = FileList['test/test/**/test_*.rb']
|
78
88
|
t.test_files = test_files
|
79
89
|
end
|
data/appveyor.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
version: '{build}'
|
2
|
+
|
3
|
+
skip_tags: true
|
4
|
+
|
5
|
+
environment:
|
6
|
+
matrix:
|
7
|
+
- ruby_version: "21"
|
8
|
+
- ruby_version: "21-x64"
|
9
|
+
|
10
|
+
install:
|
11
|
+
- SET PATH=C:\Ruby%ruby_version%\bin;%PATH%
|
12
|
+
- gem install bundler --no-document -v 1.11.2
|
13
|
+
- BUNDLE_GEMFILE=./Gemfile.norbnacl bundle _1.11.2_ install --retry=3
|
14
|
+
|
15
|
+
test_script:
|
16
|
+
- BUNDLE_GEMFILE=./Gemfile.norbnacl bundle _1.11.2_ exec rake test
|
17
|
+
|
18
|
+
build: off
|
data/lib/net/ssh.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
ENV['HOME'] ||= ENV['HOMEPATH'] ? "#{ENV['HOMEDRIVE']}#{ENV['HOMEPATH']}" : Dir.pwd
|
4
4
|
|
5
5
|
require 'logger'
|
6
|
+
require 'etc'
|
6
7
|
|
7
8
|
require 'net/ssh/config'
|
8
9
|
require 'net/ssh/errors'
|
@@ -10,6 +11,7 @@ require 'net/ssh/loggable'
|
|
10
11
|
require 'net/ssh/transport/session'
|
11
12
|
require 'net/ssh/authentication/session'
|
12
13
|
require 'net/ssh/connection/session'
|
14
|
+
require 'net/ssh/prompt'
|
13
15
|
|
14
16
|
module Net
|
15
17
|
|
@@ -69,7 +71,7 @@ module Net
|
|
69
71
|
:known_hosts, :global_known_hosts_file, :user_known_hosts_file, :host_key_alias,
|
70
72
|
:host_name, :user, :properties, :passphrase, :keys_only, :max_pkt_size,
|
71
73
|
:max_win_size, :send_env, :use_agent, :number_of_password_prompts,
|
72
|
-
:append_supported_algorithms, :non_interactive
|
74
|
+
:append_supported_algorithms, :non_interactive, :password_prompt, :agent_socket_factory
|
73
75
|
]
|
74
76
|
|
75
77
|
# The standard means of starting a new SSH connection. When used with a
|
@@ -176,7 +178,7 @@ module Net
|
|
176
178
|
# * :user_known_hosts_file => the location of the user known hosts file.
|
177
179
|
# Set to an array to specify multiple user known hosts files.
|
178
180
|
# Defaults to %w(~/.ssh/known_hosts ~/.ssh/known_hosts2).
|
179
|
-
# * :use_agent => Set false to disable the use of ssh-agent. Defaults to
|
181
|
+
# * :use_agent => Set false to disable the use of ssh-agent. Defaults to
|
180
182
|
# true
|
181
183
|
# * :non_interactive => set to true if your app is non interactive and prefers
|
182
184
|
# authentication failure vs password prompt
|
@@ -191,7 +193,11 @@ module Net
|
|
191
193
|
# password auth method
|
192
194
|
# * :non_interactive => non interactive applications should set it to true
|
193
195
|
# to prefer failing a password/etc auth methods vs asking for password
|
196
|
+
# * :password_prompt => a custom prompt object with ask method. See Net::SSH::Prompt
|
194
197
|
#
|
198
|
+
# * :agent_socket_factory => enables the user to pass a lambda/block that will serve as the socket factory
|
199
|
+
# Net::SSH::start(user,host,agent_socket_factory: ->{ UNIXSocket.open('/foo/bar') })
|
200
|
+
# example: ->{ UNIXSocket.open('/foo/bar')}
|
195
201
|
# If +user+ parameter is nil it defaults to USER from ssh_config, or
|
196
202
|
# local username
|
197
203
|
def self.start(host, user=nil, options={}, &block)
|
@@ -200,6 +206,11 @@ module Net
|
|
200
206
|
raise ArgumentError, "invalid option(s): #{invalid_options.join(', ')}"
|
201
207
|
end
|
202
208
|
|
209
|
+
if options.values.include? nil
|
210
|
+
nil_options = options.keys.select { |k| options[k].nil? }
|
211
|
+
raise ArgumentError, "Value(s) have been set to nil: #{nil_options.join(', ')}"
|
212
|
+
end
|
213
|
+
|
203
214
|
options[:user] = user if user
|
204
215
|
options = configuration_for(host, options.fetch(:config, true)).merge(options)
|
205
216
|
host = options.fetch(:host_name, host)
|
@@ -213,6 +224,8 @@ module Net
|
|
213
224
|
options[:number_of_password_prompts] = 0
|
214
225
|
end
|
215
226
|
|
227
|
+
options[:password_prompt] ||= Prompt.default(options)
|
228
|
+
|
216
229
|
if options[:verbose]
|
217
230
|
options[:logger].level = case options[:verbose]
|
218
231
|
when Fixnum then options[:verbose]
|
@@ -19,7 +19,7 @@ module Net; module SSH; module Authentication
|
|
19
19
|
|
20
20
|
# Instantiates a new agent object, connects to a running SSH agent,
|
21
21
|
# negotiates the agent protocol version, and returns the agent object.
|
22
|
-
def self.connect(logger=nil)
|
22
|
+
def self.connect(logger=nil, agent_socket_factory)
|
23
23
|
agent = new(logger)
|
24
24
|
agent.connect!
|
25
25
|
agent
|
@@ -42,9 +42,9 @@ module Net; module SSH; module Authentication
|
|
42
42
|
|
43
43
|
# Instantiates a new agent object, connects to a running SSH agent,
|
44
44
|
# negotiates the agent protocol version, and returns the agent object.
|
45
|
-
def self.connect(logger=nil)
|
45
|
+
def self.connect(logger=nil, agent_socket_factory = nil)
|
46
46
|
agent = new(logger)
|
47
|
-
agent.connect!
|
47
|
+
agent.connect!(agent_socket_factory)
|
48
48
|
agent.negotiate!
|
49
49
|
agent
|
50
50
|
end
|
@@ -59,10 +59,10 @@ module Net; module SSH; module Authentication
|
|
59
59
|
# given by the attribute writers. If the agent on the other end of the
|
60
60
|
# socket reports that it is an SSH2-compatible agent, this will fail
|
61
61
|
# (it only supports the ssh-agent distributed by OpenSSH).
|
62
|
-
def connect!
|
62
|
+
def connect!(agent_socket_factory = nil)
|
63
63
|
begin
|
64
64
|
debug { "connecting to ssh-agent" }
|
65
|
-
@socket = agent_socket_factory.open(ENV['SSH_AUTH_SOCK'])
|
65
|
+
@socket = agent_socket_factory.nil? ? socket_class.open(ENV['SSH_AUTH_SOCK']) : agent_socket_factory.call
|
66
66
|
rescue
|
67
67
|
error { "could not connect to ssh-agent" }
|
68
68
|
raise AgentNotAvailable, $!.message
|
@@ -132,7 +132,7 @@ module Net; module SSH; module Authentication
|
|
132
132
|
private
|
133
133
|
|
134
134
|
# Returns the agent socket factory to use.
|
135
|
-
def
|
135
|
+
def socket_class
|
136
136
|
if Net::SSH::Authentication::PLATFORM == :win32
|
137
137
|
Pageant::Socket
|
138
138
|
else
|
@@ -1,5 +1,6 @@
|
|
1
|
-
gem 'rbnacl-libsodium'
|
2
|
-
gem 'rbnacl'
|
1
|
+
gem 'rbnacl-libsodium', '~> 1.0.10'
|
2
|
+
gem 'rbnacl', '~> 3.3.0'
|
3
|
+
gem 'bcrypt_pbkdf', '~> 1.0.0.alpha1' unless RUBY_PLATFORM == "java"
|
3
4
|
|
4
5
|
require 'rbnacl/libsodium'
|
5
6
|
require 'rbnacl'
|
@@ -13,20 +14,14 @@ require 'base64'
|
|
13
14
|
require 'net/ssh/transport/cipher_factory'
|
14
15
|
require 'bcrypt_pbkdf' unless RUBY_PLATFORM == "java"
|
15
16
|
|
16
|
-
module
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@signing_key = sk
|
22
|
-
@verify_key = VerifyKey.new(pk)
|
23
|
-
end
|
24
|
-
end
|
17
|
+
module ED25519
|
18
|
+
class SigningKeyFromFile < RbNaCl::Signatures::Ed25519::SigningKey
|
19
|
+
def initialize(pk,sk)
|
20
|
+
@signing_key = sk
|
21
|
+
@verify_key = RbNaCl::Signatures::Ed25519::VerifyKey.new(pk)
|
25
22
|
end
|
26
23
|
end
|
27
|
-
end
|
28
24
|
|
29
|
-
module ED25519
|
30
25
|
class PubKey
|
31
26
|
def initialize(data)
|
32
27
|
@verify_key = RbNaCl::Signatures::Ed25519::VerifyKey.new(data)
|
@@ -118,7 +113,7 @@ module ED25519
|
|
118
113
|
_comment = decoded.read_string
|
119
114
|
|
120
115
|
@pk = pk
|
121
|
-
@sign_key =
|
116
|
+
@sign_key = SigningKeyFromFile.new(pk,sk)
|
122
117
|
end
|
123
118
|
|
124
119
|
def public_key
|
@@ -176,7 +176,7 @@ module Net
|
|
176
176
|
# or if the agent is otherwise not available.
|
177
177
|
def agent
|
178
178
|
return unless use_agent?
|
179
|
-
@agent ||= Agent.connect(logger)
|
179
|
+
@agent ||= Agent.connect(logger, options[:agent_socket_factory])
|
180
180
|
rescue AgentNotAvailable
|
181
181
|
@use_agent = false
|
182
182
|
nil
|
@@ -221,11 +221,11 @@ module Net
|
|
221
221
|
key = KeyFactory.load_public_key(identity[:pubkey_file])
|
222
222
|
{ :public_key => key, :from => :file, :file => identity[:privkey_file] }
|
223
223
|
when :privkey_file
|
224
|
-
private_key = KeyFactory.load_private_key(identity[:privkey_file], options[:passphrase], ask_passphrase)
|
224
|
+
private_key = KeyFactory.load_private_key(identity[:privkey_file], options[:passphrase], ask_passphrase, options[:password_prompt])
|
225
225
|
key = private_key.send(:public_key)
|
226
226
|
{ :public_key => key, :from => :file, :file => identity[:privkey_file], :key => private_key }
|
227
227
|
when :data
|
228
|
-
private_key = KeyFactory.load_data_private_key(identity[:data], options[:passphrase], ask_passphrase)
|
228
|
+
private_key = KeyFactory.load_data_private_key(identity[:data], options[:passphrase], ask_passphrase, "<key in memory>", options[:password_prompt])
|
229
229
|
key = private_key.send(:public_key)
|
230
230
|
{ :public_key => key, :from => :key_data, :data => identity[:data], :key => private_key }
|
231
231
|
else
|
@@ -22,6 +22,7 @@ module Net; module SSH; module Authentication; module Methods
|
|
22
22
|
@session = session
|
23
23
|
@key_manager = options[:key_manager]
|
24
24
|
@options = options
|
25
|
+
@prompt = options[:password_prompt]
|
25
26
|
self.logger = session.logger
|
26
27
|
end
|
27
28
|
|
@@ -55,6 +56,9 @@ module Net; module SSH; module Authentication; module Methods
|
|
55
56
|
buffer
|
56
57
|
end
|
57
58
|
|
59
|
+
private
|
60
|
+
|
61
|
+
attr_reader :prompt
|
58
62
|
end
|
59
63
|
|
60
64
|
end; end; end; end
|
@@ -8,8 +8,6 @@ module Net
|
|
8
8
|
|
9
9
|
# Implements the "keyboard-interactive" SSH authentication method.
|
10
10
|
class KeyboardInteractive < Abstract
|
11
|
-
include Prompt
|
12
|
-
|
13
11
|
USERAUTH_INFO_REQUEST = 60
|
14
12
|
USERAUTH_INFO_RESPONSE = 61
|
15
13
|
|
@@ -18,12 +16,14 @@ module Net
|
|
18
16
|
debug { "trying keyboard-interactive" }
|
19
17
|
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
|
20
18
|
|
19
|
+
prompter = nil
|
21
20
|
loop do
|
22
21
|
message = session.next_message
|
23
22
|
|
24
23
|
case message.type
|
25
24
|
when USERAUTH_SUCCESS
|
26
25
|
debug { "keyboard-interactive succeeded" }
|
26
|
+
prompter.success if prompter
|
27
27
|
return true
|
28
28
|
when USERAUTH_FAILURE
|
29
29
|
debug { "keyboard-interactive failed" }
|
@@ -31,26 +31,26 @@ module Net
|
|
31
31
|
raise Net::SSH::Authentication::DisallowedMethod unless
|
32
32
|
message[:authentications].split(/,/).include? 'keyboard-interactive'
|
33
33
|
|
34
|
-
return false
|
34
|
+
return false unless interactive?
|
35
|
+
password = nil
|
36
|
+
debug { "retrying keyboard-interactive" }
|
37
|
+
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
|
35
38
|
when USERAUTH_INFO_REQUEST
|
36
39
|
name = message.read_string
|
37
40
|
instruction = message.read_string
|
38
41
|
debug { "keyboard-interactive info request" }
|
39
42
|
|
40
|
-
|
41
|
-
|
42
|
-
puts(name) unless name.empty?
|
43
|
-
puts(instruction) unless instruction.empty?
|
44
|
-
end
|
43
|
+
if password.nil? && interactive? && prompter.nil?
|
44
|
+
prompter = prompt.start(type: 'keyboard-interactive', name: name, instruction: instruction)
|
45
45
|
end
|
46
46
|
|
47
47
|
_ = message.read_string # lang_tag
|
48
48
|
responses =[]
|
49
|
-
|
49
|
+
|
50
50
|
message.read_long.times do
|
51
51
|
text = message.read_string
|
52
52
|
echo = message.read_bool
|
53
|
-
password_to_send = password || (
|
53
|
+
password_to_send = password || (prompter && prompter.ask(text, echo))
|
54
54
|
responses << password_to_send
|
55
55
|
end
|
56
56
|
|
@@ -9,11 +9,10 @@ module Net
|
|
9
9
|
|
10
10
|
# Implements the "password" SSH authentication method.
|
11
11
|
class Password < Abstract
|
12
|
-
include Prompt
|
13
|
-
|
14
12
|
# Attempt to authenticate the given user for the given service. If
|
15
13
|
# the password parameter is nil, this will ask for password
|
16
14
|
def authenticate(next_service, username, password=nil)
|
15
|
+
clear_prompter!
|
17
16
|
retries = 0
|
18
17
|
max_retries = get_max_retries
|
19
18
|
return false if !password && max_retries == 0
|
@@ -37,6 +36,7 @@ module Net
|
|
37
36
|
case message.type
|
38
37
|
when USERAUTH_SUCCESS
|
39
38
|
debug { "password succeeded" }
|
39
|
+
@prompter.success if @prompter
|
40
40
|
return true
|
41
41
|
when USERAUTH_FAILURE
|
42
42
|
return false
|
@@ -52,9 +52,20 @@ module Net
|
|
52
52
|
|
53
53
|
NUMBER_OF_PASSWORD_PROMPTS = 3
|
54
54
|
|
55
|
+
def clear_prompter!
|
56
|
+
@prompt_info = nil
|
57
|
+
@prompter = nil
|
58
|
+
end
|
59
|
+
|
55
60
|
def ask_password(username)
|
61
|
+
host = session.transport.host
|
62
|
+
prompt_info = {type: 'password', user: username, host: host}
|
63
|
+
if @prompt_info != prompt_info
|
64
|
+
@prompt_info = prompt_info
|
65
|
+
@prompter = prompt.start(prompt_info)
|
66
|
+
end
|
56
67
|
echo = false
|
57
|
-
|
68
|
+
@prompter.ask("#{username}@#{host}'s password:", echo)
|
58
69
|
end
|
59
70
|
|
60
71
|
def get_max_retries
|