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.
Files changed (199) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/FUNDING.yml +1 -0
  5. data/.github/config/rubocop_linter_action.yml +4 -0
  6. data/.github/workflows/ci-with-docker.yml +44 -0
  7. data/.github/workflows/ci.yml +94 -0
  8. data/.github/workflows/rubocop.yml +16 -0
  9. data/.gitignore +15 -0
  10. data/.rubocop.yml +22 -0
  11. data/.rubocop_todo.yml +1081 -0
  12. data/CHANGES.txt +387 -0
  13. data/DEVELOPMENT.md +23 -0
  14. data/Dockerfile +29 -0
  15. data/Dockerfile.openssl3 +17 -0
  16. data/Gemfile +13 -0
  17. data/Gemfile.noed25519 +12 -0
  18. data/Gemfile.norbnacl +12 -0
  19. data/ISSUE_TEMPLATE.md +30 -0
  20. data/Manifest +4 -5
  21. data/README.md +303 -0
  22. data/Rakefile +174 -40
  23. data/SECURITY.md +4 -0
  24. data/THANKS.txt +25 -0
  25. data/appveyor.yml +58 -0
  26. data/docker-compose.yml +25 -0
  27. data/lib/net/ssh/authentication/agent.rb +279 -18
  28. data/lib/net/ssh/authentication/certificate.rb +183 -0
  29. data/lib/net/ssh/authentication/constants.rb +17 -15
  30. data/lib/net/ssh/authentication/ed25519.rb +184 -0
  31. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  32. data/lib/net/ssh/authentication/key_manager.rb +125 -54
  33. data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
  34. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  35. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +19 -12
  36. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  37. data/lib/net/ssh/authentication/methods/password.rb +56 -19
  38. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  39. data/lib/net/ssh/authentication/pageant.rb +483 -246
  40. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  41. data/lib/net/ssh/authentication/session.rb +138 -120
  42. data/lib/net/ssh/buffer.rb +399 -300
  43. data/lib/net/ssh/buffered_io.rb +154 -150
  44. data/lib/net/ssh/config.rb +361 -166
  45. data/lib/net/ssh/connection/channel.rb +640 -596
  46. data/lib/net/ssh/connection/constants.rb +29 -29
  47. data/lib/net/ssh/connection/event_loop.rb +123 -0
  48. data/lib/net/ssh/connection/keepalive.rb +59 -0
  49. data/lib/net/ssh/connection/session.rb +628 -548
  50. data/lib/net/ssh/connection/term.rb +125 -123
  51. data/lib/net/ssh/errors.rb +101 -95
  52. data/lib/net/ssh/key_factory.rb +198 -100
  53. data/lib/net/ssh/known_hosts.rb +221 -98
  54. data/lib/net/ssh/loggable.rb +50 -49
  55. data/lib/net/ssh/packet.rb +83 -79
  56. data/lib/net/ssh/prompt.rb +50 -81
  57. data/lib/net/ssh/proxy/command.rb +108 -60
  58. data/lib/net/ssh/proxy/errors.rb +12 -10
  59. data/lib/net/ssh/proxy/http.rb +82 -78
  60. data/lib/net/ssh/proxy/https.rb +50 -0
  61. data/lib/net/ssh/proxy/jump.rb +54 -0
  62. data/lib/net/ssh/proxy/socks4.rb +5 -8
  63. data/lib/net/ssh/proxy/socks5.rb +18 -20
  64. data/lib/net/ssh/service/forward.rb +383 -255
  65. data/lib/net/ssh/test/channel.rb +145 -136
  66. data/lib/net/ssh/test/extensions.rb +131 -110
  67. data/lib/net/ssh/test/kex.rb +34 -32
  68. data/lib/net/ssh/test/local_packet.rb +46 -44
  69. data/lib/net/ssh/test/packet.rb +89 -70
  70. data/lib/net/ssh/test/remote_packet.rb +32 -30
  71. data/lib/net/ssh/test/script.rb +156 -142
  72. data/lib/net/ssh/test/socket.rb +49 -48
  73. data/lib/net/ssh/test.rb +82 -77
  74. data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
  75. data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
  76. data/lib/net/ssh/transport/algorithms.rb +472 -348
  77. data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  78. data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  79. data/lib/net/ssh/transport/cipher_factory.rb +124 -100
  80. data/lib/net/ssh/transport/constants.rb +32 -24
  81. data/lib/net/ssh/transport/ctr.rb +42 -22
  82. data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
  83. data/lib/net/ssh/transport/hmac/abstract.rb +97 -63
  84. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  85. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  86. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  87. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  88. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  89. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  90. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  91. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  92. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  93. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  94. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  95. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  96. data/lib/net/ssh/transport/hmac.rb +14 -12
  97. data/lib/net/ssh/transport/identity_cipher.rb +54 -44
  98. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  99. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  100. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  101. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  102. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  103. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  104. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
  105. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
  106. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  107. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  108. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  109. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  110. data/lib/net/ssh/transport/kex.rb +15 -12
  111. data/lib/net/ssh/transport/key_expander.rb +24 -20
  112. data/lib/net/ssh/transport/openssl.rb +161 -124
  113. data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  114. data/lib/net/ssh/transport/packet_stream.rb +246 -183
  115. data/lib/net/ssh/transport/server_version.rb +57 -51
  116. data/lib/net/ssh/transport/session.rb +307 -235
  117. data/lib/net/ssh/transport/state.rb +178 -176
  118. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  119. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  120. data/lib/net/ssh/verifiers/always.rb +58 -0
  121. data/lib/net/ssh/verifiers/never.rb +19 -0
  122. data/lib/net/ssh/version.rb +57 -51
  123. data/lib/net/ssh.rb +140 -40
  124. data/net-ssh-public_cert.pem +21 -0
  125. data/net-ssh.gemspec +39 -184
  126. data/support/ssh_tunnel_bug.rb +5 -5
  127. data.tar.gz.sig +0 -0
  128. metadata +205 -99
  129. metadata.gz.sig +0 -0
  130. data/README.rdoc +0 -219
  131. data/Rudyfile +0 -96
  132. data/gem-public_cert.pem +0 -20
  133. data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
  134. data/lib/net/ssh/authentication/agent/socket.rb +0 -170
  135. data/lib/net/ssh/ruby_compat.rb +0 -51
  136. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  137. data/lib/net/ssh/verifiers/null.rb +0 -12
  138. data/lib/net/ssh/verifiers/secure.rb +0 -54
  139. data/lib/net/ssh/verifiers/strict.rb +0 -24
  140. data/setup.rb +0 -1585
  141. data/support/arcfour_check.rb +0 -20
  142. data/test/README.txt +0 -47
  143. data/test/authentication/methods/common.rb +0 -28
  144. data/test/authentication/methods/test_abstract.rb +0 -51
  145. data/test/authentication/methods/test_hostbased.rb +0 -114
  146. data/test/authentication/methods/test_keyboard_interactive.rb +0 -100
  147. data/test/authentication/methods/test_none.rb +0 -41
  148. data/test/authentication/methods/test_password.rb +0 -52
  149. data/test/authentication/methods/test_publickey.rb +0 -148
  150. data/test/authentication/test_agent.rb +0 -205
  151. data/test/authentication/test_key_manager.rb +0 -218
  152. data/test/authentication/test_session.rb +0 -108
  153. data/test/common.rb +0 -108
  154. data/test/configs/eqsign +0 -3
  155. data/test/configs/exact_match +0 -8
  156. data/test/configs/host_plus +0 -10
  157. data/test/configs/multihost +0 -4
  158. data/test/configs/nohost +0 -19
  159. data/test/configs/numeric_host +0 -4
  160. data/test/configs/send_env +0 -2
  161. data/test/configs/substitutes +0 -8
  162. data/test/configs/wild_cards +0 -14
  163. data/test/connection/test_channel.rb +0 -467
  164. data/test/connection/test_session.rb +0 -526
  165. data/test/known_hosts/github +0 -1
  166. data/test/manual/test_forward.rb +0 -223
  167. data/test/start/test_options.rb +0 -36
  168. data/test/start/test_transport.rb +0 -28
  169. data/test/test_all.rb +0 -11
  170. data/test/test_buffer.rb +0 -433
  171. data/test/test_buffered_io.rb +0 -63
  172. data/test/test_config.rb +0 -151
  173. data/test/test_key_factory.rb +0 -173
  174. data/test/test_known_hosts.rb +0 -13
  175. data/test/transport/hmac/test_md5.rb +0 -41
  176. data/test/transport/hmac/test_md5_96.rb +0 -27
  177. data/test/transport/hmac/test_none.rb +0 -34
  178. data/test/transport/hmac/test_ripemd160.rb +0 -36
  179. data/test/transport/hmac/test_sha1.rb +0 -36
  180. data/test/transport/hmac/test_sha1_96.rb +0 -27
  181. data/test/transport/hmac/test_sha2_256.rb +0 -37
  182. data/test/transport/hmac/test_sha2_256_96.rb +0 -27
  183. data/test/transport/hmac/test_sha2_512.rb +0 -37
  184. data/test/transport/hmac/test_sha2_512_96.rb +0 -27
  185. data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
  186. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -146
  187. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -92
  188. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -34
  189. data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
  190. data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
  191. data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
  192. data/test/transport/test_algorithms.rb +0 -330
  193. data/test/transport/test_cipher_factory.rb +0 -443
  194. data/test/transport/test_hmac.rb +0 -34
  195. data/test/transport/test_identity_cipher.rb +0 -40
  196. data/test/transport/test_packet_stream.rb +0 -1755
  197. data/test/transport/test_server_version.rb +0 -78
  198. data/test/transport/test_session.rb +0 -319
  199. data/test/transport/test_state.rb +0 -181
