net-ssh 6.1.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 (116) hide show
  1. checksums.yaml +4 -4
  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 +4 -0
  10. data/.rubocop.yml +12 -1
  11. data/.rubocop_todo.yml +475 -376
  12. data/CHANGES.txt +64 -3
  13. data/DEVELOPMENT.md +23 -0
  14. data/Dockerfile +29 -0
  15. data/Dockerfile.openssl3 +17 -0
  16. data/Gemfile +2 -0
  17. data/Gemfile.noed25519 +2 -0
  18. data/Gemfile.norbnacl +12 -0
  19. data/README.md +38 -22
  20. data/Rakefile +92 -0
  21. data/SECURITY.md +4 -0
  22. data/docker-compose.yml +25 -0
  23. data/lib/net/ssh/authentication/agent.rb +29 -13
  24. data/lib/net/ssh/authentication/certificate.rb +14 -11
  25. data/lib/net/ssh/authentication/constants.rb +0 -1
  26. data/lib/net/ssh/authentication/ed25519.rb +14 -11
  27. data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
  28. data/lib/net/ssh/authentication/key_manager.rb +65 -36
  29. data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
  30. data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
  31. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +2 -2
  32. data/lib/net/ssh/authentication/methods/none.rb +6 -9
  33. data/lib/net/ssh/authentication/methods/password.rb +2 -3
  34. data/lib/net/ssh/authentication/methods/publickey.rb +57 -17
  35. data/lib/net/ssh/authentication/pageant.rb +97 -97
  36. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +3 -3
  37. data/lib/net/ssh/authentication/session.rb +25 -17
  38. data/lib/net/ssh/buffer.rb +71 -51
  39. data/lib/net/ssh/buffered_io.rb +25 -26
  40. data/lib/net/ssh/config.rb +33 -20
  41. data/lib/net/ssh/connection/channel.rb +84 -82
  42. data/lib/net/ssh/connection/constants.rb +0 -4
  43. data/lib/net/ssh/connection/event_loop.rb +30 -24
  44. data/lib/net/ssh/connection/keepalive.rb +12 -12
  45. data/lib/net/ssh/connection/session.rb +109 -108
  46. data/lib/net/ssh/connection/term.rb +56 -58
  47. data/lib/net/ssh/errors.rb +12 -12
  48. data/lib/net/ssh/key_factory.rb +7 -8
  49. data/lib/net/ssh/known_hosts.rb +86 -18
  50. data/lib/net/ssh/loggable.rb +8 -9
  51. data/lib/net/ssh/packet.rb +1 -1
  52. data/lib/net/ssh/prompt.rb +9 -11
  53. data/lib/net/ssh/proxy/command.rb +1 -1
  54. data/lib/net/ssh/proxy/errors.rb +2 -4
  55. data/lib/net/ssh/proxy/http.rb +18 -20
  56. data/lib/net/ssh/proxy/https.rb +8 -10
  57. data/lib/net/ssh/proxy/jump.rb +8 -10
  58. data/lib/net/ssh/proxy/socks4.rb +2 -4
  59. data/lib/net/ssh/proxy/socks5.rb +3 -5
  60. data/lib/net/ssh/service/forward.rb +7 -7
  61. data/lib/net/ssh/test/channel.rb +24 -26
  62. data/lib/net/ssh/test/extensions.rb +35 -35
  63. data/lib/net/ssh/test/kex.rb +6 -8
  64. data/lib/net/ssh/test/local_packet.rb +0 -2
  65. data/lib/net/ssh/test/packet.rb +3 -3
  66. data/lib/net/ssh/test/remote_packet.rb +6 -8
  67. data/lib/net/ssh/test/script.rb +25 -27
  68. data/lib/net/ssh/test/socket.rb +12 -15
  69. data/lib/net/ssh/test.rb +4 -5
  70. data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
  71. data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
  72. data/lib/net/ssh/transport/algorithms.rb +51 -19
  73. data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  74. data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  75. data/lib/net/ssh/transport/cipher_factory.rb +56 -29
  76. data/lib/net/ssh/transport/constants.rb +3 -3
  77. data/lib/net/ssh/transport/ctr.rb +7 -7
  78. data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
  79. data/lib/net/ssh/transport/hmac/abstract.rb +20 -5
  80. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  81. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  82. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  83. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  84. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  85. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  86. data/lib/net/ssh/transport/hmac.rb +12 -12
  87. data/lib/net/ssh/transport/identity_cipher.rb +19 -13
  88. data/lib/net/ssh/transport/kex/abstract.rb +12 -5
  89. data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
  90. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +2 -1
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
  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 +21 -21
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -2
  95. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
  96. data/lib/net/ssh/transport/kex.rb +8 -6
  97. data/lib/net/ssh/transport/key_expander.rb +7 -8
  98. data/lib/net/ssh/transport/openssl.rb +51 -26
  99. data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  100. data/lib/net/ssh/transport/packet_stream.rb +46 -26
  101. data/lib/net/ssh/transport/server_version.rb +17 -16
  102. data/lib/net/ssh/transport/session.rb +9 -7
  103. data/lib/net/ssh/transport/state.rb +44 -44
  104. data/lib/net/ssh/verifiers/accept_new.rb +0 -2
  105. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
  106. data/lib/net/ssh/verifiers/always.rb +6 -4
  107. data/lib/net/ssh/verifiers/never.rb +0 -2
  108. data/lib/net/ssh/version.rb +2 -2
  109. data/lib/net/ssh.rb +15 -8
  110. data/net-ssh-public_cert.pem +19 -18
  111. data/net-ssh.gemspec +7 -4
  112. data/support/ssh_tunnel_bug.rb +3 -3
  113. data.tar.gz.sig +0 -0
  114. metadata +76 -29
  115. metadata.gz.sig +0 -0
  116. data/.travis.yml +0 -52
