net-ssh 4.2.0 → 7.0.1

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.
Files changed (126) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/config/rubocop_linter_action.yml +4 -0
  5. data/.github/workflows/ci-with-docker.yml +44 -0
  6. data/.github/workflows/ci.yml +87 -0
  7. data/.github/workflows/rubocop.yml +13 -0
  8. data/.gitignore +7 -0
  9. data/.rubocop.yml +19 -2
  10. data/.rubocop_todo.yml +619 -667
  11. data/CHANGES.txt +110 -1
  12. data/Dockerfile +27 -0
  13. data/Dockerfile.openssl3 +17 -0
  14. data/Gemfile +3 -7
  15. data/{Gemfile.norbnacl → Gemfile.noed25519} +3 -1
  16. data/Manifest +4 -5
  17. data/README.md +293 -0
  18. data/Rakefile +45 -29
  19. data/appveyor.yml +8 -6
  20. data/docker-compose.yml +23 -0
  21. data/lib/net/ssh/authentication/agent.rb +248 -223
  22. data/lib/net/ssh/authentication/certificate.rb +178 -164
  23. data/lib/net/ssh/authentication/constants.rb +17 -15
  24. data/lib/net/ssh/authentication/ed25519.rb +141 -116
  25. data/lib/net/ssh/authentication/ed25519_loader.rb +28 -28
  26. data/lib/net/ssh/authentication/key_manager.rb +79 -36
  27. data/lib/net/ssh/authentication/methods/abstract.rb +62 -47
  28. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  29. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +3 -3
  30. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  31. data/lib/net/ssh/authentication/methods/password.rb +15 -16
  32. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  33. data/lib/net/ssh/authentication/pageant.rb +468 -465
  34. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  35. data/lib/net/ssh/authentication/session.rb +131 -122
  36. data/lib/net/ssh/buffer.rb +385 -332
  37. data/lib/net/ssh/buffered_io.rb +150 -151
  38. data/lib/net/ssh/config.rb +316 -239
  39. data/lib/net/ssh/connection/channel.rb +635 -613
  40. data/lib/net/ssh/connection/constants.rb +29 -29
  41. data/lib/net/ssh/connection/event_loop.rb +104 -95
  42. data/lib/net/ssh/connection/keepalive.rb +55 -51
  43. data/lib/net/ssh/connection/session.rb +614 -611
  44. data/lib/net/ssh/connection/term.rb +125 -123
  45. data/lib/net/ssh/errors.rb +101 -99
  46. data/lib/net/ssh/key_factory.rb +194 -108
  47. data/lib/net/ssh/known_hosts.rb +212 -134
  48. data/lib/net/ssh/loggable.rb +50 -49
  49. data/lib/net/ssh/packet.rb +83 -79
  50. data/lib/net/ssh/prompt.rb +51 -51
  51. data/lib/net/ssh/proxy/command.rb +105 -91
  52. data/lib/net/ssh/proxy/errors.rb +12 -10
  53. data/lib/net/ssh/proxy/http.rb +81 -81
  54. data/lib/net/ssh/proxy/https.rb +37 -36
  55. data/lib/net/ssh/proxy/jump.rb +49 -48
  56. data/lib/net/ssh/proxy/socks4.rb +2 -6
  57. data/lib/net/ssh/proxy/socks5.rb +14 -17
  58. data/lib/net/ssh/service/forward.rb +365 -362
  59. data/lib/net/ssh/test/channel.rb +145 -143
  60. data/lib/net/ssh/test/extensions.rb +131 -127
  61. data/lib/net/ssh/test/kex.rb +34 -32
  62. data/lib/net/ssh/test/local_packet.rb +46 -44
  63. data/lib/net/ssh/test/packet.rb +87 -84
  64. data/lib/net/ssh/test/remote_packet.rb +32 -30
  65. data/lib/net/ssh/test/script.rb +155 -155
  66. data/lib/net/ssh/test/socket.rb +49 -48
  67. data/lib/net/ssh/test.rb +82 -80
  68. data/lib/net/ssh/transport/algorithms.rb +433 -364
  69. data/lib/net/ssh/transport/cipher_factory.rb +95 -91
  70. data/lib/net/ssh/transport/constants.rb +32 -24
  71. data/lib/net/ssh/transport/ctr.rb +37 -15
  72. data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
  73. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  74. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  75. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  76. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  77. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  78. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  79. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  80. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  81. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  82. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  83. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  84. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  85. data/lib/net/ssh/transport/hmac.rb +14 -12
  86. data/lib/net/ssh/transport/identity_cipher.rb +54 -52
  87. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  88. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  89. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  90. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  92. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  93. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +112 -217
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -63
  95. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  96. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  97. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  98. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  99. data/lib/net/ssh/transport/kex.rb +15 -12
  100. data/lib/net/ssh/transport/key_expander.rb +24 -21
  101. data/lib/net/ssh/transport/openssl.rb +158 -133
  102. data/lib/net/ssh/transport/packet_stream.rb +223 -191
  103. data/lib/net/ssh/transport/server_version.rb +55 -56
  104. data/lib/net/ssh/transport/session.rb +306 -259
  105. data/lib/net/ssh/transport/state.rb +178 -176
  106. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  107. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  108. data/lib/net/ssh/verifiers/always.rb +58 -0
  109. data/lib/net/ssh/verifiers/never.rb +19 -0
  110. data/lib/net/ssh/version.rb +55 -53
  111. data/lib/net/ssh.rb +47 -34
  112. data/net-ssh-public_cert.pem +18 -19
  113. data/net-ssh.gemspec +12 -11
  114. data/support/ssh_tunnel_bug.rb +5 -5
  115. data.tar.gz.sig +0 -0
  116. metadata +78 -73
  117. metadata.gz.sig +0 -0
  118. data/.travis.yml +0 -51
  119. data/Gemfile.norbnacl.lock +0 -41
  120. data/README.rdoc +0 -169
  121. data/lib/net/ssh/ruby_compat.rb +0 -24
  122. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  123. data/lib/net/ssh/verifiers/null.rb +0 -12
  124. data/lib/net/ssh/verifiers/secure.rb +0 -52
  125. data/lib/net/ssh/verifiers/strict.rb +0 -24
  126. data/support/arcfour_check.rb +0 -20