@@ -1,138 +1,147 @@
1
- module Net; module SSH; module Test
2
-
3
- # A mock channel, used for scripting actions in tests. It wraps a
4
- # Net::SSH::Test::Script instance, and delegates to it for the most part.
5
- # This class has little real functionality on its own, but rather acts as
6
- # a convenience for scripting channel-related activity for later comparison
7
- # in a unit test.
8
- #
9
- # story do |session|
10
- # channel = session.opens_channel
11
- # channel.sends_exec "ls"
12
- # channel.gets_data "result of ls"
13
- # channel.gets_extended_data "some error coming from ls"
14
- # channel.gets_close
15
- # channel.sends_close
16
- # end
17
- class Channel
18
- # The Net::SSH::Test::Script instance employed by this mock channel.
19
- attr_reader :script
20
-
21
- # Sets the local-id of this channel object (the id assigned by the client).
22
- attr_writer :local_id
23
-
24
- # Sets the remote-id of this channel object (the id assigned by the mock-server).
25
- attr_writer :remote_id
26
-
27
- # Creates a new Test::Channel instance on top of the given +script+ (which
28
- # must be a Net::SSH::Test::Script instance).
29
- def initialize(script)
30
- @script = script
31
- @local_id = @remote_id = nil
32
- end
33
-
34
- # Returns the local (client-assigned) id for this channel, or a Proc object
35
- # that will return the local-id later if the local id has not yet been set.
36
- # (See Net::SSH::Test::Packet#instantiate!.)
37
- def local_id
38
- @local_id || Proc.new { @local_id or raise "local-id has not been set yet!" }
39
- end
40
-
41
- # Returns the remote (server-assigned) id for this channel, or a Proc object
42
- # that will return the remote-id later if the remote id has not yet been set.
43
- # (See Net::SSH::Test::Packet#instantiate!.)
44
- def remote_id
45
- @remote_id || Proc.new { @remote_id or raise "remote-id has not been set yet!" }
46
- end
47
-
48
- # Because adjacent calls to #gets_data will sometimes cause the data packets
49
- # to be concatenated (causing expectations in tests to fail), you may
50
- # need to separate those calls with calls to #inject_remote_delay! (which
51
- # essentially just mimics receiving an empty data packet):
52
- #
53
- # channel.gets_data "abcdefg"
54
- # channel.inject_remote_delay!
55
- # channel.gets_data "hijklmn"
56
- def inject_remote_delay!
57
- gets_data("")
58
- end
59
-
60
- # Scripts the sending of an "exec" channel request packet to the mock
61
- # server. If +reply+ is true, then the server is expected to reply to the
62
- # request, otherwise no response to this request will be sent. If +success+
63
- # is +true+, then the request will be successful, otherwise a failure will
64
- # be scripted.
65
- #
66
- # channel.sends_exec "ls -l"
67
- def sends_exec(command, reply=true, success=true)
68
- script.sends_channel_request(self, "exec", reply, command, success)
69
- end
70
-
71
- # Scripts the sending of a "subsystem" channel request packet to the mock
72
- # server. See #sends_exec for a discussion of the meaning of the +reply+
73
- # and +success+ arguments.
74
- #
75
- # channel.sends_subsystem "sftp"
76
- def sends_subsystem(subsystem, reply=true, success=true)
77
- script.sends_channel_request(self, "subsystem", reply, subsystem, success)
78
- end
79
-
80
- # Scripts the sending of a data packet across the channel.
81
- #
82
- # channel.sends_data "foo"
83
- def sends_data(data)
84
- script.sends_channel_data(self, data)
85
- end
86
-
87
- # Scripts the sending of an EOF packet across the channel.
88
- #
89
- # channel.sends_eof
90
- def sends_eof
91
- script.sends_channel_eof(self)
92
- end
93
-
94
- # Scripts the sending of a "channel close" packet across the channel.
95
- #
96
- # channel.sends_close
97
- def sends_close
98
- script.sends_channel_close(self)
99
- end
100
-
101
- # Scripts the reception of a channel data packet from the remote end.
102
- #
103
- # channel.gets_data "bar"
104
- def gets_data(data)
105
- script.gets_channel_data(self, data)
106
- end
107
-
108
- # Scripts the reception of a channel extended data packet from the remote
109
- # end.
110
- #
111
- # channel.gets_extended_data "whoops"
112
- def gets_extended_data(data)
113
- script.gets_channel_extended_data(self, data)
114
- end
115
-
116
- # Scripts the reception of an "exit-status" channel request packet.
117
- #
118
- # channel.gets_exit_status(127)
119
- def gets_exit_status(status=0)
120
- script.gets_channel_request(self, "exit-status", false, status)
121
- end
122
-
123
- # Scripts the reception of an EOF packet from the remote end.
124
- #
125
- # channel.gets_eof
126
- def gets_eof
127
- script.gets_channel_eof(self)
128
- end
129
-
130
- # Scripts the reception of a "channel close" packet from the remote end.
131
- #
132
- # channel.gets_close
133
- def gets_close
134
- script.gets_channel_close(self)
1
+ module Net
2
+ module SSH
3
+ module Test
4
+ # A mock channel, used for scripting actions in tests. It wraps a
5
+ # Net::SSH::Test::Script instance, and delegates to it for the most part.
6
+ # This class has little real functionality on its own, but rather acts as
7
+ # a convenience for scripting channel-related activity for later comparison
8
+ # in a unit test.
9
+ #
10
+ # story do |session|
11
+ # channel = session.opens_channel
12
+ # channel.sends_exec "ls"
13
+ # channel.gets_data "result of ls"
14
+ # channel.gets_extended_data "some error coming from ls"
15
+ # channel.gets_close
16
+ # channel.sends_close
17
+ # end
18
+ class Channel
19
+ # The Net::SSH::Test::Script instance employed by this mock channel.
20
+ attr_reader :script
21
+
22
+ # Sets the local-id of this channel object (the id assigned by the client).
23
+ attr_writer :local_id
24
+
25
+ # Sets the remote-id of this channel object (the id assigned by the mock-server).
26
+ attr_writer :remote_id
27
+
28
+ # Creates a new Test::Channel instance on top of the given +script+ (which
29
+ # must be a Net::SSH::Test::Script instance).
30
+ def initialize(script)
31
+ @script = script
32
+ @local_id = @remote_id = nil
33
+ end
34
+
35
+ # Returns the local (client-assigned) id for this channel, or a Proc object
36
+ # that will return the local-id later if the local id has not yet been set.
37
+ # (See Net::SSH::Test::Packet#instantiate!.)
38
+ def local_id
39
+ @local_id || Proc.new { @local_id or raise "local-id has not been set yet!" }
40
+ end
41
+
42
+ # Returns the remote (server-assigned) id for this channel, or a Proc object
43
+ # that will return the remote-id later if the remote id has not yet been set.
44
+ # (See Net::SSH::Test::Packet#instantiate!.)
45
+ def remote_id
46
+ @remote_id || Proc.new { @remote_id or raise "remote-id has not been set yet!" }
47
+ end
48
+
49
+ # Because adjacent calls to #gets_data will sometimes cause the data packets
50
+ # to be concatenated (causing expectations in tests to fail), you may
51
+ # need to separate those calls with calls to #inject_remote_delay! (which
52
+ # essentially just mimics receiving an empty data packet):
53
+ #
54
+ # channel.gets_data "abcdefg"
55
+ # channel.inject_remote_delay!
56
+ # channel.gets_data "hijklmn"
57
+ def inject_remote_delay!
58
+ gets_data("")
59
+ end
60
+
61
+ # Scripts the sending of an "exec" channel request packet to the mock
62
+ # server. If +reply+ is true, then the server is expected to reply to the
63
+ # request, otherwise no response to this request will be sent. If +success+
64
+ # is +true+, then the request will be successful, otherwise a failure will
65
+ # be scripted.
66
+ #
67
+ # channel.sends_exec "ls -l"
68
+ def sends_exec(command, reply = true, success = true)
69
+ script.sends_channel_request(self, "exec", reply, command, success)
70
+ end
71
+
72
+ # Scripts the sending of a "subsystem" channel request packet to the mock
73
+ # server. See #sends_exec for a discussion of the meaning of the +reply+
74
+ # and +success+ arguments.
75
+ #
76
+ # channel.sends_subsystem "sftp"
77
+ def sends_subsystem(subsystem, reply = true, success = true)
78
+ script.sends_channel_request(self, "subsystem", reply, subsystem, success)
79
+ end
80
+
81
+ # Scripts the sending of a data packet across the channel.
82
+ #
83
+ # channel.sends_data "foo"
84
+ def sends_data(data)
85
+ script.sends_channel_data(self, data)
86
+ end
87
+
88
+ # Scripts the sending of an EOF packet across the channel.
89
+ #
90
+ # channel.sends_eof
91
+ def sends_eof
92
+ script.sends_channel_eof(self)
93
+ end
94
+
95
+ # Scripts the sending of a "channel close" packet across the channel.
96
+ #
97
+ # channel.sends_close
98
+ def sends_close
99
+ script.sends_channel_close(self)
100
+ end
101
+
102
+ # Scripts the sending of a "request pty" request packet across the channel.
103
+ #
104
+ # channel.sends_request_pty
105
+ def sends_request_pty
106
+ script.sends_channel_request_pty(self)
107
+ end
108
+
109
+ # Scripts the reception of a channel data packet from the remote end.
110
+ #
111
+ # channel.gets_data "bar"
112
+ def gets_data(data)
113
+ script.gets_channel_data(self, data)
114
+ end
115
+
116
+ # Scripts the reception of a channel extended data packet from the remote
117
+ # end.
118
+ #
119
+ # channel.gets_extended_data "whoops"
120
+ def gets_extended_data(data)
121
+ script.gets_channel_extended_data(self, data)
122
+ end
123
+
124
+ # Scripts the reception of an "exit-status" channel request packet.
125
+ #
126
+ # channel.gets_exit_status(127)
127
+ def gets_exit_status(status = 0)
128
+ script.gets_channel_request(self, "exit-status", false, status)
129
+ end
130
+
131
+ # Scripts the reception of an EOF packet from the remote end.
132
+ #
133
+ # channel.gets_eof
134
+ def gets_eof
135
+ script.gets_channel_eof(self)
136
+ end
137
+
138
+ # Scripts the reception of a "channel close" packet from the remote end.
139
+ #
140
+ # channel.gets_close
141
+ def gets_close
142
+ script.gets_channel_close(self)
143
+ end
144
+ end
135
145
  end