@@ -5,7 +5,6 @@ require 'net/ssh/authentication/ed25519_loader'
5
5
 
6
6
  module Net
7
7
  module SSH
8
-
9
8
  # Net::SSH::Buffer is a flexible class for building and parsing binary
10
9
  # data packets. It provides a stream-like interface for sequentially
11
10
  # reading data items from the buffer, as well as a useful helper method
@@ -71,7 +70,7 @@ module Net
71
70
 
72
71
  # Creates a new buffer, initialized to the given content. The position
73
72
  # is initialized to the beginning of the buffer.
74
- def initialize(content="")
73
+ def initialize(content = String.new)
75
74
  @content = content.to_s
76
75
  @position = 0
77
76
  end
@@ -118,7 +117,7 @@ module Net
118
117
  # Resets the buffer, making it empty. Also, resets the read position to
119
118
  # 0.
120
119
  def clear!
121
- @content = ""
120
+ @content = String.new
122
121
  @position = 0
123
122
  end
124
123
 
@@ -129,12 +128,12 @@ module Net
129
128
  # would otherwise tend to grow without bound.
130
129
  #
131
130
  # Returns the buffer object itself.
132
- def consume!(n=position)
131
+ def consume!(n = position)
133
132
  if n >= length
134
133
  # optimize for a fairly common case
135
134
  clear!
136
135
  elsif n > 0
137
- @content = @content[n..-1] || ""
136
+ @content = @content[n..-1] || String.new
138
137
  @position -= n
139
138
  @position = 0 if @position < 0
140
139
  end
@@ -172,7 +171,7 @@ module Net
172
171
  # Reads and returns the next +count+ bytes from the buffer, starting from
173
172
  # the read position. If +count+ is +nil+, this will return all remaining
174
173
  # text in the buffer. This method will increment the pointer.
175
- def read(count=nil)
174
+ def read(count = nil)
176
175
  count ||= length
177
176
  count = length - @position if @position + count > length
178
177
  @position += count
@@ -181,7 +180,7 @@ module Net
181
180
 
182
181
  # Reads (as #read) and returns the given number of bytes from the buffer,
183
182
  # and then consumes (as #consume!) all data up to the new read position.
