sonixlabs-net-ssh 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/CHANGELOG.rdoc +262 -0
  2. data/Manifest +121 -0
  3. data/README.rdoc +184 -0
  4. data/Rakefile +86 -0
  5. data/Rudyfile +96 -0
  6. data/THANKS.rdoc +19 -0
  7. data/lib/net/ssh.rb +223 -0
  8. data/lib/net/ssh/authentication/agent.rb +179 -0
  9. data/lib/net/ssh/authentication/constants.rb +18 -0
  10. data/lib/net/ssh/authentication/key_manager.rb +253 -0
  11. data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
  12. data/lib/net/ssh/authentication/methods/hostbased.rb +75 -0
  13. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +70 -0
  14. data/lib/net/ssh/authentication/methods/password.rb +43 -0
  15. data/lib/net/ssh/authentication/methods/publickey.rb +96 -0
  16. data/lib/net/ssh/authentication/pageant.rb +264 -0
  17. data/lib/net/ssh/authentication/session.rb +146 -0
  18. data/lib/net/ssh/buffer.rb +340 -0
  19. data/lib/net/ssh/buffered_io.rb +198 -0
  20. data/lib/net/ssh/config.rb +207 -0
  21. data/lib/net/ssh/connection/channel.rb +630 -0
  22. data/lib/net/ssh/connection/constants.rb +33 -0
  23. data/lib/net/ssh/connection/session.rb +597 -0
  24. data/lib/net/ssh/connection/term.rb +178 -0
  25. data/lib/net/ssh/errors.rb +88 -0
  26. data/lib/net/ssh/key_factory.rb +102 -0
  27. data/lib/net/ssh/known_hosts.rb +129 -0
  28. data/lib/net/ssh/loggable.rb +61 -0
  29. data/lib/net/ssh/packet.rb +102 -0
  30. data/lib/net/ssh/prompt.rb +93 -0
  31. data/lib/net/ssh/proxy/command.rb +75 -0
  32. data/lib/net/ssh/proxy/errors.rb +14 -0
  33. data/lib/net/ssh/proxy/http.rb +94 -0
  34. data/lib/net/ssh/proxy/socks4.rb +70 -0
  35. data/lib/net/ssh/proxy/socks5.rb +142 -0
  36. data/lib/net/ssh/ruby_compat.rb +43 -0
  37. data/lib/net/ssh/service/forward.rb +298 -0
  38. data/lib/net/ssh/test.rb +89 -0
  39. data/lib/net/ssh/test/channel.rb +129 -0
  40. data/lib/net/ssh/test/extensions.rb +152 -0
  41. data/lib/net/ssh/test/kex.rb +44 -0
  42. data/lib/net/ssh/test/local_packet.rb +51 -0
  43. data/lib/net/ssh/test/packet.rb +81 -0
  44. data/lib/net/ssh/test/remote_packet.rb +38 -0
  45. data/lib/net/ssh/test/script.rb +157 -0
  46. data/lib/net/ssh/test/socket.rb +64 -0
  47. data/lib/net/ssh/transport/algorithms.rb +386 -0
  48. data/lib/net/ssh/transport/cipher_factory.rb +79 -0
  49. data/lib/net/ssh/transport/constants.rb +30 -0
  50. data/lib/net/ssh/transport/hmac.rb +42 -0
  51. data/lib/net/ssh/transport/hmac/abstract.rb +79 -0
  52. data/lib/net/ssh/transport/hmac/md5.rb +12 -0
  53. data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
  54. data/lib/net/ssh/transport/hmac/none.rb +15 -0
  55. data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
  56. data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
  57. data/lib/net/ssh/transport/hmac/sha2_256.rb +15 -0
  58. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +13 -0
  59. data/lib/net/ssh/transport/hmac/sha2_512.rb +14 -0
  60. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +13 -0
  61. data/lib/net/ssh/transport/identity_cipher.rb +55 -0
  62. data/lib/net/ssh/transport/kex.rb +17 -0
  63. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
  64. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +80 -0
  65. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +15 -0
  66. data/lib/net/ssh/transport/key_expander.rb +26 -0
  67. data/lib/net/ssh/transport/openssl.rb +127 -0
  68. data/lib/net/ssh/transport/packet_stream.rb +235 -0
  69. data/lib/net/ssh/transport/server_version.rb +71 -0
  70. data/lib/net/ssh/transport/session.rb +278 -0
  71. data/lib/net/ssh/transport/state.rb +206 -0
  72. data/lib/net/ssh/verifiers/lenient.rb +30 -0
  73. data/lib/net/ssh/verifiers/null.rb +12 -0
  74. data/lib/net/ssh/verifiers/strict.rb +53 -0
  75. data/lib/net/ssh/version.rb +62 -0
  76. data/lib/sonixlabs-net-ssh.rb +1 -0
  77. data/net-ssh.gemspec +145 -0
  78. data/setup.rb +1585 -0
  79. data/support/arcfour_check.rb +20 -0
  80. data/support/ssh_tunnel_bug.rb +65 -0
  81. data/test/authentication/methods/common.rb +28 -0
  82. data/test/authentication/methods/test_abstract.rb +51 -0
  83. data/test/authentication/methods/test_hostbased.rb +114 -0
  84. data/test/authentication/methods/test_keyboard_interactive.rb +100 -0
  85. data/test/authentication/methods/test_password.rb +52 -0
  86. data/test/authentication/methods/test_publickey.rb +148 -0
  87. data/test/authentication/test_agent.rb +205 -0
  88. data/test/authentication/test_key_manager.rb +171 -0
  89. data/test/authentication/test_session.rb +106 -0
  90. data/test/common.rb +107 -0
  91. data/test/configs/eqsign +3 -0
  92. data/test/configs/exact_match +8 -0
  93. data/test/configs/host_plus +10 -0
  94. data/test/configs/multihost +4 -0
  95. data/test/configs/wild_cards +14 -0
  96. data/test/connection/test_channel.rb +467 -0
  97. data/test/connection/test_session.rb +488 -0
  98. data/test/test_all.rb +9 -0
  99. data/test/test_buffer.rb +336 -0
  100. data/test/test_buffered_io.rb +63 -0
  101. data/test/test_config.rb +120 -0
  102. data/test/test_key_factory.rb +79 -0
  103. data/test/transport/hmac/test_md5.rb +39 -0
  104. data/test/transport/hmac/test_md5_96.rb +25 -0
  105. data/test/transport/hmac/test_none.rb +34 -0
  106. data/test/transport/hmac/test_sha1.rb +34 -0
  107. data/test/transport/hmac/test_sha1_96.rb +25 -0
  108. data/test/transport/hmac/test_sha2_256.rb +35 -0
  109. data/test/transport/hmac/test_sha2_256_96.rb +25 -0
  110. data/test/transport/hmac/test_sha2_512.rb +35 -0
  111. data/test/transport/hmac/test_sha2_512_96.rb +25 -0
  112. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
  113. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
  114. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +33 -0
  115. data/test/transport/test_algorithms.rb +308 -0
  116. data/test/transport/test_cipher_factory.rb +213 -0
  117. data/test/transport/test_hmac.rb +34 -0
  118. data/test/transport/test_identity_cipher.rb +40 -0
  119. data/test/transport/test_packet_stream.rb +736 -0
  120. data/test/transport/test_server_version.rb +78 -0
  121. data/test/transport/test_session.rb +315 -0
  122. data/test/transport/test_state.rb +179 -0
  123. metadata +178 -0
