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
@@ -1,98 +1,150 @@
1
1
  require 'strscan'
2
2
  require 'openssl'
3
3
  require 'base64'
4
+ require 'delegate'
4
5
  require 'net/ssh/buffer'
6
+ require 'net/ssh/authentication/ed25519_loader'
5
7
 
6
- module Net; module SSH
8
+ module Net
9
+ module SSH
10
+ module HostKeyEntries
11
+ # regular public key entry
12
+ class PubKey < Delegator
13
+ def initialize(key, comment: nil) # rubocop:disable Lint/MissingSuper
14
+ @key = key
15
+ @comment = comment
16
+ end
7
17
 
8
- # Represents the result of a search in known hosts
9
- # see search_for
10
- class HostKeys
11
- include Enumerable
12
- attr_reader :host
18
+ def ssh_type
19
+ @key.ssh_type
20
+ end
13
21
 
14
- def initialize(host_keys, host, known_hosts, options = {})
15
- @host_keys = host_keys
16
- @host = host
17
- @known_hosts = known_hosts
18
- @options = options
19
- end
22
+ def ssh_types
23
+ [ssh_type]
24
+ end
20
25
 
21
- def add_host_key(key)
22
- @known_hosts.add(@host, key, @options)
23
- @host_keys.push(key)
24
- end
26
+ def to_blob
27
+ @key.to_blob
28
+ end
25
29
 
26
- def each(&block)
27
- @host_keys.each(&block)
28
- end
30
+ def __getobj__
31
+ Kernel.warn("Calling Net::SSH::Buffer methods on HostKeyEntries PubKey is deprecated")
32
+ @key
33
+ end
29
34
 
30
- def empty?
31
- @host_keys.empty?
32
- end
33
- end
35
+ def matches_key?(server_key)
36
+ @key.ssh_type == server_key.ssh_type && @key.to_blob == server_key.to_blob
37
+ end
38
+ end
39
+
40
+ # @cert-authority entry
41
+ class CertAuthority
42
+ def ssh_types
43
+ %w[
44
+ ecdsa-sha2-nistp256-cert-v01@openssh.com
45
+ ecdsa-sha2-nistp384-cert-v01@openssh.com
46
+ ecdsa-sha2-nistp521-cert-v01@openssh.com
47
+ ssh-ed25519-cert-v01@openssh.com
48
+ ssh-rsa-cert-v01@openssh.com
49
+ ssh-rsa-cert-v00@openssh.com
50
+ ]
51
+ end
34
52
 
35
- # Searches an OpenSSH-style known-host file for a given host, and returns all
36
- # matching keys. This is used to implement host-key verification, as well as
37
- # to determine what key a user prefers to use for a given host.
38
- #
39
- # This is used internally by Net::SSH, and will never need to be used directly
40
- # by consumers of the library.
41
- class KnownHosts
53
+ def initialize(key, comment: nil)
54
+ @key = key
55
+ @comment = comment
56
+ end
42
57
 
43
- if defined?(OpenSSL::PKey::EC)
44
- SUPPORTED_TYPE = %w(ssh-rsa ssh-dss
45
- ecdsa-sha2-nistp256
46
- ecdsa-sha2-nistp384
47
- ecdsa-sha2-nistp521)
48
- else
49
- SUPPORTED_TYPE = %w(ssh-rsa ssh-dss)
58
+ def matches_key?(server_key)
59
+ if ssh_types.include?(server_key.ssh_type)
60
+ server_key.signature_valid? && (server_key.signature_key.to_blob == @key.to_blob)
61
+ else
62
+ false
63
+ end
64
+ end
65
+ end
50
66
  end
51
67
 
68
+ # Represents the result of a search in known hosts
69
+ # see search_for
70
+ class HostKeys
71
+ include Enumerable
72
+ attr_reader :host
52
73
 
53
- class <<self
74
+ def initialize(host_keys, host, known_hosts, options = {})
75
+ @host_keys = host_keys
76
+ @host = host
77
+ @known_hosts = known_hosts
78
+ @options = options
79
+ end
54
80
 