136
146
  end
137
-
138
- end; end; end
147
+ end
@@ -6,145 +6,166 @@ 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; module SSH; module Test
10
-
11
- # A collection of modules used to extend/override the default behavior of
12
- # Net::SSH internals for ease of testing. As a consumer of Net::SSH, you'll
13
- # never need to use this directly--they're all used under the covers by
14
- # the Net::SSH::Test system.
15
- module Extensions
16
-
17
- # An extension to Net::SSH::BufferedIo (assumes that the underlying IO
18
- # is actually a StringIO). Facilitates unit testing.
19
- module BufferedIo
20
- # Returns +true+ if the position in the stream is less than the total
21
- # length of the stream.
22
- def select_for_read?
23
- pos < size
24
- end
9
+ module Net
10
+ module SSH
11
+ module Test
12
+ # A collection of modules used to extend/override the default behavior of
13
+ # Net::SSH internals for ease of testing. As a consumer of Net::SSH, you'll
14
+ # never need to use this directly--they're all used under the covers by
15
+ # the Net::SSH::Test system.
16
+ module Extensions
17
+ # An extension to Net::SSH::BufferedIo (assumes that the underlying IO
18
+ # is actually a StringIO). Facilitates unit testing.
19
+ module BufferedIo
20
+ # Returns +true+ if the position in the stream is less than the total
21
+ # length of the stream.
22
+ def select_for_read?
23
+ pos < size
24
+ end
25
25
 