184
- def read!(count=nil)
183
+ def read!(count = nil)
185
184
  data = read(count)
186
185
  consume!
187
186
  data
@@ -237,6 +236,7 @@ module Net
237
236
  def read_bignum
238
237
  data = read_string
239
238
  return unless data
239
+
240
240
  OpenSSL::BN.new(data, 2)
241
241
  end
242
242
 
@@ -251,7 +251,6 @@ module Net
251
251
  def read_private_keyblob(type)
252
252
  case type
253
253
  when /^ssh-rsa$/
254
- key = OpenSSL::PKey::RSA.new
255
254
  n = read_bignum
256
255
  e = read_bignum
257
256
  d = read_bignum
@@ -262,27 +261,30 @@ module Net
262
261
  _unkown2 = read_bignum
263
262
  dmp1 = d % (p - 1)
264
263
  dmq1 = d % (q - 1)
265
- if key.respond_to?(:set_key)
266
- key.set_key(n, e, d)
267
- else
268
- key.e = e
269
- key.n = n
270
- key.d = d
271
- end
272
- if key.respond_to?(:set_factors)
273
- key.set_factors(p, q)
274
- else
275
- key.p = p
276
- key.q = q
277
- end
278
- if key.respond_to?(:set_crt_params)
279
- key.set_crt_params(dmp1, dmq1, iqmp)
280
- else
281
- key.dmp1 = dmp1
282
- key.dmq1 = dmq1
283
- key.iqmp = iqmp
264
+ # Public key
265
+ data_sequence = OpenSSL::ASN1::Sequence([
266
+ OpenSSL::ASN1::Integer(n),
267
+ OpenSSL::ASN1::Integer(e)
268
+ ])
269
+
270
+ if d && p && q && dmp1 && dmq1 && iqmp
271
+ data_sequence = OpenSSL::ASN1::Sequence([
272
+ OpenSSL::ASN1::Integer(0),
273
+ OpenSSL::ASN1::Integer(n),
274
+ OpenSSL::ASN1::Integer(e),
275
+ OpenSSL::ASN1::Integer(d),
276
+ OpenSSL::ASN1::Integer(p),
277
+ OpenSSL::ASN1::Integer(q),
278
+ OpenSSL::ASN1::Integer(dmp1),
279
+ OpenSSL::ASN1::Integer(dmq1),
280
+ OpenSSL::ASN1::Integer(iqmp)
281
+ ])
284
282
  end
285
- key
283
+
284
+ asn1 = OpenSSL::ASN1::Sequence(data_sequence)
285
+ OpenSSL::PKey::RSA.new(asn1.to_der)
286
+ when /^ecdsa\-sha2\-(\w*)$/
287
+ OpenSSL::PKey::EC.read_keyblob($1, self)
286
288
  else
287
289
  raise Exception, "Cannot decode private key of type #{type}"
288
290
  end
@@ -295,29 +297,42 @@ module Net
295
297
  when /^(.*)-cert-v01@openssh\.com$/
296
298
  key = Net::SSH::Authentication::Certificate.read_certblob(self, $1)
297
299
  when /^ssh-dss$/
298
- key = OpenSSL::PKey::DSA.new
299
- if key.respond_to?(:set_pqg)
300
- key.set_pqg(read_bignum, read_bignum, read_bignum)
301
- else
302
- key.p = read_bignum
303
- key.q = read_bignum
304
- key.g = read_bignum
305
- end
306
- if key.respond_to?(:set_key)
307
- key.set_key(read_bignum, nil)
308
- else
309
- key.pub_key = read_bignum
310
- end
300
+ p = read_bignum
301
+ q = read_bignum
302
+ g = read_bignum
303
+ pub_key = read_bignum
304
+
305
+ asn1 = OpenSSL::ASN1::Sequence.new(
306
+ [
307
+ OpenSSL::ASN1::Sequence.new(
308
+ [
309
+ OpenSSL::ASN1::ObjectId.new('DSA'),
310
+ OpenSSL::ASN1::Sequence.new(
311
+ [
312
+ OpenSSL::ASN1::Integer.new(p),
313
+ OpenSSL::ASN1::Integer.new(q),
314
+ OpenSSL::ASN1::Integer.new(g)
315
+ ]
316
+ )
317
+ ]
318
+ ),
319
+ OpenSSL::ASN1::BitString.new(OpenSSL::ASN1::Integer.new(pub_key).to_der)
320
+ ]
321
+ )
322
+
323
+ key = OpenSSL::PKey::DSA.new(asn1.to_der)
311
324
  when /^ssh-rsa$/