55
- # Searches all known host files (see KnownHosts.hostfiles) for all keys
56
- # of the given host. Returns an enumerable of keys found.
57
- def search_for(host, options={})
58
- HostKeys.new(search_in(hostfiles(options), host), host, self, options)
81
+ def add_host_key(key)
82
+ @known_hosts.add(@host, key, @options)
83
+ @host_keys.push(key)
59
84
  end
60
85
 
61
- # Search for all known keys for the given host, in every file given in
62
- # the +files+ array. Returns the list of keys.
63
- def search_in(files, host)
64
- files.map { |file| KnownHosts.new(file).keys_for(host) }.flatten
86
+ def each(&block)
87
+ @host_keys.each(&block)
65
88
  end
66
89
 
67
- # Looks in the given +options+ hash for the :user_known_hosts_file and
68
- # :global_known_hosts_file keys, and returns an array of all known
69
- # hosts files. If the :user_known_hosts_file key is not set, the
70
- # default is returned (~/.ssh/known_hosts and ~/.ssh/known_hosts2). If
71
- # :global_known_hosts_file is not set, the default is used
72
- # (/etc/ssh/ssh_known_hosts and /etc/ssh/ssh_known_hosts2).
73
- #
74
- # If you only want the user known host files, you can pass :user as
75
- # the second option.
76
- def hostfiles(options, which=:all)
77
- files = []
90
+ def empty?
91
+ @host_keys.empty?
92
+ end
93
+ end
94
+
95
+ # Searches an OpenSSH-style known-host file for a given host, and returns all
96
+ # matching keys. This is used to implement host-key verification, as well as
97
+ # to determine what key a user prefers to use for a given host.
98
+ #
99
+ # This is used internally by Net::SSH, and will never need to be used directly
100
+ # by consumers of the library.
101
+ class KnownHosts
102
+ SUPPORTED_TYPE = %w[ssh-rsa ssh-dss
103
+ ecdsa-sha2-nistp256
104
+ ecdsa-sha2-nistp384
105
+ ecdsa-sha2-nistp521]
78
106
 
79
- if which == :all || which == :user
80
- files += Array(options[:user_known_hosts_file] || %w(~/.ssh/known_hosts ~/.ssh/known_hosts2))
107
+ SUPPORTED_TYPE.push('ssh-ed25519') if Net::SSH::Authentication::ED25519Loader::LOADED
108
+
109
+ class << self
110
+ # Searches all known host files (see KnownHosts.hostfiles) for all keys
111
+ # of the given host. Returns an enumerable of keys found.
112
+ def search_for(host, options = {})
113
+ HostKeys.new(search_in(hostfiles(options), host, options), host, self, options)
81
114
  end
82
115
 
83
- if which == :all || which == :global
84
- files += Array(options[:global_known_hosts_file] || %w(/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2))
116
+ # Search for all known keys for the given host, in every file given in
117
+ # the +files+ array. Returns the list of keys.
118
+ def search_in(files, host, options = {})
119
+ files.flat_map { |file| KnownHosts.new(file).keys_for(host, options) }
85
120
  end
86
121
 
87
- return files
88
- end
122
+ # Looks in the given +options+ hash for the :user_known_hosts_file and
123
+ # :global_known_hosts_file keys, and returns an array of all known
124
+ # hosts files. If the :user_known_hosts_file key is not set, the
125
+ # default is returned (~/.ssh/known_hosts and ~/.ssh/known_hosts2). If
126
+ # :global_known_hosts_file is not set, the default is used
127
+ # (/etc/ssh/ssh_known_hosts and /etc/ssh/ssh_known_hosts2).
128
+ #
129
+ # If you only want the user known host files, you can pass :user as
130
+ # the second option.
131
+ def hostfiles(options, which = :all)
132
+ files = []
133
+
134
+ files += Array(options[:user_known_hosts_file] || %w[~/.ssh/known_hosts ~/.ssh/known_hosts2]) if which == :all || which == :user
135
+
136
+ if which == :all || which == :global
137
+ files += Array(options[:global_known_hosts_file] || %w[/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2])
138
+ end
89
139
 
90
- # Looks in all user known host files (see KnownHosts.hostfiles) and tries to
91
- # add an entry for the given host and key to the first file it is able
92
- # to.
93
- def add(host, key, options={})
94
- hostfiles(options, :user).each do |file|
95
- begin
140
+ return files
141
+ end
142
+
143
+ # Looks in all user known host files (see KnownHosts.hostfiles) and tries to
144
+ # add an entry for the given host and key to the first file it is able
145
+ # to.
146
+ def add(host, key, options = {})
147
+ hostfiles(options, :user).each do |file|
96
148
  KnownHosts.new(file).add(host, key)