@@ -0,0 +1,78 @@
1
+ require 'common'
2
+ require 'net/ssh/transport/server_version'
3
+
4
+ module Transport
5
+
6
+ class TestServerVersion < Test::Unit::TestCase
7
+
8
+ def test_1_99_server_version_should_be_acceptible
9
+ s = subject(socket(true, "SSH-1.99-Testing_1.0\r\n"))
10
+ assert s.header.empty?
11
+ assert_equal "SSH-1.99-Testing_1.0", s.version
12
+ end
13
+
14
+ def test_2_0_server_version_should_be_acceptible
15
+ s = subject(socket(true, "SSH-2.0-Testing_1.0\r\n"))
16
+ assert s.header.empty?
17
+ assert_equal "SSH-2.0-Testing_1.0", s.version
18
+ end
19
+
20
+ def test_trailing_whitespace_should_be_preserved
21
+ # some servers, like Mocana, send a version string with trailing
22
+ # spaces, which are significant when exchanging keys later.
23
+ s = subject(socket(true, "SSH-2.0-Testing_1.0 \r\n"))
24
+ assert_equal "SSH-2.0-Testing_1.0 ", s.version
25
+ end
26
+
27
+ def test_unacceptible_server_version_should_raise_exception
28
+ assert_raises(Net::SSH::Exception) { subject(socket(false, "SSH-1.4-Testing_1.0\r\n")) }
29
+ end
30
+
31
+ def test_unexpected_server_close_should_raise_exception
32
+ assert_raises(Net::SSH::Disconnect) { subject(socket(false, "\r\nDestination server does not have Ssh activated.\r\nContact Cisco Systems, Inc to purchase a\r\nlicense key to activate Ssh.\r\n", true)) }
33
+ end
34
+
35
+ def test_header_lines_should_be_accumulated
36
+ s = subject(socket(true, "Welcome\r\nAnother line\r\nSSH-2.0-Testing_1.0\r\n"))
37
+ assert_equal "Welcome\r\nAnother line\r\n", s.header
38
+ assert_equal "SSH-2.0-Testing_1.0", s.version
39
+ end
40
+
41
+ def test_server_disconnect_should_raise_exception
42
+ assert_raises(Net::SSH::Disconnect) { subject(socket(false, "SSH-2.0-Aborting")) }
43
+ end
44
+
45
+ private
46
+
47
+ def socket(good, version_header, raise_eot=false)
48
+ socket = mock("socket")
49
+
50
+ data = version_header.split('')
51
+ recv_times = data.length
52
+ recv_times += 1 if data[-1] != "\n"
53
+
54
+ unless raise_eot
55
+
56
+ # socket.expects(:recv).with(1).times(recv_times).returns(*data).then.returns(nil)
57
+ # socket.expects(:readchar).times(recv_times).returns(*data).then.returns(nil)
58
+ socket.expects(:readpartial).with(1).times(recv_times).returns(*data).then.returns(nil)
59
+ else
60
+ socket.expects(:readpartial).with(1).times(recv_times+1).returns(*data).then.raises(EOFError, "end of file reached")
61
+ end
62
+
63
+ if good
64
+ socket.expects(:write).with("#{Net::SSH::Transport::ServerVersion::PROTO_VERSION}\r\n")
65
+ socket.expects(:flush)
66
+ else
67
+ socket.expects(:write).never
68
+ end
69
+
70
+ socket
71
+ end
72
+
73
+ def subject(socket)
74
+ Net::SSH::Transport::ServerVersion.new(socket, nil)
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,315 @@
1
+ require 'common'
2
+ require 'net/ssh/transport/session'
3
+
4
+ # mocha adds #verify to Object, which throws off the host-key-verifier part of
5
+ # these tests.
6
+
7
+ # can't use .include? because ruby18 uses strings and ruby19 uses symbols :/
8
+ if Object.instance_methods.any? { |v| v.to_sym == :verify }
9
+ Object.send(:undef_method, :verify)
10
+ end
11
+
12
+ module Transport
13
+
14
+ class TestSession < Test::Unit::TestCase
15
+ include Net::SSH::Transport::Constants
16
+
17
+ def test_constructor_defaults
18
+ assert_equal "net.ssh.test", session.host
19
+ assert_equal 22, session.port
20
+ assert_instance_of Net::SSH::Verifiers::Lenient, session.host_key_verifier
21
+ end
22
+
23
+ def test_paranoid_true_uses_lenient_verifier
24
+ assert_instance_of Net::SSH::Verifiers::Lenient, session(:paranoid => true).host_key_verifier
25
+ end
26
+
27
+ def test_paranoid_very_uses_strict_verifier
28
+ assert_instance_of Net::SSH::Verifiers::Strict, session(:paranoid => :very).host_key_verifier
29
+ end
30
+
31
+ def test_paranoid_false_uses_null_verifier
32
+ assert_instance_of Net::SSH::Verifiers::Null, session(:paranoid => false).host_key_verifier
33
+ end
34
+
35
+ def test_unknown_paranoid_value_raises_exception_if_value_does_not_respond_to_verify
36
+ assert_raises(ArgumentError) { session(:paranoid => :bogus).host_key_verifier }
37
+ end
38
+
39
+ def test_paranoid_value_responding_to_verify_should_pass_muster
40
+ object = stub("thingy", :verify => true)
41
+ assert_equal object, session(:paranoid => object).host_key_verifier
42
+ end
43
+
44
+ def test_host_as_string_should_return_host_and_ip_when_port_is_default
45
+ session!
46
+ socket.stubs(:peer_ip).returns("1.2.3.4")
47
+ assert_equal "net.ssh.test,1.2.3.4", session.host_as_string
48
+ end
49
+
50
+ def test_host_as_string_should_return_host_and_ip_with_port_when_port_is_not_default
51
+ session(:port => 1234) # force session to be instantiated
52
+ socket.stubs(:peer_ip).returns("1.2.3.4")
53
+ assert_equal "[net.ssh.test]:1234,[1.2.3.4]:1234", session.host_as_string
54
+ end
55
+
56
+ def test_host_as_string_should_return_only_host_when_host_is_ip
57
+ session!(:host => "1.2.3.4")
58
+ socket.stubs(:peer_ip).returns("1.2.3.4")
59
+ assert_equal "1.2.3.4", session.host_as_string
60
+ end
61
+
62
+ def test_host_as_string_should_return_only_host_and_port_when_host_is_ip_and_port_is_not_default
63
+ session!(:host => "1.2.3.4", :port => 1234)
64
+ socket.stubs(:peer_ip).returns("1.2.3.4")
65
+ assert_equal "[1.2.3.4]:1234", session.host_as_string
66
+ end
67
+
68
+ def test_close_should_cleanup_and_close_socket
69
+ session!
70
+ socket.expects(:cleanup)
71
+ socket.expects(:close)
72
+ session.close
73
+ end
74
+
75
+ def test_service_request_should_return_buffer
76
+ assert_equal "\005\000\000\000\004sftp", session.service_request('sftp').to_s
77
+ end
78
+
79
+ def test_rekey_when_kex_is_pending_should_do_nothing
80
+ algorithms.stubs(:pending? => true)
81
+ algorithms.expects(:rekey!).never
82
+ session.rekey!
83
+ end
84
+
85
+ def test_rekey_when_no_kex_is_pending_should_initiate_rekey_and_block_until_it_completes
86
+ algorithms.stubs(:pending? => false)
87
+ algorithms.expects(:rekey!)
88
+ session.expects(:wait).yields
89
+ algorithms.expects(:initialized?).returns(true)
90
+ session.rekey!
91
+ end
92
+
93
+ def test_rekey_as_needed_when_kex_is_pending_should_do_nothing
94
+ session!
95
+ algorithms.stubs(:pending? => true)
96
+ socket.expects(:if_needs_rekey?).never
97
+ session.rekey_as_needed
98
+ end
99
+
100
+ def test_rekey_as_needed_when_no_kex_is_pending_and_no_rekey_is_needed_should_do_nothing
101
+ session!
102
+ algorithms.stubs(:pending? => false)
103
+ socket.stubs(:if_needs_rekey? => false)
104
+ session.expects(:rekey!).never
105
+ session.rekey_as_needed
106
+ end
107
+
108
+ def test_rekey_as_needed_when_no_kex_is_pending_and_rekey_is_needed_should_initiate_rekey_and_block
109
+ session!
110
+ algorithms.stubs(:pending? => false)
111
+ socket.expects(:if_needs_rekey?).yields
112
+ session.expects(:rekey!)
113
+ session.rekey_as_needed
114
+ end
115
+
116
+ def test_peer_should_return_hash_of_info_about_peer
117
+ session!
118
+ socket.stubs(:peer_ip => "1.2.3.4")
119
+ assert_equal({:ip => "1.2.3.4", :port => 22, :host => "net.ssh.test", :canonized => "net.ssh.test,1.2.3.4"}, session.peer)
120
+ end
121
+
122
+ def test_next_message_should_block_until_next_message_is_available
123
+ session.expects(:poll_message).with(:block)
124
+ session.next_message
125
+ end
126
+
127
+ def test_poll_message_should_query_next_packet_using_the_given_blocking_parameter
128
+ session!
129
+ socket.expects(:next_packet).with(:blocking_parameter).returns(nil)
130
+ session.poll_message(:blocking_parameter)
131
+ end
132
+
133
+ def test_poll_message_should_default_to_non_blocking
134
+ session!
135
+ socket.expects(:next_packet).with(:nonblock).returns(nil)
136
+ session.poll_message
137
+ end
138
+
139
+ def test_poll_message_should_silently_handle_disconnect_packets
140
+ session!
141
+ socket.expects(:next_packet).returns(P(:byte, DISCONNECT, :long, 1, :string, "testing", :string, ""))
142
+ assert_raises(Net::SSH::Disconnect) { session.poll_message }
143
+ end
144
+
145
+ def test_poll_message_should_silently_handle_ignore_packets
146
+ session!
147
+ socket.expects(:next_packet).times(2).returns(P(:byte, IGNORE, :string, "test"), nil)
148
+ assert_nil session.poll_message
149
+ end
150
+
151
+ def test_poll_message_should_silently_handle_unimplemented_packets
152
+ session!
153
+ socket.expects(:next_packet).times(2).returns(P(:byte, UNIMPLEMENTED, :long, 15), nil)
154
+ assert_nil session.poll_message
155
+ end
156
+
157
+ def test_poll_message_should_silently_handle_debug_packets_with_always_display
158
+ session!
159
+ socket.expects(:next_packet).times(2).returns(P(:byte, DEBUG, :bool, true, :string, "testing", :string, ""), nil)
160
+ assert_nil session.poll_message
161
+ end
162
+
163
+ def test_poll_message_should_silently_handle_debug_packets_without_always_display
164
+ session!
165
+ socket.expects(:next_packet).times(2).returns(P(:byte, DEBUG, :bool, false, :string, "testing", :string, ""), nil)
166
+ assert_nil session.poll_message
167
+ end
168
+
169
+ def test_poll_message_should_silently_handle_kexinit_packets
170
+ session!
171
+ packet = P(:byte, KEXINIT, :raw, "lasdfalksdjfa;slkdfja;slkfjsdfaklsjdfa;df")
172
+ socket.expects(:next_packet).times(2).returns(packet, nil)
173
+ algorithms.expects(:accept_kexinit).with(packet)
174
+ assert_nil session.poll_message
175
+ end
176
+
177
+ def test_poll_message_should_return_other_packets
178
+ session!
179
+ packet = P(:byte, SERVICE_ACCEPT, :string, "test")
180
+ socket.expects(:next_packet).returns(packet)
181
+ assert_equal packet, session.poll_message
182
+ end
183
+
184
+ def test_poll_message_should_enqueue_packets_when_algorithm_disallows_packet
185
+ session!
186
+ packet = P(:byte, SERVICE_ACCEPT, :string, "test")
187
+ algorithms.stubs(:allow?).with(packet).returns(false)
188
+ socket.expects(:next_packet).times(2).returns(packet, nil)
189
+ assert_nil session.poll_message
190
+ assert_equal [packet], session.queue
191
+ end
192
+
193
+ def test_poll_message_should_read_from_queue_when_next_in_queue_is_allowed_and_consume_queue_is_true
194
+ session!
195
+ packet = P(:byte, SERVICE_ACCEPT, :string, "test")
196
+ session.push(packet)
197
+ socket.expects(:next_packet).never
198
+ assert_equal packet, session.poll_message
199
+ assert session.queue.empty?
200
+ end
201
+
202
+ def test_poll_message_should_not_read_from_queue_when_next_in_queue_is_not_allowed
203
+ session!
204
+ packet = P(:byte, SERVICE_ACCEPT, :string, "test")
205
+ algorithms.stubs(:allow?).with(packet).returns(false)
206
+ session.push(packet)
207
+ socket.expects(:next_packet).returns(nil)
208
+ assert_nil session.poll_message
209
+ assert_equal [packet], session.queue
210
+ end
211
+
212
+ def test_poll_message_should_not_read_from_queue_when_consume_queue_is_false
213
+ session!
214
+ packet = P(:byte, SERVICE_ACCEPT, :string, "test")
215
+ session.push(packet)
216
+ socket.expects(:next_packet).returns(nil)
217
+ assert_nil session.poll_message(:nonblock, false)
218
+ assert_equal [packet], session.queue
219
+ end
220
+
221
+ def test_wait_with_block_should_return_immediately_if_block_returns_truth
222
+ session.expects(:poll_message).never
223
+ session.wait { true }
224
+ end
225
+
226
+ def test_wait_should_not_consume_queue_on_reads
227
+ n = 0
228
+ session.expects(:poll_message).with(:nonblock, false).returns(nil)
229
+ session.wait { (n += 1) > 1 }
230
+ end
231
+
232
+ def test_wait_without_block_should_return_after_first_read
233
+ session.expects(:poll_message).returns(nil)
234
+ session.wait
235
+ end
236
+
237
+ def test_wait_should_enqueue_packets
238
+ session!
239
+
240
+ p1 = P(:byte, SERVICE_REQUEST, :string, "test")
241
+ p2 = P(:byte, SERVICE_ACCEPT, :string, "test")
242
+ socket.expects(:next_packet).times(2).returns(p1, p2)
243
+
244
+ n = 0
245
+ session.wait { (n += 1) > 2 }
246
+ assert_equal [p1, p2], session.queue
247
+ end
248
+
249
+ def test_push_should_enqueue_packet
250
+ packet = P(:byte, SERVICE_ACCEPT, :string, "test")
251
+ session.push(packet)
252
+ assert_equal [packet], session.queue
253
+ end
254
+
255
+ def test_send_message_should_delegate_to_socket
256
+ session!
257
+ packet = P(:byte, SERVICE_ACCEPT, :string, "test")
258
+ socket.expects(:send_packet).with(packet)
259
+ session.send_message(packet)
260
+ end
261
+
262
+ def test_enqueue_message_should_delegate_to_socket
263
+ session!
264
+ packet = P(:byte, SERVICE_ACCEPT, :string, "test")
265
+ socket.expects(:enqueue_packet).with(packet)
266
+ session.enqueue_message(packet)
267
+ end
268
+
269
+ def test_configure_client_should_pass_options_to_socket_client_state
270
+ session.configure_client :compression => :standard
271
+ assert_equal :standard, socket.client.compression
272
+ end
273
+
274
+ def test_configure_server_should_pass_options_to_socket_server_state
275
+ session.configure_server :compression => :standard
276
+ assert_equal :standard, socket.server.compression
277
+ end
278
+
279
+ def test_hint_should_set_hint_on_socket
280
+ assert !socket.hints[:authenticated]
281
+ session.hint :authenticated
282
+ assert socket.hints[:authenticated]
283
+ end
284
+
285
+ private
286
+
287
+ def socket
288
+ @socket ||= stub("socket", :hints => {})
289
+ end
290
+
291
+ def server_version
292
+ @server_version ||= stub("server_version")
293
+ end
294
+
295
+ def algorithms
296
+ @algorithms ||= stub("algorithms", :initialized? => true, :allow? => true)
297
+ end
298
+
299
+ def session(options={})
300
+ @session ||= begin
301
+ host = options.delete(:host) || "net.ssh.test"
302
+ TCPSocket.stubs(:open).with(host, options[:port] || 22).returns(socket)
303
+ Net::SSH::Transport::ServerVersion.stubs(:new).returns(server_version)
304
+ Net::SSH::Transport::Algorithms.stubs(:new).returns(algorithms)
305
+
306
+ Net::SSH::Transport::Session.new(host, options)
307
+ end
308
+ end
309
+
310
+ # a simple alias to make the tests more self-documenting. the bang
311
+ # version makes it look more like the session is being instantiated
312
+ alias session! session
313
+ end
314
+
315
+ end
@@ -0,0 +1,179 @@
1
+ require 'common'
2
+ require 'net/ssh/transport/state'
3
+
4
+ module Transport
5
+
6
+ class TestState < Test::Unit::TestCase
7
+
8
+ def setup
9
+ @socket = @state = @deflater = @inflater = nil
10
+ end
11
+
12
+ def teardown
13
+ if @deflater
14
+ @deflater.finish if !@deflater.finished?
15
+ @deflater.close
16
+ end
17
+
18
+ if @inflater
19
+ @inflater.finish if !@inflater.finished?
20
+ @inflater.close
21
+ end
22
+
23
+ state.cleanup
24
+ end
25
+
26
+ def test_constructor_should_initialize_all_values
27
+ assert_equal 0, state.sequence_number
28
+ assert_equal 0, state.packets
29
+ assert_equal 0, state.blocks
30
+
31
+ assert_nil state.compression
32
+ assert_nil state.compression_level
33
+ assert_nil state.max_packets
34
+ assert_nil state.max_blocks
35
+ assert_nil state.rekey_limit
36
+
37
+ assert_equal "identity", state.cipher.name
38
+ assert_instance_of Net::SSH::Transport::HMAC::None, state.hmac
39
+ end
40
+
41
+ def test_increment_should_increment_counters
42
+ state.increment(24)
43
+ assert_equal 1, state.sequence_number
44
+ assert_equal 1, state.packets
45
+ assert_equal 3, state.blocks
46
+ end
47
+
48
+ def test_reset_should_reset_counters_and_fix_defaults_for_maximums
49
+ state.increment(24)
50
+ state.reset!
51
+ assert_equal 1, state.sequence_number
52
+ assert_equal 0, state.packets
53
+ assert_equal 0, state.blocks
54
+ assert_equal 2147483648, state.max_packets
55
+ assert_equal 134217728, state.max_blocks
56
+ end
57
+
58
+ def test_set_should_set_variables_and_reset_counters
59
+ state.expects(:reset!)
60
+ state.set :cipher => :a, :hmac => :b, :compression => :c,
61
+ :compression_level => :d, :max_packets => 500, :max_blocks => 1000,
62
+ :rekey_limit => 1500
63
+ assert_equal :a, state.cipher
64
+ assert_equal :b, state.hmac
65
+ assert_equal :c, state.compression
66
+ assert_equal :d, state.compression_level
67
+ assert_equal 500, state.max_packets
68
+ assert_equal 1000, state.max_blocks
69
+ assert_equal 1500, state.rekey_limit
70
+ end
71
+
72
+ def test_set_with_max_packets_should_respect_max_packets_setting
73
+ state.set :max_packets => 500
74
+ assert_equal 500, state.max_packets
75
+ end
76
+
77
+ def test_set_with_max_blocks_should_respect_max_blocks_setting
78
+ state.set :max_blocks => 1000
79
+ assert_equal 1000, state.max_blocks
80
+ end
81
+
82
+ def test_set_with_rekey_limit_should_include_rekey_limit_in_computation_of_max_blocks
83
+ state.set :rekey_limit => 4000
84
+ assert_equal 500, state.max_blocks
85
+ end
86
+
87
+ def test_compressor_defaults_to_default_zlib_compression
88
+ expect = deflater.deflate("hello world")
89
+ assert_equal expect, state.compressor.deflate("hello world")
90
+ end
91
+
92
+ def test_compressor_uses_compression_level_when_given
93
+ state.set :compression_level => 1
94
+ expect = deflater(1).deflate("hello world")
95
+ assert_equal expect, state.compressor.deflate("hello world")
96
+ end
97
+
98
+ def test_compress_when_no_compression_is_active_returns_text
99
+ assert_equal "hello everybody", state.compress("hello everybody")
100
+ end
101
+
102
+ def test_decompress_when_no_compression_is_active_returns_text
103
+ assert_equal "hello everybody", state.decompress("hello everybody")
104
+ end
105
+
106
+ def test_compress_when_compression_is_delayed_and_no_auth_hint_is_set_should_return_text
107
+ state.set :compression => :delayed
108
+ assert_equal "hello everybody", state.compress("hello everybody")
109
+ end
110
+
111
+ def test_decompress_when_compression_is_delayed_and_no_auth_hint_is_set_should_return_text
112
+ state.set :compression => :delayed
113
+ assert_equal "hello everybody", state.decompress("hello everybody")
114
+ end
115
+
116
+ def test_compress_when_compression_is_enabled_should_return_compressed_text
117
+ state.set :compression => :standard
118
+ # JRuby Zlib implementation (1.4 & 1.5) does not have byte-to-byte compatibility with MRI's.
119
+ # skip this test under JRuby.
120
+ return if defined?(JRUBY_VERSION)
121
+ assert_equal "x\234\312H\315\311\311WH-K-\252L\312O\251\004\000\000\000\377\377", state.compress("hello everybody")
122
+ end
123
+
124
+ def test_decompress_when_compression_is_enabled_should_return_decompressed_text
125
+ state.set :compression => :standard
126
+ # JRuby Zlib implementation (1.4 & 1.5) does not have byte-to-byte compatibility with MRI's.
127
+ # skip this test under JRuby.
128
+ return if defined?(JRUBY_VERSION)
129
+ assert_equal "hello everybody", state.decompress("x\234\312H\315\311\311WH-K-\252L\312O\251\004\000\000\000\377\377")
130
+ end
131
+
132
+ def test_compress_when_compression_is_delayed_and_auth_hint_is_set_should_return_compressed_text
133
+ socket.hints[:authenticated] = true
134
+ state.set :compression => :delayed
135
+ assert_equal "x\234\312H\315\311\311WH-K-\252L\312O\251\004\000\000\000\377\377", state.compress("hello everybody")
136
+ end
137
+
138
+ def test_decompress_when_compression_is_delayed_and_auth_hint_is_set_should_return_decompressed_text
139
+ socket.hints[:authenticated] = true
140
+ state.set :compression => :delayed
141
+ assert_equal "hello everybody", state.decompress("x\234\312H\315\311\311WH-K-\252L\312O\251\004\000\000\000\377\377")
142
+ end
143
+
144
+ def test_needs_rekey_should_be_true_if_packets_exceeds_max_packets
145
+ state.set :max_packets => 2
146
+ state.increment(8)
147
+ state.increment(8)
148
+ assert !state.needs_rekey?
149
+ state.increment(8)
150
+ assert state.needs_rekey?
151
+ end
152
+
153
+ def test_needs_rekey_should_be_true_if_blocks_exceeds_max_blocks
154
+ state.set :max_blocks => 10
155
+ assert !state.needs_rekey?
156
+ state.increment(88)
157
+ assert state.needs_rekey?
158
+ end
159
+
160
+ private
161
+
162
+ def deflater(level=Zlib::DEFAULT_COMPRESSION)
163
+ @deflater ||= Zlib::Deflate.new(level)
164
+ end
165
+
166
+ def inflater
167
+ @inflater ||= Zlib::Inflate.new(nil)
168
+ end
169
+
170
+ def socket
171
+ @socket ||= stub("socket", :hints => {})
172
+ end
173
+
174
+ def state
175
+ @state ||= Net::SSH::Transport::State.new(socket, :test)
176
+ end
177
+ end
178
+
179
+ end