312
- key = OpenSSL::PKey::RSA.new
313
- if key.respond_to?(:set_key)
314
- e = read_bignum
315
- n = read_bignum
316
- key.set_key(n, e, nil)
317
- else
318
- key.e = read_bignum
319
- key.n = read_bignum
320
- end
325
+ e = read_bignum
326
+ n = read_bignum
327
+
328
+ asn1 = OpenSSL::ASN1::Sequence(
329
+ [
330
+ OpenSSL::ASN1::Integer(n),
331
+ OpenSSL::ASN1::Integer(e)
332
+ ]
333
+ )
334
+
335
+ key = OpenSSL::PKey::RSA.new(asn1.to_der)
321
336
  when /^ssh-ed25519$/
322
337
  Net::SSH::Authentication::ED25519Loader.raiseUnlessLoaded("unsupported key type `#{type}'")
323
338
  key = Net::SSH::Authentication::ED25519::PubKey.read_keyblob(self)
@@ -346,7 +361,12 @@ module Net
346
361
  # Optimized version of write where the caller gives up ownership of string
347
362
  # to the method. This way we can mutate the string.
348
363
  def write_moved(string)
349
- @content << string.force_encoding('BINARY')
364
+ @content <<
365
+ if string.frozen?
366
+ string.dup.force_encoding('BINARY')
367
+ else
368
+ string.force_encoding('BINARY')
369
+ end
350
370
  self
351
371
  end
352
372
 
@@ -1,9 +1,8 @@
1
1
  require 'net/ssh/buffer'
2
2
  require 'net/ssh/loggable'
3
3
 
4
- module Net
4
+ module Net
5
5
  module SSH
6
-
7
6
  # This module is used to extend sockets and other IO objects, to allow
8
7
  # them to be buffered for both read and write. This abstraction makes it
9
8
  # quite easy to write a select-based event loop
@@ -48,21 +47,21 @@ module Net
48
47
  # end
49
48
  module BufferedIo
50
49
  include Loggable
51
-
50
+
52
51
  # Called when the #extend is called on an object, with this module as the
53
52
  # argument. It ensures that the modules instance variables are all properly
54
53
  # initialized.
55
- def self.extended(object) #:nodoc:
54
+ def self.extended(object) # :nodoc:
56
55
  # need to use __send__ because #send is overridden in Socket
57
56
  object.__send__(:initialize_buffered_io)
58
57
  end
59
-
58
+
60
59
  # Tries to read up to +n+ bytes of data from the remote end, and appends
61
60
  # the data to the input buffer. It returns the number of bytes read, or 0
62
61
  # if no data was available to be read.
63
- def fill(n=8192)
62
+ def fill(n = 8192)
64
63
  input.consume!
65
- data = recv(n)
64
+ data = recv(n) || ""
66
65
  debug { "read #{data.length} bytes" }
67
66
  input.append(data)
68
67
  return data.length
@@ -70,31 +69,31 @@ module Net
70
69
  @input_errors << e
71
70
  return 0
72
71
  end
73
-
72
+
74
73
  # Read up to +length+ bytes from the input buffer. If +length+ is nil,
75
74
  # all available data is read from the buffer. (See #available.)
76
- def read_available(length=nil)
75
+ def read_available(length = nil)
77
76
  input.read(length || available)
78
77
  end
79
-
78
+
80
79
  # Returns the number of bytes available to be read from the input buffer.