97
149
  return
98
150
  rescue SystemCallError
@@ -100,88 +152,114 @@ module Net; module SSH
100
152
  end
101
153
  end
102
154
  end
103
- end
104
155
 
105
- # The host-key file name that this KnownHosts instance will use to search
106
- # for keys.
107
- attr_reader :source
156
+ # The host-key file name that this KnownHosts instance will use to search
157
+ # for keys.
158
+ attr_reader :source
108
159
 
109
- # Instantiate a new KnownHosts instance that will search the given known-hosts
110
- # file. The path is expanded file File.expand_path.
111
- def initialize(source)
112
- @source = File.expand_path(source)
113
- end
160
+ # Instantiate a new KnownHosts instance that will search the given known-hosts
161
+ # file. The path is expanded file File.expand_path.
162
+ def initialize(source)
163
+ @source = File.expand_path(source)
164
+ end
114
165
 
115
- # Returns an array of all keys that are known to be associatd with the
116
- # given host. The +host+ parameter is either the domain name or ip address
117
- # of the host, or both (comma-separated). Additionally, if a non-standard
118
- # port is being used, it may be specified by putting the host (or ip, or
119
- # both) in square brackets, and appending the port outside the brackets
120
- # after a colon. Possible formats for +host+, then, are;
121
- #
122
- # "net.ssh.test"
123
- # "1.2.3.4"
124
- # "net.ssh.test,1.2.3.4"
125
- # "[net.ssh.test]:5555"
126
- # "[1,2,3,4]:5555"
127
- # "[net.ssh.test]:5555,[1.2.3.4]:5555
128
- def keys_for(host)
129
- keys = []
130
- return keys unless File.readable?(source)
166
+ # Returns an array of all keys that are known to be associatd with the
167
+ # given host. The +host+ parameter is either the domain name or ip address
168
+ # of the host, or both (comma-separated). Additionally, if a non-standard
169
+ # port is being used, it may be specified by putting the host (or ip, or
170
+ # both) in square brackets, and appending the port outside the brackets
171
+ # after a colon. Possible formats for +host+, then, are;
172
+ #
173
+ # "net.ssh.test"
174
+ # "1.2.3.4"
175
+ # "net.ssh.test,1.2.3.4"
176
+ # "[net.ssh.test]:5555"
177
+ # "[1,2,3,4]:5555"
178
+ # "[net.ssh.test]:5555,[1.2.3.4]:5555
179
+ def keys_for(host, options = {})
180
+ keys = []
181
+ return keys unless File.readable?(source)
182
+
183
+ entries = host.split(/,/)
184
+ host_name = entries[0]
185
+ host_ip = entries[1]
131
186
 
132
- entries = host.split(/,/)
187
+ File.open(source) do |file|
188
+ file.each_line do |line|
189
+ if line.start_with?('@')
190
+ marker, hosts, type, key_content, comment = line.split(' ')
191
+ else
192
+ marker = nil
193
+ hosts, type, key_content, comment = line.split(' ')
194
+ end
133
195
 
134
- File.open(source) do |file|
135
- scanner = StringScanner.new("")
136
- file.each_line do |line|
137
- scanner.string = line
196
+ # Skip empty line or one that is commented
197
+ next if hosts.nil? || hosts.start_with?('#')
138
198
 