26
- # Set this to +true+ if you want the IO to pretend to be available for writing
27
- attr_accessor :select_for_write
26
+ # Set this to +true+ if you want the IO to pretend to be available for writing
27
+ attr_accessor :select_for_write
28
28
 
29
- # Set this to +true+ if you want the IO to pretend to be in an error state
30
- attr_accessor :select_for_error
29
+ # Set this to +true+ if you want the IO to pretend to be in an error state
30
+ attr_accessor :select_for_error
31
31
 
32
- alias select_for_write? select_for_write
33
- alias select_for_error? select_for_error
34
- end
32
+ alias select_for_write? select_for_write
33
+ alias select_for_error? select_for_error
34
+ end
35
35
 
36
- # An extension to Net::SSH::Transport::PacketStream (assumes that the
37
- # underlying IO is actually a StringIO). Facilitates unit testing.
38
- module PacketStream
39
- include BufferedIo # make sure we get the extensions here, too
36
+ # An extension to Net::SSH::Transport::PacketStream (assumes that the
37
+ # underlying IO is actually a StringIO). Facilitates unit testing.
38
+ module PacketStream
39
+ include BufferedIo # make sure we get the extensions here, too
40
40
 
41
- def self.included(base) #:nodoc:
42
- base.send :alias_method, :real_available_for_read?, :available_for_read?
43
- base.send :alias_method, :available_for_read?, :test_available_for_read?
41
+ def self.included(base) # :nodoc:
42
+ base.send :alias_method, :real_available_for_read?, :available_for_read?
43
+ base.send :alias_method, :available_for_read?, :test_available_for_read?
44
44
 