81
80
  # (See #read_available.)
82
81
  def available
83
82
  input.available
84
83
  end
85
-
84
+
86
85
  # Enqueues data in the output buffer, to be written when #send_pending
87
86
  # is called. Note that the data is _not_ sent immediately by this method!
88
87
  def enqueue(data)
89
88
  output.append(data)
90
89
  end
91
-
90
+
92
91
  # Returns +true+ if there is data waiting in the output buffer, and
93
92
  # +false+ otherwise.
94
93
  def pending_write?
95
94
  output.length > 0
96
95
  end
97
-
96
+
98
97
  # Sends as much of the pending output as possible. Returns +true+ if any
99
98
  # data was sent, and +false+ otherwise.
100
99
  def send_pending
@@ -107,7 +106,7 @@ module Net
107
106
  return false
108
107
  end
109
108
  end
110
-
109
+
111
110
  # Calls #send_pending repeatedly, if necessary, blocking until the output
112
111
  # buffer is empty.
113
112
  def wait_for_pending_sends
@@ -115,31 +114,32 @@ module Net
115
114
  while output.length > 0
116
115
  result = IO.select(nil, [self]) or next
117
116
  next unless result[1].any?
117
+
118
118
  send_pending
119
119
  end
120
120
  end
121
-
121
+
122
122
  public # these methods are primarily for use in tests
123
-
124
- def write_buffer #:nodoc:
123
+
124
+ def write_buffer # :nodoc:
125
125
  output.to_s
126
126
  end
127
-
128
- def read_buffer #:nodoc:
127
+
128
+ def read_buffer # :nodoc:
129
129
  input.to_s
130
130
  end
131
-
131
+
132
132
  private
133
-
133
+
134
134
  #--
135
135
  # Can't use attr_reader here (after +private+) without incurring the
136
136
  # wrath of "ruby -w". We hates it.
137
137
  #++
138
-
138
+
139
139
  def input; @input; end
140
140
 
141
141
  def output; @output; end
142
-
142
+
143
143
  # Initializes the intput and output buffers for this object. This method
144
144
  # is called automatically when the module is mixed into an object via
145
145
  # Object#extend (see Net::SSH::BufferedIo.extended), but must be called
@@ -166,7 +166,7 @@ module Net
166
166
  # http://github.com/net-ssh/net-ssh/tree/portfwfix
167
167
  #
168
168
  module ForwardedBufferedIo
169
- def fill(n=8192)
169
+ def fill(n = 8192)
170
170
  begin
171
171
  super(n)
172
172
  rescue Errno::ECONNRESET => e
@@ -181,7 +181,7 @@ module Net
181
181
  end
182
182
  end
183
183
  end
184
-
184
+
185
185
  def send_pending
186
186
  begin
187
187
  super
@@ -198,6 +198,5 @@ module Net
198
198
  end
199
199
  end
200
200
  end
201
-
202
201
  end
203
202
  end
@@ -1,6 +1,5 @@
1
1
  module Net
2
2
  module SSH
3
-
4
3
  # The Net::SSH::Config class is used to parse OpenSSH configuration files,
5
4
  # and translates that syntax into the configuration syntax that Net::SSH
6
5
  # understands. This lets Net::SSH scripts read their configuration (to
@@ -34,7 +33,7 @@ module Net
34
33
  # * ProxyJump => maps to the :proxy option
35
34
  # * PubKeyAuthentication => maps to the :auth_methods option
36
35
  # * RekeyLimit => :rekey_limit
37
- # * StrictHostKeyChecking => :strict_host_key_checking
36
+ # * StrictHostKeyChecking => :verify_host_key
38
37
  # * User => :user
39
38
  # * UserKnownHostsFile => :user_known_hosts_file
40
39
  # * NumberOfPasswordPrompts => :number_of_password_prompts
@@ -66,7 +65,7 @@ module Net
66
65
  # given +files+ (defaulting to the list of files returned by
67
66
  # #default_files), translates the resulting hash into the options
68
67
  # recognized by Net::SSH, and returns them.