@@ -2,179 +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; module SSH; module Test
6
-
7
- # Represents a sequence of scripted events that identify the behavior that
8
- # a test expects. Methods named "sends_*" create events for packets being
9
- # sent from the local to the remote host, and methods named "gets_*" create
10
- # events for packets being received by the local from the remote host.
11
- #
12
- # A reference to a script. is generally obtained in a unit test via the
13
- # Net::SSH::Test#story helper method:
14
- #
15
- # story do |script|
16
- # channel = script.opens_channel
17
- # ...
18
- # end
19
- class Script
20
- # The list of scripted events. These will be Net::SSH::Test::LocalPacket
21
- # and Net::SSH::Test::RemotePacket instances.
22
- attr_reader :events
23
-
24
- # Create a new, empty script.
25
- def initialize
26
- @events = []
27
- end
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
- # Scripts the opening of a channel by adding a local packet sending the
30
- # channel open request, and if +confirm+ is true (the default), also
31
- # adding a remote packet confirming the new channel.
32
- #
33
- # A new Net::SSH::Test::Channel instance is returned, which can be used
34
- # to script additional channel operations.
35
- def opens_channel(confirm=true)
36
- channel = Channel.new(self)
37
- channel.remote_id = 5555
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
- events << LocalPacket.new(:channel_open) { |p| channel.local_id = p[:remote_id] }
40
+ events << LocalPacket.new(:channel_open) { |p| channel.local_id = p[:remote_id] }
40
41
 
41
- if confirm
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
- channel
46
- end
44
+ channel
45
+ end
47
46
 
