net-ssh 5.2.0 → 7.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/.dockerignore +6 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +87 -0
- data/.github/workflows/rubocop.yml +13 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +16 -2
- data/.rubocop_todo.yml +623 -511
- data/CHANGES.txt +50 -2
- data/Dockerfile +27 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +2 -0
- data/Gemfile.noed25519 +2 -0
- data/Manifest +0 -1
- data/README.md +293 -0
- data/Rakefile +6 -2
- data/appveyor.yml +4 -2
- data/docker-compose.yml +23 -0
- data/lib/net/ssh/authentication/agent.rb +29 -13
- data/lib/net/ssh/authentication/certificate.rb +19 -7
- data/lib/net/ssh/authentication/constants.rb +0 -1
- data/lib/net/ssh/authentication/ed25519.rb +13 -8
- data/lib/net/ssh/authentication/ed25519_loader.rb +5 -8
- data/lib/net/ssh/authentication/key_manager.rb +73 -32
- data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
- data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +5 -3
- data/lib/net/ssh/authentication/methods/none.rb +6 -9
- data/lib/net/ssh/authentication/methods/password.rb +2 -3
- data/lib/net/ssh/authentication/methods/publickey.rb +56 -16
- data/lib/net/ssh/authentication/pageant.rb +97 -97
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -3
- data/lib/net/ssh/authentication/session.rb +27 -23
- data/lib/net/ssh/buffer.rb +51 -40
- data/lib/net/ssh/buffered_io.rb +24 -26
- data/lib/net/ssh/config.rb +82 -50
- data/lib/net/ssh/connection/channel.rb +101 -87
- data/lib/net/ssh/connection/constants.rb +0 -4
- data/lib/net/ssh/connection/event_loop.rb +30 -25
- data/lib/net/ssh/connection/keepalive.rb +12 -12
- data/lib/net/ssh/connection/session.rb +115 -111
- data/lib/net/ssh/connection/term.rb +56 -58
- data/lib/net/ssh/errors.rb +12 -12
- data/lib/net/ssh/key_factory.rb +10 -13
- data/lib/net/ssh/known_hosts.rb +106 -39
- data/lib/net/ssh/loggable.rb +10 -11
- data/lib/net/ssh/packet.rb +1 -1
- data/lib/net/ssh/prompt.rb +9 -11
- data/lib/net/ssh/proxy/command.rb +1 -2
- data/lib/net/ssh/proxy/errors.rb +2 -4
- data/lib/net/ssh/proxy/http.rb +18 -20
- data/lib/net/ssh/proxy/https.rb +8 -10
- data/lib/net/ssh/proxy/jump.rb +8 -10
- data/lib/net/ssh/proxy/socks4.rb +2 -4
- data/lib/net/ssh/proxy/socks5.rb +3 -6
- data/lib/net/ssh/service/forward.rb +9 -8
- data/lib/net/ssh/test/channel.rb +24 -26
- data/lib/net/ssh/test/extensions.rb +35 -35
- data/lib/net/ssh/test/kex.rb +6 -8
- data/lib/net/ssh/test/local_packet.rb +0 -2
- data/lib/net/ssh/test/packet.rb +3 -3
- data/lib/net/ssh/test/remote_packet.rb +6 -8
- data/lib/net/ssh/test/script.rb +25 -27
- data/lib/net/ssh/test/socket.rb +12 -15
- data/lib/net/ssh/test.rb +7 -7
- data/lib/net/ssh/transport/algorithms.rb +100 -58
- data/lib/net/ssh/transport/cipher_factory.rb +34 -50
- data/lib/net/ssh/transport/constants.rb +13 -9
- data/lib/net/ssh/transport/ctr.rb +8 -14
- data/lib/net/ssh/transport/hmac/abstract.rb +20 -5
- data/lib/net/ssh/transport/hmac/md5.rb +0 -2
- data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/none.rb +0 -2
- data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +13 -11
- data/lib/net/ssh/transport/identity_cipher.rb +11 -13
- data/lib/net/ssh/transport/kex/abstract.rb +130 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +5 -19
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +30 -139
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -8
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +20 -81
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +5 -4
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +5 -4
- data/lib/net/ssh/transport/kex.rb +15 -10
- data/lib/net/ssh/transport/key_expander.rb +7 -8
- data/lib/net/ssh/transport/openssl.rb +149 -127
- data/lib/net/ssh/transport/packet_stream.rb +50 -16
- data/lib/net/ssh/transport/server_version.rb +17 -16
- data/lib/net/ssh/transport/session.rb +9 -7
- data/lib/net/ssh/transport/state.rb +44 -44
- data/lib/net/ssh/verifiers/accept_new.rb +0 -2
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
- data/lib/net/ssh/verifiers/always.rb +6 -4
- data/lib/net/ssh/verifiers/never.rb +0 -2
- data/lib/net/ssh/version.rb +3 -3
- data/lib/net/ssh.rb +12 -8
- data/net-ssh-public_cert.pem +8 -8
- data/net-ssh.gemspec +9 -7
- data/support/ssh_tunnel_bug.rb +3 -3
- data.tar.gz.sig +0 -0
- metadata +55 -30
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -53
- data/Gemfile.noed25519.lock +0 -41
- data/README.rdoc +0 -194
- data/lib/net/ssh/ruby_compat.rb +0 -13
- data/support/arcfour_check.rb +0 -20
@@ -6,16 +6,14 @@ require 'net/ssh/connection/constants'
|
|
6
6
|
require 'net/ssh/transport/constants'
|
7
7
|
require 'net/ssh/transport/packet_stream'
|
8
8
|
|
9
|
-
module Net
|
10
|
-
module SSH
|
9
|
+
module Net
|
10
|
+
module SSH
|
11
11
|
module Test
|
12
|
-
|
13
12
|
# A collection of modules used to extend/override the default behavior of
|
14
13
|
# Net::SSH internals for ease of testing. As a consumer of Net::SSH, you'll
|
15
14
|
# never need to use this directly--they're all used under the covers by
|
16
15
|
# the Net::SSH::Test system.
|
17
16
|
module Extensions
|
18
|
-
|
19
17
|
# An extension to Net::SSH::BufferedIo (assumes that the underlying IO
|
20
18
|
# is actually a StringIO). Facilitates unit testing.
|
21
19
|
module BufferedIo
|
@@ -24,80 +22,82 @@ module Net
|
|
24
22
|
def select_for_read?
|
25
23
|
pos < size
|
26
24
|
end
|
27
|
-
|
25
|
+
|
28
26
|
# Set this to +true+ if you want the IO to pretend to be available for writing
|
29
27
|
attr_accessor :select_for_write
|
30
|
-
|
28
|
+
|
31
29
|
# Set this to +true+ if you want the IO to pretend to be in an error state
|
32
30
|
attr_accessor :select_for_error
|
33
|
-
|
31
|
+
|
34
32
|
alias select_for_write? select_for_write
|
35
33
|
alias select_for_error? select_for_error
|
36
34
|
end
|
37
|
-
|
35
|
+
|
38
36
|
# An extension to Net::SSH::Transport::PacketStream (assumes that the
|
39
37
|
# underlying IO is actually a StringIO). Facilitates unit testing.
|
40
38
|
module PacketStream
|
41
39
|
include BufferedIo # make sure we get the extensions here, too
|
42
|
-
|
43
|
-
def self.included(base)
|
40
|
+
|
41
|
+
def self.included(base) # :nodoc:
|
44
42
|
base.send :alias_method, :real_available_for_read?, :available_for_read?
|
45
43
|
base.send :alias_method, :available_for_read?, :test_available_for_read?
|
46
|
-
|
44
|
+
|
47
45
|
base.send :alias_method, :real_enqueue_packet, :enqueue_packet
|
48
46
|
base.send :alias_method, :enqueue_packet, :test_enqueue_packet
|
49
|
-
|
47
|
+
|
50
48
|
base.send :alias_method, :real_poll_next_packet, :poll_next_packet
|
51
49
|
base.send :alias_method, :poll_next_packet, :test_poll_next_packet
|
52
50
|
end
|
53
|
-
|
51
|
+
|
54
52
|
# Called when another packet should be inspected from the current
|
55
53
|
# script. If the next packet is a remote packet, it pops it off the
|
56
54
|
# script and shoves it onto this IO object, making it available to
|
57
55
|
# be read.
|
58
56
|
def idle!
|
59
57
|
return false unless script.next(:first)
|
60
|
-
|
58
|
+
|
61
59
|
if script.next(:first).remote?
|
62
60
|
self.string << script.next.to_s
|
63
61
|
self.pos = pos
|
64
62
|
end
|
65
|
-
|
63
|
+
|
66
64
|
return true
|
67
65
|
end
|
68
|
-
|
66
|
+
|
69
67
|
# The testing version of Net::SSH::Transport::PacketStream#available_for_read?.
|
70
68
|
# Returns true if there is data pending to be read. Otherwise calls #idle!.
|
71
69
|
def test_available_for_read?
|
72
70
|
return true if select_for_read?
|
71
|
+
|
73
72
|
idle!
|
74
73
|
false
|
75
74
|
end
|
76
|
-
|
75
|
+
|
77
76
|
# The testing version of Net::SSH::Transport::PacketStream#enqueued_packet.
|
78
77
|
# Simply calls Net::SSH::Test::Script#process on the packet.
|
79
78
|
def test_enqueue_packet(payload)
|
80
79
|
packet = Net::SSH::Buffer.new(payload.to_s)
|
81
80
|
script.process(packet)
|
82
81
|
end
|
83
|
-
|
82
|
+
|
84
83
|
# The testing version of Net::SSH::Transport::PacketStream#poll_next_packet.
|
85
84
|
# Reads the next available packet from the IO object and returns it.
|
86
85
|
def test_poll_next_packet
|
87
86
|
return nil if available <= 0
|
87
|
+
|
88
88
|
packet = Net::SSH::Buffer.new(read_available(4))
|
89
89
|
length = packet.read_long
|
90
90
|
Net::SSH::Packet.new(read_available(length))
|
91
91
|
end
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
# An extension to Net::SSH::Connection::Channel. Facilitates unit testing.
|
95
95
|
module Channel
|
96
|
-
def self.included(base)
|
96
|
+
def self.included(base) # :nodoc:
|
97
97
|
base.send :alias_method, :send_data_for_real, :send_data
|
98
98
|
base.send :alias_method, :send_data, :send_data_for_test
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
# The testing version of Net::SSH::Connection::Channel#send_data. Calls
|
102
102
|
# the original implementation, and then immediately enqueues the data for
|
103
103
|
# output so that scripted sends are properly interpreted as discrete
|
@@ -107,16 +107,16 @@ module Net
|
|
107
107
|
enqueue_pending_output
|
108
108
|
end
|
109
109
|
end
|
110
|
-
|
110
|
+
|
111
111
|
# An extension to the built-in ::IO class. Simply redefines IO.select
|
112
112
|
# so that it can be scripted in Net::SSH unit tests.
|
113
113
|
module IO
|
114
|
-
def self.included(base)
|
114
|
+
def self.included(base) # :nodoc:
|
115
115
|
base.extend(ClassMethods)
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
@extension_enabled = false
|
119
|
-
|
119
|
+
|
120
120
|
def self.with_test_extension(&block)
|
121
121
|
orig_value = @extension_enabled
|
122
122
|
@extension_enabled = true
|
@@ -126,35 +126,36 @@ module Net
|
|
126
126
|
@extension_enabled = orig_value
|
127
127
|
end
|
128
128
|
end
|
129
|
-
|
129
|
+
|
130
130
|
def self.extension_enabled?
|
131
131
|
@extension_enabled
|
132
132
|
end
|
133
|
-
|
133
|
+
|
134
134
|
module ClassMethods
|
135
|
-
def self.extended(obj)
|
136
|
-
class <<obj
|
135
|
+
def self.extended(obj) # :nodoc:
|
136
|
+
class << obj
|
137
137
|
alias_method :select_for_real, :select
|
138
138
|
alias_method :select, :select_for_test
|
139
139
|
end
|
140
140
|
end
|
141
|
-
|
141
|
+
|
142
142
|
# The testing version of ::IO.select. Assumes that all readers,
|
143
143
|
# writers, and errors arrays are either nil, or contain only objects
|
144
144
|
# that mix in Net::SSH::Test::Extensions::BufferedIo.
|
145
|
-
def select_for_test(readers=nil, writers=nil, errors=nil, wait=nil)
|
145
|
+
def select_for_test(readers = nil, writers = nil, errors = nil, wait = nil)
|
146
146
|
return select_for_real(readers, writers, errors, wait) unless Net::SSH::Test::Extensions::IO.extension_enabled?
|
147
|
+
|
147
148
|
ready_readers = Array(readers).select { |r| r.select_for_read? }
|
148
149
|
ready_writers = Array(writers).select { |r| r.select_for_write? }
|
149
150
|
ready_errors = Array(errors).select { |r| r.select_for_error? }
|
150
|
-
|
151
|
+
|
151
152
|
return [ready_readers, ready_writers, ready_errors] if ready_readers.any? || ready_writers.any? || ready_errors.any?
|
152
|
-
|
153
|
+
|
153
154
|
processed = 0
|
154
155
|
Array(readers).each do |reader|
|
155
156
|
processed += 1 if reader.idle!
|
156
157
|
end
|
157
|
-
|
158
|
+
|
158
159
|
raise "no readers were ready for reading, and none had any incoming packets" if processed == 0 && wait != 0
|
159
160
|
|
160
161
|
[[], [], []]
|
@@ -162,7 +163,6 @@ module Net
|
|
162
163
|
end
|
163
164
|
end
|
164
165
|
end
|
165
|
-
|
166
166
|
end
|
167
167
|
end
|
168
168
|
end
|
data/lib/net/ssh/test/kex.rb
CHANGED
@@ -5,10 +5,9 @@ require 'net/ssh/transport/algorithms'
|
|
5
5
|
require 'net/ssh/transport/constants'
|
6
6
|
require 'net/ssh/transport/kex'
|
7
7
|
|
8
|
-
module Net
|
9
|
-
module SSH
|
8
|
+
module Net
|
9
|
+
module SSH
|
10
10
|
module Test
|
11
|
-
|
12
11
|
# An implementation of a key-exchange strategy specifically for unit tests.
|
13
12
|
# (This strategy would never really work against a real SSH server--it makes
|
14
13
|
# too many assumptions about the server's response.)
|
@@ -17,29 +16,28 @@ module Net
|
|
17
16
|
# "test" algorithm.
|
18
17
|
class Kex
|
19
18
|
include Net::SSH::Transport::Constants
|
20
|
-
|
19
|
+
|
21
20
|
# Creates a new instance of the testing key-exchange algorithm with the
|
22
21
|
# given arguments.
|
23
22
|
def initialize(algorithms, connection, data)
|
24
23
|
@connection = connection
|
25
24
|
end
|
26
|
-
|
25
|
+
|
27
26
|
# Exchange keys with the server. This returns a hash of constant values,
|
28
27
|
# and does not actually exchange keys.
|
29
28
|
def exchange_keys
|
30
29
|
result = Net::SSH::Buffer.from(:byte, NEWKEYS)
|
31
30
|
@connection.send_message(result)
|
32
|
-
|
31
|
+
|
33
32
|
buffer = @connection.next_message
|
34
33
|
raise Net::SSH::Exception, "expected NEWKEYS" unless buffer.type == NEWKEYS
|
35
|
-
|
34
|
+
|
36
35
|
{ session_id: "abc-xyz",
|
37
36
|
server_key: OpenSSL::PKey::RSA.new(512),
|
38
37
|
shared_secret: OpenSSL::BN.new("1234567890", 10),
|
39
38
|
hashing_algorithm: OpenSSL::Digest::SHA1 }
|
40
39
|
end
|
41
40
|
end
|
42
|
-
|
43
41
|
end
|
44
42
|
end
|
45
43
|
end
|
@@ -4,7 +4,6 @@ require 'net/ssh/test/packet'
|
|
4
4
|
module Net
|
5
5
|
module SSH
|
6
6
|
module Test
|
7
|
-
|
8
7
|
# This is a specialization of Net::SSH::Test::Packet for representing mock
|
9
8
|
# packets that are sent from the local (client) host. These are created
|
10
9
|
# automatically by Net::SSH::Test::Script and Net::SSH::Test::Channel by any
|
@@ -49,7 +48,6 @@ module Net
|
|
49
48
|
end
|
50
49
|
end
|
51
50
|
end
|
52
|
-
|
53
51
|
end
|
54
52
|
end
|
55
53
|
end
|
data/lib/net/ssh/test/packet.rb
CHANGED
@@ -4,7 +4,6 @@ require 'net/ssh/transport/constants'
|
|
4
4
|
module Net
|
5
5
|
module SSH
|
6
6
|
module Test
|
7
|
-
|
8
7
|
# This is an abstract class, not to be instantiated directly, subclassed by
|
9
8
|
# Net::SSH::Test::LocalPacket and Net::SSH::Test::RemotePacket. It implements
|
10
9
|
# functionality common to those subclasses.
|
@@ -70,7 +69,7 @@ module Net
|
|
70
69
|
# added. Unsupported packet types will otherwise raise an exception.
|
71
70
|
def types
|
72
71
|
@types ||= case @type
|
73
|
-
when KEXINIT
|
72
|
+
when KEXINIT
|
74
73
|
%i[long long long long
|
75
74
|
string string string string string string string string string string
|
76
75
|
bool]
|
@@ -83,13 +82,14 @@ module Net
|
|
83
82
|
when CHANNEL_REQUEST
|
84
83
|
parts = %i[long string bool]
|
85
84
|
case @data[1]
|
86
|
-
when "exec", "subsystem","shell" then parts << :string
|
85
|
+
when "exec", "subsystem", "shell" then parts << :string
|
87
86
|
when "exit-status" then parts << :long
|
88
87
|
when "pty-req" then parts.concat(%i[string long long long long string])
|
89
88
|
when "env" then parts.contact(%i[string string])
|
90
89
|
else
|
91
90
|
request = Packet.registered_channel_requests(@data[1])
|
92
91
|
raise "don't know what to do about #{@data[1]} channel request" unless request
|
92
|
+
|
93
93
|
parts.concat(request[:extra_parts])
|
94
94
|
end
|
95
95
|
else raise "don't know how to parse packet type #{@type}"
|
@@ -1,10 +1,9 @@
|
|
1
1
|
require 'net/ssh/buffer'
|
2
2
|
require 'net/ssh/test/packet'
|
3
3
|
|
4
|
-
module Net
|
5
|
-
module SSH
|
4
|
+
module Net
|
5
|
+
module SSH
|
6
6
|
module Test
|
7
|
-
|
8
7
|
# This is a specialization of Net::SSH::Test::Packet for representing mock
|
9
8
|
# packets that are received by the local (client) host. These are created
|
10
9
|
# automatically by Net::SSH::Test::Script and Net::SSH::Test::Channel by any
|
@@ -14,7 +13,7 @@ module Net
|
|
14
13
|
def remote?
|
15
14
|
true
|
16
15
|
end
|
17
|
-
|
16
|
+
|
18
17
|
# The #process method should only be called on Net::SSH::Test::LocalPacket
|
19
18
|
# packets; if it is attempted on a remote packet, then it is an expectation
|
20
19
|
# mismatch (a remote packet was received when a local packet was expected
|
@@ -23,8 +22,8 @@ module Net
|
|
23
22
|
def process(packet)
|
24
23
|
raise "received packet type #{packet.read_byte} and was not expecting any packet"
|
25
24
|
end
|
26
|
-
|
27
|
-
# Returns this remote packet as a string, suitable for parsing by
|
25
|
+
|
26
|
+
# Returns this remote packet as a string, suitable for parsing by
|
28
27
|
# Net::SSH::Transport::PacketStream and friends. When a remote packet is
|
29
28
|
# received, this method is called and the result concatenated onto the
|
30
29
|
# input buffer for the packet stream.
|
@@ -36,7 +35,6 @@ module Net
|
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
39
|
-
|
40
38
|
end
|
41
39
|
end
|
42
|
-
end
|
40
|
+
end
|
data/lib/net/ssh/test/script.rb
CHANGED
@@ -2,10 +2,9 @@ require 'net/ssh/test/channel'
|
|
2
2
|
require 'net/ssh/test/local_packet'
|
3
3
|
require 'net/ssh/test/remote_packet'
|
4
4
|
|
5
|
-
module Net
|
6
|
-
module SSH
|
5
|
+
module Net
|
6
|
+
module SSH
|
7
7
|
module Test
|
8
|
-
|
9
8
|
# Represents a sequence of scripted events that identify the behavior that
|
10
9
|
# a test expects. Methods named "sends_*" create events for packets being
|
11
10
|
# sent from the local to the remote host, and methods named "gets_*" create
|
@@ -22,41 +21,41 @@ module Net
|
|
22
21
|
# The list of scripted events. These will be Net::SSH::Test::LocalPacket
|
23
22
|
# and Net::SSH::Test::RemotePacket instances.
|
24
23
|
attr_reader :events
|
25
|
-
|
24
|
+
|
26
25
|
# Create a new, empty script.
|
27
26
|
def initialize
|
28
27
|
@events = []
|
29
28
|
end
|
30
|
-
|
29
|
+
|
31
30
|
# Scripts the opening of a channel by adding a local packet sending the
|
32
31
|
# channel open request, and if +confirm+ is true (the default), also
|
33
32
|
# adding a remote packet confirming the new channel.
|
34
33
|
#
|
35
34
|
# A new Net::SSH::Test::Channel instance is returned, which can be used
|
36
35
|
# to script additional channel operations.
|
37
|
-
def opens_channel(confirm=true)
|
36
|
+
def opens_channel(confirm = true)
|
38
37
|
channel = Channel.new(self)
|
39
38
|
channel.remote_id = 5555
|
40
|
-
|
39
|
+
|
41
40
|
events << LocalPacket.new(:channel_open) { |p| channel.local_id = p[:remote_id] }
|
42
|
-
|
41
|
+
|
43
42
|
events << RemotePacket.new(:channel_open_confirmation, channel.local_id, channel.remote_id, 0x20000, 0x10000) if confirm
|
44
|
-
|
43
|
+
|
45
44
|
channel
|
46
45
|
end
|
47
|
-
|
46
|
+
|
48
47
|
# A convenience method for adding an arbitrary local packet to the events
|
49
48
|
# list.
|
50
49
|
def sends(type, *args, &block)
|
51
50
|
events << LocalPacket.new(type, *args, &block)
|
52
51
|
end
|
53
|
-
|
52
|
+
|
54
53
|
# A convenience method for adding an arbitrary remote packet to the events
|
55
54
|
# list.
|
56
55
|
def gets(type, *args)
|
57
56
|
events << RemotePacket.new(type, *args)
|
58
57
|
end
|
59
|
-
|
58
|
+
|
60
59
|
# Scripts the sending of a new channel request packet to the remote host.
|
61
60
|
# +channel+ should be an instance of Net::SSH::Test::Channel. +request+
|
62
61
|
# is a string naming the request type to send, +reply+ is a boolean
|
@@ -71,7 +70,7 @@ module Net
|
|
71
70
|
#
|
72
71
|
# This will typically be called via Net::SSH::Test::Channel#sends_exec or
|
73
72
|
# Net::SSH::Test::Channel#sends_subsystem.
|
74
|
-
def sends_channel_request(channel, request, reply, data, success=true)
|
73
|
+
def sends_channel_request(channel, request, reply, data, success = true)
|
75
74
|
if data.is_a? Array
|
76
75
|
events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, *data)
|
77
76
|
else
|
@@ -85,7 +84,7 @@ module Net
|
|
85
84
|
end
|
86
85
|
end
|
87
86
|
end
|
88
|
-
|
87
|
+
|
89
88
|
# Scripts the sending of a channel data packet. +channel+ must be a
|
90
89
|
# Net::SSH::Test::Channel object, and +data+ is the (string) data to
|
91
90
|
# expect will be sent.
|
@@ -94,21 +93,21 @@ module Net
|
|
94
93
|
def sends_channel_data(channel, data)
|
95
94
|
events << LocalPacket.new(:channel_data, channel.remote_id, data)
|
96
95
|
end
|
97
|
-
|
96
|
+
|
98
97
|
# Scripts the sending of a channel EOF packet from the given
|
99
98
|
# Net::SSH::Test::Channel +channel+. This will typically be called via
|
100
99
|
# Net::SSH::Test::Channel#sends_eof.
|
101
100
|
def sends_channel_eof(channel)
|
102
101
|
events << LocalPacket.new(:channel_eof, channel.remote_id)
|
103
102
|
end
|
104
|
-
|
103
|
+
|
105
104
|
# Scripts the sending of a channel close packet from the given
|
106
105
|
# Net::SSH::Test::Channel +channel+. This will typically be called via
|
107
106
|
# Net::SSH::Test::Channel#sends_close.
|
108
107
|
def sends_channel_close(channel)
|
109
108
|
events << LocalPacket.new(:channel_close, channel.remote_id)
|
110
109
|
end
|
111
|
-
|
110
|
+
|
112
111
|
# Scripts the sending of a channel request pty packets from the given
|
113
112
|
# Net::SSH::Test::Channel +channel+. This will typically be called via
|
114
113
|
# Net::SSH::Test::Channel#sends_request_pty.
|
@@ -117,14 +116,14 @@ module Net
|
|
117
116
|
data += Net::SSH::Connection::Channel::VALID_PTY_OPTIONS.merge(modes: "\0").values
|
118
117
|
events << LocalPacket.new(:channel_request, channel.remote_id, *data)
|
119
118
|
end
|
120
|
-
|
119
|
+
|
121
120
|
# Scripts the reception of a channel data packet from the remote host by
|
122
121
|
# the given Net::SSH::Test::Channel +channel+. This will typically be
|
123
122
|
# called via Net::SSH::Test::Channel#gets_data.
|
124
123
|
def gets_channel_data(channel, data)
|
125
124
|
events << RemotePacket.new(:channel_data, channel.local_id, data)
|
126
125
|
end
|
127
|
-
|
126
|
+
|
128
127
|
# Scripts the reception of a channel extended data packet from the remote
|
129
128
|
# host by the given Net::SSH::Test::Channel +channel+. This will typically
|
130
129
|
# be called via Net::SSH::Test::Channel#gets_extended_data.
|
@@ -133,28 +132,28 @@ module Net
|
|
133
132
|
def gets_channel_extended_data(channel, data)
|
134
133
|
events << RemotePacket.new(:channel_extended_data, channel.local_id, 1, data)
|
135
134
|
end
|
136
|
-
|
135
|
+
|
137
136
|
# Scripts the reception of a channel request packet from the remote host by
|
138
137
|
# the given Net::SSH::Test::Channel +channel+. This will typically be
|
139
138
|
# called via Net::SSH::Test::Channel#gets_exit_status.
|
140
139
|
def gets_channel_request(channel, request, reply, data)
|
141
140
|
events << RemotePacket.new(:channel_request, channel.local_id, request, reply, data)
|
142
141
|
end
|
143
|
-
|
142
|
+
|
144
143
|
# Scripts the reception of a channel EOF packet from the remote host by
|
145
144
|
# the given Net::SSH::Test::Channel +channel+. This will typically be
|
146
145
|
# called via Net::SSH::Test::Channel#gets_eof.
|
147
146
|
def gets_channel_eof(channel)
|
148
147
|
events << RemotePacket.new(:channel_eof, channel.local_id)
|
149
148
|
end
|
150
|
-
|
149
|
+
|
151
150
|
# Scripts the reception of a channel close packet from the remote host by
|
152
151
|
# the given Net::SSH::Test::Channel +channel+. This will typically be
|
153
152
|
# called via Net::SSH::Test::Channel#gets_close.
|
154
153
|
def gets_channel_close(channel)
|
155
154
|
events << RemotePacket.new(:channel_close, channel.local_id)
|
156
155
|
end
|
157
|
-
|
156
|
+
|
158
157
|
# By default, removes the next event in the list and returns it. However,
|
159
158
|
# this can also be used to non-destructively peek at the next event in the
|
160
159
|
# list, by passing :first as the argument.
|
@@ -164,10 +163,10 @@ module Net
|
|
164
163
|
#
|
165
164
|
# # peek at the next event
|
166
165
|
# event = script.next(:first)
|
167
|
-
def next(mode
|
166
|
+
def next(mode = :shift)
|
168
167
|
events.send(mode)
|
169
168
|
end
|
170
|
-
|
169
|
+
|
171
170
|
# Compare the given packet against the next event in the list. If there is
|
172
171
|
# no next event, an exception will be raised. This is called by
|
173
172
|
# Net::SSH::Test::Extensions::PacketStream#test_enqueue_packet.
|
@@ -176,7 +175,6 @@ module Net
|
|
176
175
|
event.process(packet)
|
177
176
|
end
|
178
177
|
end
|
179
|
-
|
180
178
|
end
|
181
179
|
end
|
182
|
-
end
|
180
|
+
end
|
data/lib/net/ssh/test/socket.rb
CHANGED
@@ -3,66 +3,63 @@ require 'stringio'
|
|
3
3
|
require 'net/ssh/test/extensions'
|
4
4
|
require 'net/ssh/test/script'
|
5
5
|
|
6
|
-
module Net
|
7
|
-
module SSH
|
6
|
+
module Net
|
7
|
+
module SSH
|
8
8
|
module Test
|
9
|
-
|
10
9
|
# A mock socket implementation for use in testing. It implements the minimum
|
11
10
|
# necessary interface for interacting with the rest of the Net::SSH::Test
|
12
11
|
# system.
|
13
12
|
class Socket < StringIO
|
14
13
|
attr_reader :host, :port
|
15
|
-
|
14
|
+
|
16
15
|
# The Net::SSH::Test::Script object in use by this socket. This is the
|
17
16
|
# canonical script instance that should be used for any test depending on
|
18
17
|
# this socket instance.
|
19
18
|
attr_reader :script
|
20
|
-
|
19
|
+
|
21
20
|
# Create a new test socket. This will also instantiate a new Net::SSH::Test::Script
|
22
21
|
# and seed it with the necessary events to power the initialization of the
|
23
22
|
# connection.
|
24
23
|
def initialize
|
25
24
|
extend(Net::SSH::Transport::PacketStream)
|
26
25
|
super "SSH-2.0-Test\r\n"
|
27
|
-
|
26
|
+
|
28
27
|
@script = Script.new
|
29
|
-
|
28
|
+
|
30
29
|
script.sends(:kexinit)
|
31
30
|
script.gets(:kexinit, 1, 2, 3, 4, "test", "ssh-rsa", "none", "none", "none", "none", "none", "none", "", "", false)
|
32
31
|
script.sends(:newkeys)
|
33
32
|
script.gets(:newkeys)
|
34
33
|
end
|
35
|
-
|
34
|
+
|
36
35
|
# This doesn't actually do anything, since we don't really care what gets
|
37
36
|
# written.
|
38
37
|
def write(data)
|
39
38
|
# black hole, because we don't actually care about what gets written
|
40
39
|
end
|
41
|
-
|
40
|
+
|
42
41
|
# Allows the socket to also mimic a socket factory, simply returning
|
43
42
|
# +self+.
|
44
|
-
def open(host, port, options={})
|
43
|
+
def open(host, port, options = {})
|
45
44
|
@host, @port = host, port
|
46
45
|
self
|
47
46
|
end
|
48
|
-
|
47
|
+
|
49
48
|
# Returns a sockaddr struct for the port and host that were used when the
|
50
49
|
# socket was instantiated.
|
51
50
|
def getpeername
|
52
51
|
::Socket.sockaddr_in(port, host)
|
53
52
|
end
|
54
|
-
|
53
|
+
|
55
54
|
# Alias to #read, but never returns nil (returns an empty string instead).
|
56
55
|
def recv(n)
|
57
56
|
read(n) || ""
|
58
57
|
end
|
59
|
-
|
58
|
+
|
60
59
|
def readpartial(n)
|
61
60
|
recv(n)
|
62
61
|
end
|
63
|
-
|
64
62
|
end
|
65
|
-
|
66
63
|
end
|
67
64
|
end
|
68
65
|
end
|
data/lib/net/ssh/test.rb
CHANGED
@@ -5,7 +5,6 @@ require 'net/ssh/test/socket'
|
|
5
5
|
|
6
6
|
module Net
|
7
7
|
module SSH
|
8
|
-
|
9
8
|
# This module may be used in unit tests, for when you want to test that your
|
10
9
|
# SSH state machines are really doing what you expect they are doing. You will
|
11
10
|
# typically include this module in your unit test class, and then build a
|
@@ -57,24 +56,24 @@ module Net
|
|
57
56
|
|
58
57
|
# Returns the test socket instance to use for these tests (see
|
59
58
|
# Net::SSH::Test::Socket).
|
60
|
-
def socket(options={})
|
59
|
+
def socket(options = {})
|
61
60
|
@socket ||= Net::SSH::Test::Socket.new
|
62
61
|
end
|
63
62
|
|
64
63
|
# Returns the connection session (Net::SSH::Connection::Session) for use
|
65
64
|
# in these tests. It is a fully functional SSH session, operating over
|
66
65
|
# a mock socket (#socket).
|
67
|
-
def connection(options={})
|
66
|
+
def connection(options = {})
|
68
67
|
@connection ||= Net::SSH::Connection::Session.new(transport(options), options)
|
69
68
|
end
|
70
69
|
|
71
70
|
# Returns the transport session (Net::SSH::Transport::Session) for use
|
72
71
|
# in these tests. It is a fully functional SSH transport session, operating
|
73
72
|
# over a mock socket (#socket).
|
74
|
-
def transport(options={})
|
73
|
+
def transport(options = {})
|
75
74
|
@transport ||= Net::SSH::Transport::Session.new(
|
76
75
|
options[:host] || "localhost",
|
77
|
-
options.merge(kex: "test", host_key: "ssh-rsa", verify_host_key: :never, proxy: socket(options))
|
76
|
+
options.merge(kex: "test", host_key: "ssh-rsa", append_all_supported_algorithms: true, verify_host_key: :never, proxy: socket(options))
|
78
77
|
)
|
79
78
|
end
|
80
79
|
|
@@ -85,10 +84,11 @@ module Net
|
|
85
84
|
# the block passed to this assertion.
|
86
85
|
def assert_scripted
|
87
86
|
raise "there is no script to be processed" if socket.script.events.empty?
|
87
|
+
|
88
88
|
Net::SSH::Test::Extensions::IO.with_test_extension { yield }
|
89
|
-
assert socket.script.events.empty?, "there should not be any remaining scripted events, but there are still
|
89
|
+
assert socket.script.events.empty?, "there should not be any remaining scripted events, but there are still" \
|
90
|
+
"#{socket.script.events.length} pending"
|
90
91
|
end
|
91
92
|
end
|
92
|
-
|
93
93
|
end
|
94
94
|
end
|