69
- def for(host, files=expandable_default_files)
68
+ def for(host, files = expandable_default_files)
70
69
  translate(files.inject({}) { |settings, file|
71
70
  load(file, host, settings)
72
71
  })
@@ -78,7 +77,7 @@ module Net
78
77
  # ones. Returns a hash containing the OpenSSH options. (See
79
78
  # #translate for how to convert the OpenSSH options into Net::SSH
80
79
  # options.)
81
- def load(path, host, settings={}, base_dir = nil)
80
+ def load(path, host, settings = {}, base_dir = nil)
82
81
  file = File.expand_path(path)
83
82
  base_dir ||= File.dirname(file)
84
83
  return settings unless File.readable?(file)
@@ -186,17 +185,35 @@ module Net
186
185
  # Filters default_files down to the files that are expandable.
187
186
  def expandable_default_files
188
187
  default_files.keep_if do |path|
189
- begin
190
- File.expand_path(path)
191
- true
192
- rescue ArgumentError
193
- false
194
- end
188
+ File.expand_path(path)
189
+ true
190
+ rescue ArgumentError
191
+ false
195
192
  end
196
193
  end
197
194
 
198
195
  private
199
196
 
197
+ def translate_verify_host_key(value)
198
+ case value
199
+ when false
200
+ :never
201
+ when true
202
+ :always
203
+ when 'accept-new'
204
+ :accept_new
205
+ end
206
+ end
207
+
208
+ def translate_keepalive(hash, value)
209
+ if value && value.to_i > 0
210
+ hash[:keepalive] = true
211
+ hash[:keepalive_interval] = value.to_i
212
+ else
213
+ hash[:keepalive] = false
214
+ end
215
+ end
216
+
200
217
  TRANSLATE_CONFIG_KEY_RENAME_MAP = {
201
218
  bindaddress: :bind_address,
202
219
  compression: :compression,
@@ -211,13 +228,14 @@ module Net
211
228
  identityfile: :keys,
212
229
  fingerprinthash: :fingerprint_hash,
213
230
  port: :port,
214
- stricthostkeychecking: :strict_host_key_checking,
215
231
  user: :user,
216
232
  userknownhostsfile: :user_known_hosts_file,
217
233
  checkhostip: :check_host_ip
218
234
  }.freeze
219
235
  def translate_config_key(hash, key, value, settings)
220
236
  case key
237
+ when :stricthostkeychecking
238
+ hash[:verify_host_key] = translate_verify_host_key(value)
221
239
  when :ciphers
222
240
  hash[:encryption] = value.split(/,/)
223
241
  when :hostbasedauthentication
@@ -235,12 +253,7 @@ module Net
235
253
  when :serveralivecountmax
236
254
  hash[:keepalive_maxcount] = value.to_i if value
237
255
  when :serveraliveinterval
238
- if value && value.to_i > 0
239
- hash[:keepalive] = true
240
- hash[:keepalive_interval] = value.to_i
241
- else
242
- hash[:keepalive] = false
243
- end
256
+ translate_keepalive(hash, value)
244
257
  when :passwordauthentication
245
258
  if value
246
259
  (hash[:auth_methods] << 'password').uniq!
@@ -302,9 +315,9 @@ module Net
302
315
  # host names.
303
316
  def pattern2regex(pattern)
304
317
  tail = pattern
305
- prefix = ""
318
+ prefix = String.new
306
319
  while !tail.empty? do
307
- head,sep,tail = tail.partition(/[\*\?]/)
320
+ head, sep, tail = tail.partition(/[\*\?]/)
308
321
  prefix = prefix + Regexp.quote(head)
309
322
  case sep
310
323
  when '*'
@@ -358,7 +371,7 @@ module Net
358
371
 
359
372
  conditions = conditions.each_slice(2)
360
373
  condition_matches = []
361
- conditions.each do |(kind,exprs)|
374
+ conditions.each do |(kind, exprs)|
362
375
  exprs = unquote(exprs)
363
376
 
364
377
  case kind.downcase