45
- base.send :alias_method, :real_enqueue_packet, :enqueue_packet
46
- base.send :alias_method, :enqueue_packet, :test_enqueue_packet
45
+ base.send :alias_method, :real_enqueue_packet, :enqueue_packet
46
+ base.send :alias_method, :enqueue_packet, :test_enqueue_packet
47
47
 
48
- base.send :alias_method, :real_poll_next_packet, :poll_next_packet
49
- base.send :alias_method, :poll_next_packet, :test_poll_next_packet
50
- end
48
+ base.send :alias_method, :real_poll_next_packet, :poll_next_packet
49
+ base.send :alias_method, :poll_next_packet, :test_poll_next_packet
50
+ end
51
51
 
52
- # Called when another packet should be inspected from the current
53
- # script. If the next packet is a remote packet, it pops it off the
54
- # script and shoves it onto this IO object, making it available to
55
- # be read.
56
- def idle!
57
- return false unless script.next(:first)
52
+ # Called when another packet should be inspected from the current
53
+ # script. If the next packet is a remote packet, it pops it off the
54
+ # script and shoves it onto this IO object, making it available to
55
+ # be read.
56
+ def idle!
57
+ return false unless script.next(:first)
58
58
 
59
- if script.next(:first).remote?
60
- self.string << script.next.to_s
61
- self.pos = pos
62
- end
59
+ if script.next(:first).remote?
60
+ self.string << script.next.to_s
61
+ self.pos = pos
62
+ end
63
63
 