48
- # A convenience method for adding an arbitrary local packet to the events
49
- # list.
50
- def sends(type, *args, &block)
51
- events << LocalPacket.new(type, *args, &block)
52
- end
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
- # A convenience method for adding an arbitrary remote packet to the events
55
- # list.
56
- def gets(type, *args)
57
- events << RemotePacket.new(type, *args)
58
- end
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
- # Scripts the sending of a new channel request packet to the remote host.
61
- # +channel+ should be an instance of Net::SSH::Test::Channel. +request+
62
- # is a string naming the request type to send, +reply+ is a boolean
63
- # indicating whether a response to this packet is required , and +data+
64
- # is any additional request-specific data that this packet should send.
65
- # +success+ indicates whether the response (if one is required) should be
66
- # success or failure. If +data+ is an array it will be treated as multiple
67
- # data.
68
- #
69
- # If a reply is desired, a remote packet will also be queued, :channel_success
70
- # if +success+ is true, or :channel_failure if +success+ is false.
71
- #
72
- # This will typically be called via Net::SSH::Test::Channel#sends_exec or
73
- # Net::SSH::Test::Channel#sends_subsystem.
74
- def sends_channel_request(channel, request, reply, data, success=true)
75
- if data.is_a? Array
76
- events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, *data)
77
- else
78
- events << LocalPacket.new(:channel_request, channel.remote_id, request, reply, data)
79
- end
80
- if reply
81
- if success
82
- events << RemotePacket.new(:channel_success, channel.local_id)
83
- else
84
- events << RemotePacket.new(:channel_failure, channel.local_id)
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
85
86
  end
86
- end
87
- end
88
87
 
89
- # Scripts the sending of a channel data packet. +channel+ must be a
90
- # Net::SSH::Test::Channel object, and +data+ is the (string) data to
91
- # expect will be sent.
92
- #
93
- # This will typically be called via Net::SSH::Test::Channel#sends_data.
94
- def sends_channel_data(channel, data)
95
- events << LocalPacket.new(:channel_data, channel.remote_id, data)
96
- end
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
97
96
 
98
- # Scripts the sending of a channel EOF packet from the given
99
- # Net::SSH::Test::Channel +channel+. This will typically be called via
100
- # Net::SSH::Test::Channel#sends_eof.
101
- def sends_channel_eof(channel)
102
- events << LocalPacket.new(:channel_eof, channel.remote_id)
103
- end
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
104
103
 
105
- # Scripts the sending of a channel close packet from the given
106
- # Net::SSH::Test::Channel +channel+. This will typically be called via
107
- # Net::SSH::Test::Channel#sends_close.
108
- def sends_channel_close(channel)
109
- events << LocalPacket.new(:channel_close, channel.remote_id)
110
- end
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
111
110
 
112
- # Scripts the sending of a channel request pty packets from the given
113
- # Net::SSH::Test::Channel +channel+. This will typically be called via
114
- # Net::SSH::Test::Channel#sends_request_pty.
115
- def sends_channel_request_pty(channel)
116
- data = ['pty-req', false]
117
- data += Net::SSH::Connection::Channel::VALID_PTY_OPTIONS.merge(modes: "\0").values
118
- events << LocalPacket.new(:channel_request, channel.remote_id, *data)
119
- end
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
120
119
 
121
- # Scripts the reception of a channel data packet from the remote host by
122
- # the given Net::SSH::Test::Channel +channel+. This will typically be
123
- # called via Net::SSH::Test::Channel#gets_data.
124
- def gets_channel_data(channel, data)
125
- events << RemotePacket.new(:channel_data, channel.local_id, data)
126
- 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
127
126
 
128
- # Scripts the reception of a channel extended data packet from the remote
129
- # host by the given Net::SSH::Test::Channel +channel+. This will typically
130
- # be called via Net::SSH::Test::Channel#gets_extended_data.
131
- #
132
- # Currently the only extended data type is stderr == 1.
133
- def gets_channel_extended_data(channel, data)
134
- events << RemotePacket.new(:channel_extended_data, channel.local_id, 1, data)
135
- end
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
136
135
 