139
- scanner.skip(/\s*/)
140
- next if scanner.match?(/$|#/)
199
+ hostlist = hosts.split(',')
141
200
 
142
- hostlist = scanner.scan(/\S+/).split(/,/)
143
- found = entries.all? { |entry| hostlist.include?(entry) } ||
144
- known_host_hash?(hostlist, entries, scanner)
145
- next unless found
201
+ next unless SUPPORTED_TYPE.include?(type)
146
202
 
147
- scanner.skip(/\s*/)
148
- type = scanner.scan(/\S+/)
203
+ found = hostlist.any? { |pattern| match(host_name, pattern) } || known_host_hash?(hostlist, entries)
204
+ next unless found
149
205
 
150
- next unless SUPPORTED_TYPE.include?(type)
206
+ found = hostlist.include?(host_ip) if options[:check_host_ip] && entries.size > 1 && hostlist.size > 1
207
+ next unless found
151
208
 
152
- scanner.skip(/\s*/)
153
- blob = scanner.rest.unpack("m*").first
154
- keys << Net::SSH::Buffer.new(blob).read_key
209
+ blob = key_content.unpack("m*").first
210
+ raw_key = Net::SSH::Buffer.new(blob).read_key
211
+
212
+ keys <<
213
+ if marker == "@cert-authority"
214
+ HostKeyEntries::CertAuthority.new(raw_key, comment: comment)
215
+ else
216
+ HostKeyEntries::PubKey.new(raw_key, comment: comment)
217
+ end
218
+ end
155
219
  end
220
+
221
+ keys
156
222
  end
157
223
 
158
- keys
159
- end
224
+ def match(host, pattern)
225
+ if pattern.include?('*') || pattern.include?('?')
226
+ # see man 8 sshd for pattern details
227
+ pattern_regexp = pattern.split('*', -1).map do |x|
228
+ x.split('?', -1).map do |y|
229
+ Regexp.escape(y)
230
+ end.join('.')
231
+ end.join('.*')
160
232
 
161
- # Indicates whether one of the entries matches an hostname that has been
162
- # stored as a HMAC-SHA1 hash in the known hosts.
163
- def known_host_hash?(hostlist, entries, scanner)
164
- if hostlist.size == 1 && hostlist.first =~ /\A\|1(\|.+){2}\z/
165
- chunks = hostlist.first.split(/\|/)
166
- salt = Base64.decode64(chunks[2])
167
- digest = OpenSSL::Digest.new('sha1')
168
- entries.each do |entry|
169
- hmac = OpenSSL::HMAC.digest(digest, salt, entry)
170
- return true if Base64.encode64(hmac).chomp == chunks[3]
233
+ host =~ Regexp.new("\\A#{pattern_regexp}\\z")
234
+ else
235
+ host == pattern
171
236
  end
172
237
  end
173
- false
174
- end
175
238
 
176
- # Tries to append an entry to the current source file for the given host
177
- # and key. If it is unable to (because the file is not writable, for
178
- # instance), an exception will be raised.
179
- def add(host, key)
180
- File.open(source, "a") do |file|
181
- blob = [Net::SSH::Buffer.from(:key, key).to_s].pack("m*").gsub(/\s/, "")
182
- file.puts "#{host} #{key.ssh_type} #{blob}"
239
+ # Indicates whether one of the entries matches an hostname that has been
240
+ # stored as a HMAC-SHA1 hash in the known hosts.
241
+ def known_host_hash?(hostlist, entries)
242
+ if hostlist.size == 1 && hostlist.first =~ /\A\|1(\|.+){2}\z/
243
+ chunks = hostlist.first.split(/\|/)
244
+ salt = Base64.decode64(chunks[2])
245
+ digest = OpenSSL::Digest.new('sha1')
246
+ entries.each do |entry|
247
+ hmac = OpenSSL::HMAC.digest(digest, salt, entry)
248
+ return true if Base64.encode64(hmac).chomp == chunks[3]
249
+ end
250
+ end
251
+ false
183
252
  end
184
- end
185
253
 
254
+ # Tries to append an entry to the current source file for the given host
255
+ # and key. If it is unable to (because the file is not writable, for
256
+ # instance), an exception will be raised.
257
+ def add(host, key)
258
+ File.open(source, "a") do |file|
259
+ blob = [Net::SSH::Buffer.from(:key, key).to_s].pack("m*").gsub(/\s/, "")
260
+ file.puts "#{host} #{key.ssh_type} #{blob}"
261
+ end
262
+ end
263
+ end
186
264
  end
187
- end; end
265
+ end
@@ -1,61 +1,62 @@
1
- module Net; module SSH
2
-
3
- # A simple module to make logging easier to deal with. It assumes that the
4
- # logger instance (if not nil) quacks like a Logger object (in Ruby's
5
- # standard library). Although used primarily internally by Net::SSH, it
6
- # can easily be used to add Net::SSH-like logging to your own programs.
7
- #
8
- # class MyClass
9
- # include Net::SSH::Loggable
10
- # end
11
- #
12
- # Net::SSH.start(...) do |ssh|
13
- # obj = MyClass.new
14
- # obj.logger = ssh.logger
15
- # ...
16
- # end
17
- module Loggable
18
- # The logger instance that will be used to log messages. If nil, nothing
19
- # will be logged.
20
- attr_accessor :logger
21
-
22
- # Displays the result of yielding if the log level is Logger::DEBUG or
23
- # greater.
24
- def debug
25
- logger.add(Logger::DEBUG, nil, facility) { yield } if logger && logger.debug?
26
- end
1
+ module Net
2
+ module SSH
3
+ # A simple module to make logging easier to deal with. It assumes that the
4
+ # logger instance (if not nil) quacks like a Logger object (in Ruby's
5
+ # standard library). Although used primarily internally by Net::SSH, it
6
+ # can easily be used to add Net::SSH-like logging to your own programs.
7
+ #
8
+ # class MyClass
9
+ # include Net::SSH::Loggable
10
+ # end
11
+ #
12
+ # Net::SSH.start(...) do |ssh|
13
+ # obj = MyClass.new
14
+ # obj.logger = ssh.logger
15
+ # ...
16
+ # end
17
+ module Loggable
18
+ # The logger instance that will be used to log messages. If nil, nothing
19
+ # will be logged.
20
+ attr_accessor :logger
21
+
22
+ # Displays the result of yielding if the log level is Logger::DEBUG or
23
+ # greater.
24
+ def debug
25
+ logger.add(Logger::DEBUG, nil, facility) { yield } if logger && logger.debug?
26
+ end
27
27
 
28
- # Displays the result of yielding if the log level is Logger::INFO or
29
- # greater.
30
- def info
31
- logger.add(Logger::INFO, nil, facility) { yield } if logger && logger.info?
32
- end
28
+ # Displays the result of yielding if the log level is Logger::INFO or
29
+ # greater.
30
+ def info
31
+ logger.add(Logger::INFO, nil, facility) { yield } if logger && logger.info?
32
+ end
33
33
 
34
- # Displays the result of yielding if the log level is Logger::WARN or
35
- # greater. (Called lwarn to avoid shadowing with Kernel#warn.)
36
- def lwarn
37
- logger.add(Logger::WARN, nil, facility) { yield } if logger && logger.warn?
38
- end
34
+ # Displays the result of yielding if the log level is Logger::WARN or
35
+ # greater. (Called lwarn to avoid shadowing with Kernel#warn.)
36
+ def lwarn
37
+ logger.add(Logger::WARN, nil, facility) { yield } if logger && logger.warn?
38
+ end
39
39
 
40
- # Displays the result of yielding if the log level is Logger:ERROR or
41
- # greater.
42
- def error
43
- logger.add(Logger::ERROR, nil, facility) { yield } if logger && logger.error?
44
- end
40
+ # Displays the result of yielding if the log level is Logger:ERROR or
41
+ # greater.
42
+ def error
43
+ logger.add(Logger::ERROR, nil, facility) { yield } if logger && logger.error?
44
+ end
45
45
 
46
- # Displays the result of yielding if the log level is Logger::FATAL or
47
- # greater.
48
- def fatal
49
- logger.add(Logger::FATAL, nil, facility) { yield } if logger && logger.fatal?
50
- end
46
+ # Displays the result of yielding if the log level is Logger::FATAL or
47
+ # greater.
48
+ def fatal
49
+ logger.add(Logger::FATAL, nil, facility) { yield } if logger && logger.fatal?
50
+ end
51
51
 
52
- private
52
+ private
53
53
 
54
54
  # Sets the "facility" value, used for reporting where a log message
55
55
  # originates. It defaults to the name of class with the object_id
56
56
  # appended.
57
57
  def facility
58
- @facility ||= self.class.name.gsub(/::/, ".").gsub(/([a-z])([A-Z])/, "\\1_\\2").downcase + "[%x]" % object_id
58
+ @facility ||= self.class.to_s.gsub(/::/, ".").gsub(/([a-z])([A-Z])/, "\\1_\\2").downcase + "[%x]" % object_id
59
59
  end
60
+ end
60
61
  end
61
- end; end
62
+ end