64
- return true
65
- end
64
+ return true
65
+ end
66
66
 
67
- # The testing version of Net::SSH::Transport::PacketStream#available_for_read?.
68
- # Returns true if there is data pending to be read. Otherwise calls #idle!.
69
- def test_available_for_read?
70
- return true if select_for_read?
71
- idle!
72
- false
73
- end
67
+ # The testing version of Net::SSH::Transport::PacketStream#available_for_read?.
68
+ # Returns true if there is data pending to be read. Otherwise calls #idle!.
69
+ def test_available_for_read?
70
+ return true if select_for_read?
74
71
 
75
- # The testing version of Net::SSH::Transport::PacketStream#enqueued_packet.
76
- # Simply calls Net::SSH::Test::Script#process on the packet.
77
- def test_enqueue_packet(payload)
78
- packet = Net::SSH::Buffer.new(payload.to_s)
79
- script.process(packet)
80
- end
72
+ idle!
73
+ false
74
+ end
81
75
 
82
- # The testing version of Net::SSH::Transport::PacketStream#poll_next_packet.
83
- # Reads the next available packet from the IO object and returns it.
84
- def test_poll_next_packet
85
- return nil if available <= 0
86
- packet = Net::SSH::Buffer.new(read_available(4))
87
- length = packet.read_long
88
- Net::SSH::Packet.new(read_available(length))
89
- end
90
- end
76
+ # The testing version of Net::SSH::Transport::PacketStream#enqueued_packet.
77
+ # Simply calls Net::SSH::Test::Script#process on the packet.
78
+ def test_enqueue_packet(payload)
79
+ packet = Net::SSH::Buffer.new(payload.to_s)
80
+ script.process(packet)
81
+ end
91
82
 