137
- # Scripts the reception of a channel request packet from the remote host by
138
- # the given Net::SSH::Test::Channel +channel+. This will typically be
139
- # called via Net::SSH::Test::Channel#gets_exit_status.
140
- def gets_channel_request(channel, request, reply, data)
141
- events << RemotePacket.new(:channel_request, channel.local_id, request, reply, data)
142
- end
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
143
142
 
144
- # Scripts the reception of a channel EOF packet from the remote host by
145
- # the given Net::SSH::Test::Channel +channel+. This will typically be
146
- # called via Net::SSH::Test::Channel#gets_eof.
147
- def gets_channel_eof(channel)
148
- events << RemotePacket.new(:channel_eof, channel.local_id)
149
- end
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
150
149
 
151
- # Scripts the reception of a channel close packet from the remote host by
152
- # the given Net::SSH::Test::Channel +channel+. This will typically be
153
- # called via Net::SSH::Test::Channel#gets_close.
154
- def gets_channel_close(channel)
155
- events << RemotePacket.new(:channel_close, channel.local_id)
156
- end
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
157
156
 
158
- # By default, removes the next event in the list and returns it. However,
159
- # this can also be used to non-destructively peek at the next event in the
160
- # list, by passing :first as the argument.
161
- #
162
- # # remove the next event and return it
163
- # event = script.next
164
- #
165
- # # peek at the next event
166
- # event = script.next(:first)
167
- def next(mode=:shift)
168
- events.send(mode)
169
- end
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
170
169
 
171
- # Compare the given packet against the next event in the list. If there is
172
- # no next event, an exception will be raised. This is called by
173
- # Net::SSH::Test::Extensions::PacketStream#test_enqueue_packet.
174
- def process(packet)
175
- event = events.shift or raise "end of script reached, but got a packet type #{packet.read_byte}"
176
- event.process(packet)
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
177
178
  end
178
179
  end
179
-
180
- end; end; end
180
+ end
@@ -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; module SSH; module Test
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
- # A mock socket implementation for use in testing. It implements the minimum
9
- # necessary interface for interacting with the rest of the Net::SSH::Test
10
- # system.
11
- class Socket < StringIO
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
- # The Net::SSH::Test::Script object in use by this socket. This is the
15
- # canonical script instance that should be used for any test depending on
16
- # this socket instance.
17
- attr_reader :script
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
- # Create a new test socket. This will also instantiate a new Net::SSH::Test::Script
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
- @script = Script.new
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
- script.sends(:kexinit)
29
- script.gets(:kexinit, 1, 2, 3, 4, "test", "ssh-rsa", "none", "none", "none", "none", "none", "none", "", "", false)
30
- script.sends(:newkeys)
31
- script.gets(:newkeys)
32
- end
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
- # This doesn't actually do anything, since we don't really care what gets
35
- # written.
36
- def write(data)
37
- # black hole, because we don't actually care about what gets written
38
- end
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
- # Allows the socket to also mimic a socket factory, simply returning
41
- # +self+.
42
- def open(host, port, options={})
43
- @host, @port = host, port
44
- self
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
- # Returns a sockaddr struct for the port and host that were used when the
48
- # socket was instantiated.
49
- def getpeername
50
- ::Socket.sockaddr_in(port, host)
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
- # Alias to #read, but never returns nil (returns an empty string instead).
54
- def recv(n)
55
- read(n) || ""
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,90 +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; module SSH
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
- # 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
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
- # 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
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
- # 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
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
- # 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", verify_host_key: false, proxy: socket(options))
77
- )
78
- end
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?
79
87
 
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?
87
- Net::SSH::Test::Extensions::IO.with_test_extension { yield }
88
- 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
89
92
  end
90
93
  end
91
-
92
- end; end
94
+ end