net-ssh 2.7.0 → 7.3.0
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.dockerignore +6 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +94 -0
- data/.github/workflows/rubocop.yml +16 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +22 -0
- data/.rubocop_todo.yml +1081 -0
- data/CHANGES.txt +387 -0
- data/DEVELOPMENT.md +23 -0
- data/Dockerfile +29 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +13 -0
- data/Gemfile.noed25519 +12 -0
- data/Gemfile.norbnacl +12 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/Manifest +4 -5
- data/README.md +303 -0
- data/Rakefile +174 -40
- data/SECURITY.md +4 -0
- data/THANKS.txt +25 -0
- data/appveyor.yml +58 -0
- data/docker-compose.yml +25 -0
- data/lib/net/ssh/authentication/agent.rb +279 -18
- data/lib/net/ssh/authentication/certificate.rb +183 -0
- data/lib/net/ssh/authentication/constants.rb +17 -15
- data/lib/net/ssh/authentication/ed25519.rb +184 -0
- data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
- data/lib/net/ssh/authentication/key_manager.rb +125 -54
- data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
- data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +19 -12
- data/lib/net/ssh/authentication/methods/none.rb +16 -19
- data/lib/net/ssh/authentication/methods/password.rb +56 -19
- data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
- data/lib/net/ssh/authentication/pageant.rb +483 -246
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +138 -120
- data/lib/net/ssh/buffer.rb +399 -300
- data/lib/net/ssh/buffered_io.rb +154 -150
- data/lib/net/ssh/config.rb +361 -166
- data/lib/net/ssh/connection/channel.rb +640 -596
- data/lib/net/ssh/connection/constants.rb +29 -29
- data/lib/net/ssh/connection/event_loop.rb +123 -0
- data/lib/net/ssh/connection/keepalive.rb +59 -0
- data/lib/net/ssh/connection/session.rb +628 -548
- data/lib/net/ssh/connection/term.rb +125 -123
- data/lib/net/ssh/errors.rb +101 -95
- data/lib/net/ssh/key_factory.rb +198 -100
- data/lib/net/ssh/known_hosts.rb +221 -98
- data/lib/net/ssh/loggable.rb +50 -49
- data/lib/net/ssh/packet.rb +83 -79
- data/lib/net/ssh/prompt.rb +50 -81
- data/lib/net/ssh/proxy/command.rb +108 -60
- data/lib/net/ssh/proxy/errors.rb +12 -10
- data/lib/net/ssh/proxy/http.rb +82 -78
- data/lib/net/ssh/proxy/https.rb +50 -0
- data/lib/net/ssh/proxy/jump.rb +54 -0
- data/lib/net/ssh/proxy/socks4.rb +5 -8
- data/lib/net/ssh/proxy/socks5.rb +18 -20
- data/lib/net/ssh/service/forward.rb +383 -255
- data/lib/net/ssh/test/channel.rb +145 -136
- data/lib/net/ssh/test/extensions.rb +131 -110
- data/lib/net/ssh/test/kex.rb +34 -32
- data/lib/net/ssh/test/local_packet.rb +46 -44
- data/lib/net/ssh/test/packet.rb +89 -70
- data/lib/net/ssh/test/remote_packet.rb +32 -30
- data/lib/net/ssh/test/script.rb +156 -142
- data/lib/net/ssh/test/socket.rb +49 -48
- data/lib/net/ssh/test.rb +82 -77
- data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
- data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
- data/lib/net/ssh/transport/algorithms.rb +472 -348
- data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
- data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
- data/lib/net/ssh/transport/cipher_factory.rb +124 -100
- data/lib/net/ssh/transport/constants.rb +32 -24
- data/lib/net/ssh/transport/ctr.rb +42 -22
- data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +97 -63
- 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 +14 -12
- data/lib/net/ssh/transport/identity_cipher.rb +54 -44
- 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 +33 -40
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
- data/lib/net/ssh/transport/kex.rb +15 -12
- data/lib/net/ssh/transport/key_expander.rb +24 -20
- data/lib/net/ssh/transport/openssl.rb +161 -124
- data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
- data/lib/net/ssh/transport/packet_stream.rb +246 -183
- data/lib/net/ssh/transport/server_version.rb +57 -51
- data/lib/net/ssh/transport/session.rb +307 -235
- data/lib/net/ssh/transport/state.rb +178 -176
- data/lib/net/ssh/verifiers/accept_new.rb +33 -0
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
- data/lib/net/ssh/verifiers/always.rb +58 -0
- data/lib/net/ssh/verifiers/never.rb +19 -0
- data/lib/net/ssh/version.rb +57 -51
- data/lib/net/ssh.rb +140 -40
- data/net-ssh-public_cert.pem +21 -0
- data/net-ssh.gemspec +39 -184
- data/support/ssh_tunnel_bug.rb +5 -5
- data.tar.gz.sig +0 -0
- metadata +205 -99
- metadata.gz.sig +0 -0
- data/README.rdoc +0 -219
- data/Rudyfile +0 -96
- data/gem-public_cert.pem +0 -20
- data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
- data/lib/net/ssh/authentication/agent/socket.rb +0 -170
- data/lib/net/ssh/ruby_compat.rb +0 -51
- data/lib/net/ssh/verifiers/lenient.rb +0 -30
- data/lib/net/ssh/verifiers/null.rb +0 -12
- data/lib/net/ssh/verifiers/secure.rb +0 -54
- data/lib/net/ssh/verifiers/strict.rb +0 -24
- data/setup.rb +0 -1585
- data/support/arcfour_check.rb +0 -20
- data/test/README.txt +0 -47
- data/test/authentication/methods/common.rb +0 -28
- data/test/authentication/methods/test_abstract.rb +0 -51
- data/test/authentication/methods/test_hostbased.rb +0 -114
- data/test/authentication/methods/test_keyboard_interactive.rb +0 -100
- data/test/authentication/methods/test_none.rb +0 -41
- data/test/authentication/methods/test_password.rb +0 -52
- data/test/authentication/methods/test_publickey.rb +0 -148
- data/test/authentication/test_agent.rb +0 -205
- data/test/authentication/test_key_manager.rb +0 -218
- data/test/authentication/test_session.rb +0 -108
- data/test/common.rb +0 -108
- data/test/configs/eqsign +0 -3
- data/test/configs/exact_match +0 -8
- data/test/configs/host_plus +0 -10
- data/test/configs/multihost +0 -4
- data/test/configs/nohost +0 -19
- data/test/configs/numeric_host +0 -4
- data/test/configs/send_env +0 -2
- data/test/configs/substitutes +0 -8
- data/test/configs/wild_cards +0 -14
- data/test/connection/test_channel.rb +0 -467
- data/test/connection/test_session.rb +0 -526
- data/test/known_hosts/github +0 -1
- data/test/manual/test_forward.rb +0 -223
- data/test/start/test_options.rb +0 -36
- data/test/start/test_transport.rb +0 -28
- data/test/test_all.rb +0 -11
- data/test/test_buffer.rb +0 -433
- data/test/test_buffered_io.rb +0 -63
- data/test/test_config.rb +0 -151
- data/test/test_key_factory.rb +0 -173
- data/test/test_known_hosts.rb +0 -13
- data/test/transport/hmac/test_md5.rb +0 -41
- data/test/transport/hmac/test_md5_96.rb +0 -27
- data/test/transport/hmac/test_none.rb +0 -34
- data/test/transport/hmac/test_ripemd160.rb +0 -36
- data/test/transport/hmac/test_sha1.rb +0 -36
- data/test/transport/hmac/test_sha1_96.rb +0 -27
- data/test/transport/hmac/test_sha2_256.rb +0 -37
- data/test/transport/hmac/test_sha2_256_96.rb +0 -27
- data/test/transport/hmac/test_sha2_512.rb +0 -37
- data/test/transport/hmac/test_sha2_512_96.rb +0 -27
- data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -146
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -92
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -34
- data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
- data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
- data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
- data/test/transport/test_algorithms.rb +0 -330
- data/test/transport/test_cipher_factory.rb +0 -443
- data/test/transport/test_hmac.rb +0 -34
- data/test/transport/test_identity_cipher.rb +0 -40
- data/test/transport/test_packet_stream.rb +0 -1755
- data/test/transport/test_server_version.rb +0 -78
- data/test/transport/test_session.rb +0 -319
- data/test/transport/test_state.rb +0 -181
data/lib/net/ssh/test/script.rb
CHANGED
@@ -2,165 +2,179 @@ 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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
5
|
+
module Net
|
6
|
+
module SSH
|
7
|
+
module Test
|
8
|
+
# Represents a sequence of scripted events that identify the behavior that
|
9
|
+
# a test expects. Methods named "sends_*" create events for packets being
|
10
|
+
# sent from the local to the remote host, and methods named "gets_*" create
|
11
|
+
# events for packets being received by the local from the remote host.
|
12
|
+
#
|
13
|
+
# A reference to a script. is generally obtained in a unit test via the
|
14
|
+
# Net::SSH::Test#story helper method:
|
15
|
+
#
|
16
|
+
# story do |script|
|
17
|
+
# channel = script.opens_channel
|
18
|
+
# ...
|
19
|
+
# end
|
20
|
+
class Script
|
21
|
+
# The list of scripted events. These will be Net::SSH::Test::LocalPacket
|
22
|
+
# and Net::SSH::Test::RemotePacket instances.
|
23
|
+
attr_reader :events
|
24
|
+
|
25
|
+
# Create a new, empty script.
|
26
|
+
def initialize
|
27
|
+
@events = []
|
28
|
+
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
30
|
+
# Scripts the opening of a channel by adding a local packet sending the
|
31
|
+
# channel open request, and if +confirm+ is true (the default), also
|
32
|
+
# adding a remote packet confirming the new channel.
|
33
|
+
#
|
34
|
+
# A new Net::SSH::Test::Channel instance is returned, which can be used
|
35
|
+
# to script additional channel operations.
|
36
|
+
def opens_channel(confirm = true)
|
37
|
+
channel = Channel.new(self)
|
38
|
+
channel.remote_id = 5555
|
38
39
|
|
39
|
-
|
40
|
+
events << LocalPacket.new(:channel_open) { |p| channel.local_id = p[:remote_id] }
|
40
41
|
|
41
|
-
|
42
|
-
events << RemotePacket.new(:channel_open_confirmation, channel.local_id, channel.remote_id, 0x20000, 0x10000)
|
43
|
-
end
|
42
|
+
events << RemotePacket.new(:channel_open_confirmation, channel.local_id, channel.remote_id, 0x20000, 0x10000) if confirm
|
44
43
|
|
45
|
-
|
46
|
-
|
44
|
+
channel
|
45
|
+
end
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
47
|
+
# A convenience method for adding an arbitrary local packet to the events
|
48
|
+
# list.
|
49
|
+
def sends(type, *args, &block)
|
50
|
+
events << LocalPacket.new(type, *args, &block)
|
51
|
+
end
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
53
|
+
# A convenience method for adding an arbitrary remote packet to the events
|
54
|
+
# list.
|
55
|
+
def gets(type, *args)
|
56
|
+
events << RemotePacket.new(type, *args)
|
57
|
+
end
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
59
|
+
# Scripts the sending of a new channel request packet to the remote host.
|
60
|
+
# +channel+ should be an instance of Net::SSH::Test::Channel. +request+
|
61
|
+
# is a string naming the request type to send, +reply+ is a boolean
|
62
|
+
# indicating whether a response to this packet is required , and +data+
|
63
|
+
# is any additional request-specific data that this packet should send.
|
64
|
+
# +success+ indicates whether the response (if one is required) should be
|
65
|
+
# success or failure. If +data+ is an array it will be treated as multiple
|
66
|
+
# data.
|
67
|
+
#
|
68
|
+
# If a reply is desired, a remote packet will also be queued, :channel_success
|
69
|
+
# if +success+ is true, or :channel_failure if +success+ is false.
|
70
|
+
#
|
71
|
+
# This will typically be called via Net::SSH::Test::Channel#sends_exec or
|
72
|
+
# Net::SSH::Test::Channel#sends_subsystem.
|
73
|
+
def sends_channel_request(channel, request, reply, data, success = true)
|
74
|
+
if data.is_a? Array
|
75
|
+
events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, *data)
|
76
|
+
else
|
77
|
+
events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, data)
|
78
|
+
end
|
79
|
+
if reply
|
80
|
+
if success
|
81
|
+
events << RemotePacket.new(:channel_success, channel.local_id)
|
82
|
+
else
|
83
|
+
events << RemotePacket.new(:channel_failure, channel.local_id)
|
84
|
+
end
|
85
|
+
end
|
80
86
|
end
|
81
|
-
end
|
82
|
-
end
|
83
87
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
88
|
+
# Scripts the sending of a channel data packet. +channel+ must be a
|
89
|
+
# Net::SSH::Test::Channel object, and +data+ is the (string) data to
|
90
|
+
# expect will be sent.
|
91
|
+
#
|
92
|
+
# This will typically be called via Net::SSH::Test::Channel#sends_data.
|
93
|
+
def sends_channel_data(channel, data)
|
94
|
+
events << LocalPacket.new(:channel_data, channel.remote_id, data)
|
95
|
+
end
|
92
96
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
97
|
+
# Scripts the sending of a channel EOF packet from the given
|
98
|
+
# Net::SSH::Test::Channel +channel+. This will typically be called via
|
99
|
+
# Net::SSH::Test::Channel#sends_eof.
|
100
|
+
def sends_channel_eof(channel)
|
101
|
+
events << LocalPacket.new(:channel_eof, channel.remote_id)
|
102
|
+
end
|
99
103
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
104
|
+
# Scripts the sending of a channel close packet from the given
|
105
|
+
# Net::SSH::Test::Channel +channel+. This will typically be called via
|
106
|
+
# Net::SSH::Test::Channel#sends_close.
|
107
|
+
def sends_channel_close(channel)
|
108
|
+
events << LocalPacket.new(:channel_close, channel.remote_id)
|
109
|
+
end
|
106
110
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
111
|
+
# Scripts the sending of a channel request pty packets from the given
|
112
|
+
# Net::SSH::Test::Channel +channel+. This will typically be called via
|
113
|
+
# Net::SSH::Test::Channel#sends_request_pty.
|
114
|
+
def sends_channel_request_pty(channel)
|
115
|
+
data = ['pty-req', false]
|
116
|
+
data += Net::SSH::Connection::Channel::VALID_PTY_OPTIONS.merge(modes: "\0").values
|
117
|
+
events << LocalPacket.new(:channel_request, channel.remote_id, *data)
|
118
|
+
end
|
113
119
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
events << RemotePacket.new(:channel_extended_data, channel.local_id, 1, data)
|
121
|
-
end
|
120
|
+
# Scripts the reception of a channel data packet from the remote host by
|
121
|
+
# the given Net::SSH::Test::Channel +channel+. This will typically be
|
122
|
+
# called via Net::SSH::Test::Channel#gets_data.
|
123
|
+
def gets_channel_data(channel, data)
|
124
|
+
events << RemotePacket.new(:channel_data, channel.local_id, data)
|
125
|
+
end
|
122
126
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
127
|
+
# Scripts the reception of a channel extended data packet from the remote
|
128
|
+
# host by the given Net::SSH::Test::Channel +channel+. This will typically
|
129
|
+
# be called via Net::SSH::Test::Channel#gets_extended_data.
|
130
|
+
#
|
131
|
+
# Currently the only extended data type is stderr == 1.
|
132
|
+
def gets_channel_extended_data(channel, data)
|
133
|
+
events << RemotePacket.new(:channel_extended_data, channel.local_id, 1, data)
|
134
|
+
end
|
129
135
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
+
# Scripts the reception of a channel request packet from the remote host by
|
137
|
+
# the given Net::SSH::Test::Channel +channel+. This will typically be
|
138
|
+
# called via Net::SSH::Test::Channel#gets_exit_status.
|
139
|
+
def gets_channel_request(channel, request, reply, data)
|
140
|
+
events << RemotePacket.new(:channel_request, channel.local_id, request, reply, data)
|
141
|
+
end
|
136
142
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
+
# Scripts the reception of a channel EOF packet from the remote host by
|
144
|
+
# the given Net::SSH::Test::Channel +channel+. This will typically be
|
145
|
+
# called via Net::SSH::Test::Channel#gets_eof.
|
146
|
+
def gets_channel_eof(channel)
|
147
|
+
events << RemotePacket.new(:channel_eof, channel.local_id)
|
148
|
+
end
|
143
149
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
150
|
+
# Scripts the reception of a channel close packet from the remote host by
|
151
|
+
# the given Net::SSH::Test::Channel +channel+. This will typically be
|
152
|
+
# called via Net::SSH::Test::Channel#gets_close.
|
153
|
+
def gets_channel_close(channel)
|
154
|
+
events << RemotePacket.new(:channel_close, channel.local_id)
|
155
|
+
end
|
156
|
+
|
157
|
+
# By default, removes the next event in the list and returns it. However,
|
158
|
+
# this can also be used to non-destructively peek at the next event in the
|
159
|
+
# list, by passing :first as the argument.
|
160
|
+
#
|
161
|
+
# # remove the next event and return it
|
162
|
+
# event = script.next
|
163
|
+
#
|
164
|
+
# # peek at the next event
|
165
|
+
# event = script.next(:first)
|
166
|
+
def next(mode = :shift)
|
167
|
+
events.send(mode)
|
168
|
+
end
|
156
169
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
170
|
+
# Compare the given packet against the next event in the list. If there is
|
171
|
+
# no next event, an exception will be raised. This is called by
|
172
|
+
# Net::SSH::Test::Extensions::PacketStream#test_enqueue_packet.
|
173
|
+
def process(packet)
|
174
|
+
event = events.shift or raise "end of script reached, but got a packet type #{packet.read_byte}"
|
175
|
+
event.process(packet)
|
176
|
+
end
|
177
|
+
end
|
163
178
|
end
|
164
179
|
end
|
165
|
-
|
166
|
-
end; end; end
|
180
|
+
end
|
data/lib/net/ssh/test/socket.rb
CHANGED
@@ -3,62 +3,63 @@ require 'stringio'
|
|
3
3
|
require 'net/ssh/test/extensions'
|
4
4
|
require 'net/ssh/test/script'
|
5
5
|
|
6
|
-
module Net
|
6
|
+
module Net
|
7
|
+
module SSH
|
8
|
+
module Test
|
9
|
+
# A mock socket implementation for use in testing. It implements the minimum
|
10
|
+
# necessary interface for interacting with the rest of the Net::SSH::Test
|
11
|
+
# system.
|
12
|
+
class Socket < StringIO
|
13
|
+
attr_reader :host, :port
|
7
14
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
attr_reader :host, :port
|
15
|
+
# The Net::SSH::Test::Script object in use by this socket. This is the
|
16
|
+
# canonical script instance that should be used for any test depending on
|
17
|
+
# this socket instance.
|
18
|
+
attr_reader :script
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
20
|
+
# Create a new test socket. This will also instantiate a new Net::SSH::Test::Script
|
21
|
+
# and seed it with the necessary events to power the initialization of the
|
22
|
+
# connection.
|
23
|
+
def initialize
|
24
|
+
extend(Net::SSH::Transport::PacketStream)
|
25
|
+
super "SSH-2.0-Test\r\n"
|
18
26
|
|
19
|
-
|
20
|
-
# and seed it with the necessary events to power the initialization of the
|
21
|
-
# connection.
|
22
|
-
def initialize
|
23
|
-
extend(Net::SSH::Transport::PacketStream)
|
24
|
-
super "SSH-2.0-Test\r\n"
|
27
|
+
@script = Script.new
|
25
28
|
|
26
|
-
|
29
|
+
script.sends(:kexinit)
|
30
|
+
script.gets(:kexinit, 1, 2, 3, 4, "test", "ssh-rsa", "none", "none", "none", "none", "none", "none", "", "", false)
|
31
|
+
script.sends(:newkeys)
|
32
|
+
script.gets(:newkeys)
|
33
|
+
end
|
27
34
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
35
|
+
# This doesn't actually do anything, since we don't really care what gets
|
36
|
+
# written.
|
37
|
+
def write(data)
|
38
|
+
# black hole, because we don't actually care about what gets written
|
39
|
+
end
|
33
40
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
41
|
+
# Allows the socket to also mimic a socket factory, simply returning
|
42
|
+
# +self+.
|
43
|
+
def open(host, port, options = {})
|
44
|
+
@host, @port = host, port
|
45
|
+
self
|
46
|
+
end
|
39
47
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
48
|
+
# Returns a sockaddr struct for the port and host that were used when the
|
49
|
+
# socket was instantiated.
|
50
|
+
def getpeername
|
51
|
+
::Socket.sockaddr_in(port, host)
|
52
|
+
end
|
46
53
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
54
|
+
# Alias to #read, but never returns nil (returns an empty string instead).
|
55
|
+
def recv(n)
|
56
|
+
read(n) || ""
|
57
|
+
end
|
52
58
|
|
53
|
-
|
54
|
-
|
55
|
-
|
59
|
+
def readpartial(n)
|
60
|
+
recv(n)
|
61
|
+
end
|
62
|
+
end
|
56
63
|
end
|
57
|
-
|
58
|
-
def readpartial(n)
|
59
|
-
recv(n)
|
60
|
-
end
|
61
|
-
|
62
64
|
end
|
63
|
-
|
64
|
-
end; end; end
|
65
|
+
end
|
data/lib/net/ssh/test.rb
CHANGED
@@ -3,87 +3,92 @@ require 'net/ssh/connection/session'
|
|
3
3
|
require 'net/ssh/test/kex'
|
4
4
|
require 'net/ssh/test/socket'
|
5
5
|
|
6
|
-
module Net
|
6
|
+
module Net
|
7
|
+
module SSH
|
8
|
+
# This module may be used in unit tests, for when you want to test that your
|
9
|
+
# SSH state machines are really doing what you expect they are doing. You will
|
10
|
+
# typically include this module in your unit test class, and then build a
|
11
|
+
# "story" of expected sends and receives:
|
12
|
+
#
|
13
|
+
# require 'minitest/autorun'
|
14
|
+
# require 'net/ssh/test'
|
15
|
+
#
|
16
|
+
# class MyTest < Minitest::Test
|
17
|
+
# include Net::SSH::Test
|
18
|
+
#
|
19
|
+
# def test_exec_via_channel_works
|
20
|
+
# story do |session|
|
21
|
+
# channel = session.opens_channel
|
22
|
+
# channel.sends_exec "ls"
|
23
|
+
# channel.gets_data "result of ls"
|
24
|
+
# channel.gets_close
|
25
|
+
# channel.sends_close
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# assert_scripted do
|
29
|
+
# result = nil
|
30
|
+
#
|
31
|
+
# connection.open_channel do |ch|
|
32
|
+
# ch.exec("ls") do |success|
|
33
|
+
# ch.on_data { |c, data| result = data }
|
34
|
+
# ch.on_close { |c| c.close }
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# connection.loop
|
39
|
+
# assert_equal "result of ls", result
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# See Net::SSH::Test::Channel and Net::SSH::Test::Script for more options.
|
45
|
+
#
|
46
|
+
# Note that the Net::SSH::Test system is rather finicky yet, and can be kind
|
47
|
+
# of frustrating to get working. Any suggestions for improvement will be
|
48
|
+
# welcome!
|
49
|
+
module Test
|
50
|
+
# If a block is given, yields the script for the test socket (#socket).
|
51
|
+
# Otherwise, simply returns the socket's script. See Net::SSH::Test::Script.
|
52
|
+
def story
|
53
|
+
Net::SSH::Test::Extensions::IO.with_test_extension { yield socket.script if block_given? }
|
54
|
+
return socket.script
|
55
|
+
end
|
7
56
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# require 'test/unit'
|
14
|
-
# require 'net/ssh/test'
|
15
|
-
#
|
16
|
-
# class MyTest < Test::Unit::TestCase
|
17
|
-
# include Net::SSH::Test
|
18
|
-
#
|
19
|
-
# def test_exec_via_channel_works
|
20
|
-
# story do |session|
|
21
|
-
# channel = session.opens_channel
|
22
|
-
# channel.sends_exec "ls"
|
23
|
-
# channel.gets_data "result of ls"
|
24
|
-
# channel.gets_close
|
25
|
-
# channel.sends_close
|
26
|
-
# end
|
27
|
-
#
|
28
|
-
# assert_scripted do
|
29
|
-
# result = nil
|
30
|
-
#
|
31
|
-
# connection.open_channel do |ch|
|
32
|
-
# ch.exec("ls") do |success|
|
33
|
-
# ch.on_data { |c, data| result = data }
|
34
|
-
# ch.on_close { |c| c.close }
|
35
|
-
# end
|
36
|
-
# end
|
37
|
-
#
|
38
|
-
# connection.loop
|
39
|
-
# assert_equal "result of ls", result
|
40
|
-
# end
|
41
|
-
# end
|
42
|
-
# end
|
43
|
-
#
|
44
|
-
# See Net::SSH::Test::Channel and Net::SSH::Test::Script for more options.
|
45
|
-
#
|
46
|
-
# Note that the Net::SSH::Test system is rather finicky yet, and can be kind
|
47
|
-
# of frustrating to get working. Any suggestions for improvement will be
|
48
|
-
# welcome!
|
49
|
-
module Test
|
50
|
-
# If a block is given, yields the script for the test socket (#socket).
|
51
|
-
# Otherwise, simply returns the socket's script. See Net::SSH::Test::Script.
|
52
|
-
def story
|
53
|
-
yield socket.script if block_given?
|
54
|
-
return socket.script
|
55
|
-
end
|
57
|
+
# Returns the test socket instance to use for these tests (see
|
58
|
+
# Net::SSH::Test::Socket).
|
59
|
+
def socket(options = {})
|
60
|
+
@socket ||= Net::SSH::Test::Socket.new
|
61
|
+
end
|
56
62
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
63
|
+
# Returns the connection session (Net::SSH::Connection::Session) for use
|
64
|
+
# in these tests. It is a fully functional SSH session, operating over
|
65
|
+
# a mock socket (#socket).
|
66
|
+
def connection(options = {})
|
67
|
+
@connection ||= Net::SSH::Connection::Session.new(transport(options), options)
|
68
|
+
end
|
62
69
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
70
|
+
# Returns the transport session (Net::SSH::Transport::Session) for use
|
71
|
+
# in these tests. It is a fully functional SSH transport session, operating
|
72
|
+
# over a mock socket (#socket).
|
73
|
+
def transport(options = {})
|
74
|
+
@transport ||= Net::SSH::Transport::Session.new(
|
75
|
+
options[:host] || "localhost",
|
76
|
+
options.merge(kex: "test", host_key: "ssh-rsa", append_all_supported_algorithms: true, verify_host_key: :never, proxy: socket(options))
|
77
|
+
)
|
78
|
+
end
|
69
79
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
80
|
+
# First asserts that a story has been described (see #story). Then yields,
|
81
|
+
# and then asserts that all items described in the script have been
|
82
|
+
# processed. Typically, this is called immediately after a story has
|
83
|
+
# been built, and the SSH commands being tested are then executed within
|
84
|
+
# the block passed to this assertion.
|
85
|
+
def assert_scripted
|
86
|
+
raise "there is no script to be processed" if socket.script.events.empty?
|
76
87
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
# the block passed to this assertion.
|
82
|
-
def assert_scripted
|
83
|
-
raise "there is no script to be processed" if socket.script.events.empty?
|
84
|
-
yield
|
85
|
-
assert socket.script.events.empty?, "there should not be any remaining scripted events, but there are still #{socket.script.events.length} pending"
|
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" \
|
90
|
+
"#{socket.script.events.length} pending"
|
91
|
+
end
|
86
92
|
end
|
87
93
|
end
|
88
|
-
|
89
|
-
end; end
|
94
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'net/ssh/transport/hmac/abstract'
|
2
|
+
require 'net/ssh/transport/gcm_cipher'
|
3
|
+
|
4
|
+
module Net::SSH::Transport
|
5
|
+
## Implements the aes128-gcm@openssh cipher
|
6
|
+
class AES128_GCM
|
7
|
+
extend ::Net::SSH::Transport::GCMCipher
|
8
|
+
|
9
|
+
## Implicit HMAC, do need to do anything
|
10
|
+
class ImplicitHMac < ::Net::SSH::Transport::HMAC::Abstract
|
11
|
+
def aead
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def key_length
|
16
|
+
16
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def implicit_mac
|
21
|
+
ImplicitHMac.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def algo_name
|
25
|
+
'aes-128-gcm'
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
'aes128-gcm@openssh.com'
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# --- RFC 5647 ---
|
34
|
+
# K_LEN AES key length 16 octets
|
35
|
+
#
|
36
|
+
def self.key_length
|
37
|
+
16
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|