92
- # An extension to Net::SSH::Connection::Channel. Facilitates unit testing.
93
- module Channel
94
- def self.included(base) #:nodoc:
95
- base.send :alias_method, :send_data_for_real, :send_data
96
- base.send :alias_method, :send_data, :send_data_for_test
97
- end
83
+ # The testing version of Net::SSH::Transport::PacketStream#poll_next_packet.
84
+ # Reads the next available packet from the IO object and returns it.
85
+ def test_poll_next_packet
86
+ return nil if available <= 0
98
87
 
99
- # The testing version of Net::SSH::Connection::Channel#send_data. Calls
100
- # the original implementation, and then immediately enqueues the data for
101
- # output so that scripted sends are properly interpreted as discrete
102
- # (rather than concatenated) data packets.
103
- def send_data_for_test(data)
104
- send_data_for_real(data)
105
- enqueue_pending_output
106
- end
107
- end
88
+ packet = Net::SSH::Buffer.new(read_available(4))
89
+ length = packet.read_long
90
+ Net::SSH::Packet.new(read_available(length))
91
+ end
92
+ end
108
93
 
109
- # An extension to the built-in ::IO class. Simply redefines IO.select
110
- # so that it can be scripted in Net::SSH unit tests.
111
- module IO
112
- def self.included(base) #:nodoc:
113
- base.extend(ClassMethods)
114
- end
94
+ # An extension to Net::SSH::Connection::Channel. Facilitates unit testing.
95
+ module Channel
96
+ def self.included(base) # :nodoc:
97
+ base.send :alias_method, :send_data_for_real, :send_data
98
+ base.send :alias_method, :send_data, :send_data_for_test
99
+ end
115
100
 
116
- module ClassMethods
117
- def self.extended(obj) #:nodoc:
118
- class <<obj
119
- alias_method :select_for_real, :select
120
- alias_method :select, :select_for_test
101
+ # The testing version of Net::SSH::Connection::Channel#send_data. Calls
102
+ # the original implementation, and then immediately enqueues the data for
103
+ # output so that scripted sends are properly interpreted as discrete
104
+ # (rather than concatenated) data packets.
105
+ def send_data_for_test(data)
106
+ send_data_for_real(data)
107
+ enqueue_pending_output
121
108
  end
122
109
  end
123
110
 
124
- # The testing version of ::IO.select. Assumes that all readers,
125
- # writers, and errors arrays are either nil, or contain only objects
126
- # that mix in Net::SSH::Test::Extensions::BufferedIo.
127
- def select_for_test(readers=nil, writers=nil, errors=nil, wait=nil)
128
- ready_readers = Array(readers).select { |r| r.select_for_read? }
129
- ready_writers = Array(writers).select { |r| r.select_for_write? }
130
- ready_errors = Array(errors).select { |r| r.select_for_error? }
111
+ # An extension to the built-in ::IO class. Simply redefines IO.select
112
+ # so that it can be scripted in Net::SSH unit tests.
113
+ module IO
114
+ def self.included(base) # :nodoc:
115
+ base.extend(ClassMethods)
116
+ end
117
+
118
+ @extension_enabled = false
131
119
 
132
- if ready_readers.any? || ready_writers.any? || ready_errors.any?
133
- return [ready_readers, ready_writers, ready_errors]
120
+ def self.with_test_extension(&block)
121
+ orig_value = @extension_enabled
122
+ @extension_enabled = true
123
+ begin
124
+ yield
125
+ ensure
126
+ @extension_enabled = orig_value
127
+ end
134
128
  end
135
129
 
136
- processed = 0
137
- Array(readers).each do |reader|
138
- processed += 1 if reader.idle!
130
+ def self.extension_enabled?
131
+ @extension_enabled
139
132
  end
140
133
 
141
- raise "no readers were ready for reading, and none had any incoming packets" if processed == 0
134
+ module ClassMethods
135
+ def self.extended(obj) # :nodoc:
136
+ class << obj
137
+ alias_method :select_for_real, :select
138
+ alias_method :select, :select_for_test
139
+ end
140
+ end
141
+
142
+ # The testing version of ::IO.select. Assumes that all readers,
143
+ # writers, and errors arrays are either nil, or contain only objects
144
+ # that mix in Net::SSH::Test::Extensions::BufferedIo.
145
+ def select_for_test(readers = nil, writers = nil, errors = nil, wait = nil)
146
+ return select_for_real(readers, writers, errors, wait) unless Net::SSH::Test::Extensions::IO.extension_enabled?
147
+
148
+ ready_readers = Array(readers).select { |r| r.select_for_read? }
149
+ ready_writers = Array(writers).select { |r| r.select_for_write? }
150
+ ready_errors = Array(errors).select { |r| r.select_for_error? }
151
+
152
+ return [ready_readers, ready_writers, ready_errors] if ready_readers.any? || ready_writers.any? || ready_errors.any?
153
+
154
+ processed = 0
155
+ Array(readers).each do |reader|
156
+ processed += 1 if reader.idle!
157
+ end
158
+
159
+ raise "no readers were ready for reading, and none had any incoming packets" if processed == 0 && wait != 0
160
+
161
+ [[], [], []]
162
+ end
163
+ end
142
164
  end
143
165
  end
144
166
  end
145
167
  end
146
-
147
- end; end; end
168
+ end
148
169
 
149
170
  Net::SSH::BufferedIo.send(:include, Net::SSH::Test::Extensions::BufferedIo)
150
171
  Net::SSH::Transport::PacketStream.send(:include, Net::SSH::Test::Extensions::PacketStream)
@@ -5,40 +5,42 @@ require 'net/ssh/transport/algorithms'
5
5
  require 'net/ssh/transport/constants'
6
6
  require 'net/ssh/transport/kex'
7
7
 
8
- module Net; module SSH; module Test
9
-
10
- # An implementation of a key-exchange strategy specifically for unit tests.
11
- # (This strategy would never really work against a real SSH server--it makes
12
- # too many assumptions about the server's response.)
13
- #
14
- # This registers itself with the transport key-exchange system as the
15
- # "test" algorithm.
16
- class Kex
17
- include Net::SSH::Transport::Constants
18
-
19
- # Creates a new instance of the testing key-exchange algorithm with the
20
- # given arguments.
21
- def initialize(algorithms, connection, data)
22
- @connection = connection
23
- end
24
-
25
- # Exchange keys with the server. This returns a hash of constant values,
26
- # and does not actually exchange keys.
27
- def exchange_keys
28
- result = Net::SSH::Buffer.from(:byte, NEWKEYS)
29
- @connection.send_message(result)
30
-
31
- buffer = @connection.next_message
32
- raise Net::SSH::Exception, "expected NEWKEYS" unless buffer.type == NEWKEYS
33
-
34
- { :session_id => "abc-xyz",
35
- :server_key => OpenSSL::PKey::RSA.new(512),
36
- :shared_secret => OpenSSL::BN.new("1234567890", 10),
37
- :hashing_algorithm => OpenSSL::Digest::SHA1 }
8
+ module Net
9
+ module SSH
10
+ module Test
11
+ # An implementation of a key-exchange strategy specifically for unit tests.
12
+ # (This strategy would never really work against a real SSH server--it makes
13
+ # too many assumptions about the server's response.)
14
+ #
15
+ # This registers itself with the transport key-exchange system as the
16
+ # "test" algorithm.
17
+ class Kex
18
+ include Net::SSH::Transport::Constants
19
+
20
+ # Creates a new instance of the testing key-exchange algorithm with the
21
+ # given arguments.
22
+ def initialize(algorithms, connection, data)
23
+ @connection = connection
24
+ end
25
+
26
+ # Exchange keys with the server. This returns a hash of constant values,
27
+ # and does not actually exchange keys.
28
+ def exchange_keys
29
+ result = Net::SSH::Buffer.from(:byte, NEWKEYS)
30
+ @connection.send_message(result)
31
+
32
+ buffer = @connection.next_message
33
+ raise Net::SSH::Exception, "expected NEWKEYS" unless buffer.type == NEWKEYS
34
+
35
+ { session_id: "abc-xyz",
36
+ server_key: OpenSSL::PKey::RSA.new(512),
37
+ shared_secret: OpenSSL::BN.new("1234567890", 10),
38
+ hashing_algorithm: OpenSSL::Digest::SHA1 }
39
+ end
40
+ end
38
41
  end
39
42
  end
40
-
41
- end; end; end
43
+ end
42
44
 
43
45
  Net::SSH::Transport::Algorithms::ALGORITHMS[:kex] << "test"
44
46
  Net::SSH::Transport::Kex::MAP["test"] = Net::SSH::Test::Kex