net-sftp 2.1.2 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/ci.yml +35 -0
- data/.gitignore +6 -0
- data/CHANGES.txt +4 -0
- data/Gemfile +15 -0
- data/README.rdoc +7 -4
- data/Rakefile +24 -30
- data/lib/net/sftp/operations/dir.rb +3 -3
- data/lib/net/sftp/operations/download.rb +8 -7
- data/lib/net/sftp/operations/file.rb +32 -9
- data/lib/net/sftp/operations/upload.rb +3 -3
- data/lib/net/sftp/session.rb +7 -5
- data/lib/net/sftp/version.rb +63 -13
- data/lib/net/sftp.rb +12 -4
- data/net-sftp-public_cert.pem +20 -0
- data/net-sftp.gemspec +35 -93
- data.tar.gz.sig +0 -0
- metadata +53 -82
- metadata.gz.sig +0 -0
- data/gem-public_cert.pem +0 -20
- data/test/common.rb +0 -184
- data/test/protocol/01/test_attributes.rb +0 -97
- data/test/protocol/01/test_base.rb +0 -210
- data/test/protocol/01/test_name.rb +0 -27
- data/test/protocol/02/test_base.rb +0 -26
- data/test/protocol/03/test_base.rb +0 -27
- data/test/protocol/04/test_attributes.rb +0 -148
- data/test/protocol/04/test_base.rb +0 -74
- data/test/protocol/04/test_name.rb +0 -53
- data/test/protocol/05/test_base.rb +0 -62
- data/test/protocol/06/test_attributes.rb +0 -124
- data/test/protocol/06/test_base.rb +0 -51
- data/test/protocol/test_base.rb +0 -42
- data/test/test_all.rb +0 -7
- data/test/test_dir.rb +0 -47
- data/test/test_download.rb +0 -287
- data/test/test_file.rb +0 -159
- data/test/test_file_factory.rb +0 -48
- data/test/test_packet.rb +0 -9
- data/test/test_protocol.rb +0 -17
- data/test/test_request.rb +0 -71
- data/test/test_response.rb +0 -53
- data/test/test_session.rb +0 -741
- data/test/test_upload.rb +0 -233
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4319de630f665ee342eb3c367bf1fbe1e71a057206379c5251ab2c3b073d0cb7
|
4
|
+
data.tar.gz: a35ca9f05cf5bd73f2e9b5ede7ed9f473d0025c7da530707a6470e0bdbcc1adb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 37774670d3e3a6627f1070e5043316ccc590fd0c5049971ff36a5f83391b266a129b3f660f1b75a1d71819baef95c104f3c22bb21a1c90cdab05ff4c96ddd7a9
|
7
|
+
data.tar.gz: 0fd554d08be7d9151484f8fe8a5bb17a4f095918457a33ffc6dbebd06a7fbffc3fcbf6d79d159339e4f20c3bada94d1b3c9980936808012287b717296c4facf0
|
checksums.yaml.gz.sig
ADDED
Binary file
|
@@ -0,0 +1,35 @@
|
|
1
|
+
name: CI
|
2
|
+
on: [push, pull_request]
|
3
|
+
jobs:
|
4
|
+
test:
|
5
|
+
runs-on: ubuntu-18.04
|
6
|
+
continue-on-error: ${{ matrix.flaky }}
|
7
|
+
strategy:
|
8
|
+
matrix:
|
9
|
+
ruby-version: ["2.5", "2.6", "2.7", "3.0", "3.1", "truffleruby-22", "truffleruby-21"]
|
10
|
+
flaky: [false]
|
11
|
+
include:
|
12
|
+
- ruby-version: "ruby-head"
|
13
|
+
flaky: true
|
14
|
+
- ruby-version: "jruby-9.2"
|
15
|
+
flaky: true
|
16
|
+
- ruby-version: "jruby-9.3"
|
17
|
+
flaky: true
|
18
|
+
- ruby-version: "jruby-head"
|
19
|
+
flaky: true
|
20
|
+
- ruby-version: "truffleruby-head"
|
21
|
+
flaky: true
|
22
|
+
steps:
|
23
|
+
- uses: actions/checkout@v1
|
24
|
+
|
25
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
26
|
+
uses: ruby/setup-ruby@v1
|
27
|
+
with:
|
28
|
+
ruby-version: ${{ matrix.ruby-version }}
|
29
|
+
|
30
|
+
- name: Bundle install
|
31
|
+
run: |
|
32
|
+
gem install bundler
|
33
|
+
bundle install
|
34
|
+
- name: Run Tests
|
35
|
+
run: bundle exec rake test
|
data/.gitignore
ADDED
data/CHANGES.txt
CHANGED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in mygem.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
# TODO: add to gemspec
|
7
|
+
gem "bundler", "~> 2.1"
|
8
|
+
gem "rake", "~> 12.0"
|
9
|
+
|
10
|
+
gem 'byebug', group: %i[development test] if !Gem.win_platform? && RUBY_ENGINE == "ruby"
|
11
|
+
|
12
|
+
if ENV["CI"]
|
13
|
+
gem 'codecov', require: false, group: :test
|
14
|
+
gem 'simplecov', require: false, group: :test
|
15
|
+
end
|
data/README.rdoc
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
= Net::SFTP
|
2
2
|
|
3
|
-
|
3
|
+
<em><b>Please note: this project is in maintenance mode. It is not under active development but pull requests are very much welcome. Just be sure to include tests! -- delano</b></em>
|
4
|
+
|
5
|
+
|
6
|
+
* Docs: http://net-ssh.github.io/net-sftp
|
4
7
|
* Issues: https://github.com/net-ssh/net-sftp/issues
|
5
8
|
* Codes: https://github.com/net-ssh/net-sftp
|
6
9
|
* Email: net-ssh@solutious.com
|
@@ -69,12 +72,12 @@ If you wish to run the tests, you'll need:
|
|
69
72
|
|
70
73
|
* gem install net-sftp (might need sudo privileges)
|
71
74
|
|
72
|
-
However, in order to be sure the code you're installing hasn't been tampered with, it's recommended that you verify the
|
75
|
+
However, in order to be sure the code you're installing hasn't been tampered with, it's recommended that you verify the signature[http://docs.rubygems.org/read/chapter/21]. To do this, you need to add my public key as a trusted certificate (you only need to do this once):
|
73
76
|
|
74
77
|
# Add the public key as a trusted certificate
|
75
78
|
# (You only need to do this once)
|
76
|
-
$ curl -O https://raw.
|
77
|
-
$ gem cert --add
|
79
|
+
$ curl -O https://raw.githubusercontent.com/net-ssh/net-sftp/master/net-sftp-public_cert.pem
|
80
|
+
$ gem cert --add net-sftp-public_cert.pem
|
78
81
|
|
79
82
|
Then, when install the gem, do so with high security:
|
80
83
|
|
data/Rakefile
CHANGED
@@ -2,40 +2,35 @@ require "rubygems"
|
|
2
2
|
require "rake"
|
3
3
|
require "rake/clean"
|
4
4
|
require "rdoc/task"
|
5
|
+
require "bundler/gem_tasks"
|
6
|
+
|
7
|
+
desc "When releasing make sure NET_SSH_BUILDGEM_SIGNED is set"
|
8
|
+
task :check_NET_SSH_BUILDGEM_SIGNED do
|
9
|
+
raise "NET_SSH_BUILDGEM_SIGNED should be set to release" unless ENV['NET_SSH_BUILDGEM_SIGNED']
|
10
|
+
end
|
11
|
+
|
12
|
+
Rake::Task[:release].enhance [:check_NET_SSH_BUILDGEM_SIGNED]
|
13
|
+
Rake::Task[:release].prerequisites.unshift(:check_NET_SSH_BUILDGEM_SIGNED)
|
5
14
|
|
6
15
|
task :default => ["build"]
|
7
16
|
CLEAN.include [ 'pkg', 'rdoc' ]
|
8
17
|
name = "net-sftp"
|
9
18
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
s.authors = ["Jamis Buck", "Delano Mandelbaum"]
|
25
|
-
|
26
|
-
s.add_dependency 'net-ssh', ">=2.6.5"
|
27
|
-
|
28
|
-
s.add_development_dependency 'test-unit'
|
29
|
-
s.add_development_dependency 'mocha'
|
30
|
-
|
31
|
-
s.license = "MIT"
|
32
|
-
|
33
|
-
s.signing_key = File.join('/mnt/gem/', 'gem-private_key.pem')
|
34
|
-
s.cert_chain = ['gem-public_cert.pem']
|
19
|
+
require_relative "lib/net/sftp/version"
|
20
|
+
version = Net::SFTP::Version::CURRENT
|
21
|
+
|
22
|
+
namespace :cert do
|
23
|
+
desc "Update public cert from private - only run if public is expired"
|
24
|
+
task :update_public_when_expired do
|
25
|
+
require 'openssl'
|
26
|
+
require 'time'
|
27
|
+
raw = File.read "net-sftp-public_cert.pem"
|
28
|
+
certificate = OpenSSL::X509::Certificate.new raw
|
29
|
+
raise Exception, "Not yet expired: #{certificate.not_after}" unless certificate.not_after < Time.now
|
30
|
+
sh "gem cert --build netssh@solutious.com --days 365*5 --private-key /mnt/gem/net-ssh-private_key.pem"
|
31
|
+
sh "mv gem-public_cert.pem net-sftp-public_cert.pem"
|
32
|
+
sh "gem cert --add net-sftp-public_cert.pem"
|
35
33
|
end
|
36
|
-
Jeweler::GemcutterTasks.new
|
37
|
-
rescue LoadError
|
38
|
-
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
39
34
|
end
|
40
35
|
|
41
36
|
require 'rake/testtask'
|
@@ -53,7 +48,6 @@ RDoc::Task.new do |rdoc|
|
|
53
48
|
rdoc.rdoc_files.include("bin/*.rb")
|
54
49
|
rdoc.rdoc_files.include("lib/**/*.rb")
|
55
50
|
extra_files.each { |file|
|
56
|
-
rdoc.rdoc_files.include(file) if File.
|
51
|
+
rdoc.rdoc_files.include(file) if File.exist?(file)
|
57
52
|
}
|
58
53
|
end
|
59
|
-
|
@@ -57,10 +57,10 @@ module Net; module SFTP; module Operations
|
|
57
57
|
# it should be able to handle modest numbers of files in each directory.
|
58
58
|
def glob(path, pattern, flags=0)
|
59
59
|
flags |= ::File::FNM_PATHNAME
|
60
|
-
path = path.chop if path
|
60
|
+
path = path.chop if path.end_with?('/') && path != '/'
|
61
61
|
|
62
62
|
results = [] unless block_given?
|
63
|
-
queue = entries(path).reject { |e|
|
63
|
+
queue = entries(path).reject { |e| %w(. ..).include?(e.name) }
|
64
64
|
while queue.any?
|
65
65
|
entry = queue.shift
|
66
66
|
|
@@ -90,4 +90,4 @@ module Net; module SFTP; module Operations
|
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
-
end; end; end
|
93
|
+
end; end; end
|
@@ -27,7 +27,7 @@ module Net; module SFTP; module Operations
|
|
27
27
|
#
|
28
28
|
# sftp.download!("/path/to/remotedir", "/path/to/local", :recursive => true)
|
29
29
|
#
|
30
|
-
# This will download "/path/to/remotedir",
|
30
|
+
# This will download "/path/to/remotedir", its contents, its subdirectories,
|
31
31
|
# and their contents, recursively, to "/path/to/local" on the local host.
|
32
32
|
# (If you specify :recursive => true and the source is not a directory,
|
33
33
|
# you'll get an error!)
|
@@ -81,6 +81,7 @@ module Net; module SFTP; module Operations
|
|
81
81
|
# puts "creating directory #{args[0]}"
|
82
82
|
# when :finish then
|
83
83
|
# puts "all done!"
|
84
|
+
# end
|
84
85
|
# end
|
85
86
|
#
|
86
87
|
# However, for more complex implementations (e.g., GUI interfaces and such)
|
@@ -255,7 +256,7 @@ module Net; module SFTP; module Operations
|
|
255
256
|
# operation was successful.
|
256
257
|
def on_opendir(response)
|
257
258
|
entry = response.request[:entry]
|
258
|
-
raise "opendir #{entry.remote}
|
259
|
+
raise StatusException.new(response, "opendir #{entry.remote}") unless response.ok?
|
259
260
|
entry.handle = response[:handle]
|
260
261
|
request = sftp.readdir(response[:handle], &method(:on_readdir))
|
261
262
|
request[:parent] = entry
|
@@ -270,7 +271,7 @@ module Net; module SFTP; module Operations
|
|
270
271
|
request = sftp.close(entry.handle, &method(:on_closedir))
|
271
272
|
request[:parent] = entry
|
272
273
|
elsif !response.ok?
|
273
|
-
raise "readdir #{entry.remote}
|
274
|
+
raise StatusException.new(response, "readdir #{entry.remote}")
|
274
275
|
else
|
275
276
|
response[:names].each do |item|
|
276
277
|
next if item.name == "." || item.name == ".."
|
@@ -296,7 +297,7 @@ module Net; module SFTP; module Operations
|
|
296
297
|
def on_closedir(response)
|
297
298
|
@active -= 1
|
298
299
|
entry = response.request[:parent]
|
299
|
-
raise "close #{entry.remote}
|
300
|
+
raise StatusException.new(response, "close #{entry.remote}") unless response.ok?
|
300
301
|
process_next_entry
|
301
302
|
end
|
302
303
|
|
@@ -304,7 +305,7 @@ module Net; module SFTP; module Operations
|
|
304
305
|
# to initiate the data transfer.
|
305
306
|
def on_open(response)
|
306
307
|
entry = response.request[:entry]
|
307
|
-
raise "open #{entry.remote}
|
308
|
+
raise StatusException.new(response, "open #{entry.remote}") unless response.ok?
|
308
309
|
|
309
310
|
entry.handle = response[:handle]
|
310
311
|
entry.sink = entry.local.respond_to?(:write) ? entry.local : ::File.open(entry.local, "wb")
|
@@ -332,7 +333,7 @@ module Net; module SFTP; module Operations
|
|
332
333
|
request = sftp.close(entry.handle, &method(:on_close))
|
333
334
|
request[:entry] = entry
|
334
335
|
elsif !response.ok?
|
335
|
-
raise "read #{entry.remote}
|
336
|
+
raise StatusException.new(response, "read #{entry.remote}")
|
336
337
|
else
|
337
338
|
entry.offset += response[:data].bytesize
|
338
339
|
update_progress(:get, entry, response.request[:offset], response[:data])
|
@@ -345,7 +346,7 @@ module Net; module SFTP; module Operations
|
|
345
346
|
def on_close(response)
|
346
347
|
@active -= 1
|
347
348
|
entry = response.request[:entry]
|
348
|
-
raise "close #{entry.remote}
|
349
|
+
raise StatusException.new(response, "close #{entry.remote}") unless response.ok?
|
349
350
|
process_next_entry
|
350
351
|
end
|
351
352
|
|
@@ -81,21 +81,35 @@ module Net; module SFTP; module Operations
|
|
81
81
|
# Reads up to the next instance of +sep_string+ in the stream, and
|
82
82
|
# returns the bytes read (including +sep_string+). If +sep_string+ is
|
83
83
|
# omitted, it defaults to +$/+. If EOF is encountered before any data
|
84
|
-
# could be read, #gets will return +nil+.
|
85
|
-
|
86
|
-
|
84
|
+
# could be read, #gets will return +nil+. If the first argument is an
|
85
|
+
# integer, or optional second argument is given, the returning string
|
86
|
+
# would not be longer than the given value in bytes.
|
87
|
+
def gets(sep_or_limit=$/, limit=Float::INFINITY)
|
88
|
+
if sep_or_limit.is_a? Integer
|
89
|
+
sep_string = $/
|
90
|
+
lim = sep_or_limit
|
91
|
+
else
|
92
|
+
sep_string = sep_or_limit
|
93
|
+
lim = limit
|
94
|
+
end
|
95
|
+
|
96
|
+
delim = if sep_string && sep_string.length == 0
|
87
97
|
"#{$/}#{$/}"
|
88
98
|
else
|
89
99
|
sep_string
|
90
100
|
end
|
91
101
|
|
92
102
|
loop do
|
93
|
-
at = @buffer.index(delim)
|
103
|
+
at = @buffer.index(delim) if delim
|
94
104
|
if at
|
95
|
-
offset = at + delim.length
|
105
|
+
offset = [at + delim.length, lim].min
|
96
106
|
@pos += offset
|
97
107
|
line, @buffer = @buffer[0,offset], @buffer[offset..-1]
|
98
108
|
return line
|
109
|
+
elsif lim < @buffer.length
|
110
|
+
@pos += lim
|
111
|
+
line, @buffer = @buffer[0,lim], @buffer[lim..-1]
|
112
|
+
return line
|
99
113
|
elsif !fill
|
100
114
|
return nil if @buffer.empty?
|
101
115
|
@pos += @buffer.length
|
@@ -107,8 +121,8 @@ module Net; module SFTP; module Operations
|
|
107
121
|
|
108
122
|
# Same as #gets, but raises EOFError if EOF is encountered before any
|
109
123
|
# data could be read.
|
110
|
-
def readline(
|
111
|
-
line = gets(
|
124
|
+
def readline(sep_or_limit=$/, limit=Float::INFINITY)
|
125
|
+
line = gets(sep_or_limit, limit)
|
112
126
|
raise EOFError if line.nil?
|
113
127
|
return line
|
114
128
|
end
|
@@ -118,9 +132,9 @@ module Net; module SFTP; module Operations
|
|
118
132
|
def write(data)
|
119
133
|
data = data.to_s
|
120
134
|
sftp.write!(handle, @real_pos, data)
|
121
|
-
@real_pos += data.length
|
135
|
+
@real_pos += data.bytes.length
|
122
136
|
@pos = @real_pos
|
123
|
-
data.length
|
137
|
+
data.bytes.length
|
124
138
|
end
|
125
139
|
|
126
140
|
# Writes each argument to the stream. If +$\+ is set, it will be written
|
@@ -131,6 +145,15 @@ module Net; module SFTP; module Operations
|
|
131
145
|
nil
|
132
146
|
end
|
133
147
|
|
148
|
+
def size
|
149
|
+
stat.size
|
150
|
+
end
|
151
|
+
|
152
|
+
# Resets position to beginning of file
|
153
|
+
def rewind
|
154
|
+
self.pos = 0
|
155
|
+
end
|
156
|
+
|
134
157
|
# Writes each argument to the stream, appending a newline to any item
|
135
158
|
# that does not already end in a newline. Array arguments are flattened.
|
136
159
|
def puts(*items)
|
@@ -27,14 +27,14 @@ module Net; module SFTP; module Operations
|
|
27
27
|
#
|
28
28
|
# sftp.upload!("/path/to/directory", "/path/to/remote")
|
29
29
|
#
|
30
|
-
# This will upload "/path/to/directory",
|
30
|
+
# This will upload "/path/to/directory", its contents, its subdirectories,
|
31
31
|
# and their contents, recursively, to "/path/to/remote" on the remote server.
|
32
32
|
#
|
33
33
|
# For uploading a directory without creating it, do
|
34
34
|
# sftp.upload!("/path/to/directory", "/path/to/remote", :mkdir => false)
|
35
35
|
#
|
36
36
|
# If you want to send data to a file on the remote server, but the data is
|
37
|
-
# in memory, you can pass an IO object and upload
|
37
|
+
# in memory, you can pass an IO object and upload its contents:
|
38
38
|
#
|
39
39
|
# require 'stringio'
|
40
40
|
# io = StringIO.new(data)
|
@@ -173,7 +173,7 @@ module Net; module SFTP; module Operations
|
|
173
173
|
process_next_entry
|
174
174
|
end
|
175
175
|
else
|
176
|
-
raise ArgumentError, "expected a file to upload" unless local.respond_to?(:read) || ::File.
|
176
|
+
raise ArgumentError, "expected a file to upload" unless local.respond_to?(:read) || ::File.exist?(local)
|
177
177
|
@stack = [[local]]
|
178
178
|
process_next_entry
|
179
179
|
end
|
data/lib/net/sftp/session.rb
CHANGED
@@ -75,11 +75,13 @@ module Net; module SFTP
|
|
75
75
|
#
|
76
76
|
# sftp = Net::SFTP::Session.new(ssh)
|
77
77
|
# sftp.loop { sftp.opening? }
|
78
|
-
def initialize(session, &block)
|
78
|
+
def initialize(session, version = nil, &block)
|
79
79
|
@session = session
|
80
|
+
@version = version
|
80
81
|
@input = Net::SSH::Buffer.new
|
81
82
|
self.logger = session.logger
|
82
83
|
@state = :closed
|
84
|
+
@pending_requests = {}
|
83
85
|
|
84
86
|
connect(&block)
|
85
87
|
end
|
@@ -106,7 +108,7 @@ module Net; module SFTP
|
|
106
108
|
# Initiates a download from +remote+ to +local+, asynchronously. This
|
107
109
|
# method will return a new Net::SFTP::Operations::Download instance, and requires
|
108
110
|
# that the event loop be run in order for the download to progress. See
|
109
|
-
# Net::SFTP::Operations::Download for a full discussion of
|
111
|
+
# Net::SFTP::Operations::Download for a full discussion of how this method can be
|
110
112
|
# used.
|
111
113
|
#
|
112
114
|
# download = sftp.download("/remote/path", "/local/path")
|
@@ -417,7 +419,7 @@ module Net; module SFTP
|
|
417
419
|
|
418
420
|
# :call-seq:
|
419
421
|
# readdir(handle) -> request
|
420
|
-
#
|
422
|
+
# readdir(handle) { |response| ... } -> request
|
421
423
|
#
|
422
424
|
# Reads a set of entries from the given directory handle (which must
|
423
425
|
# have been obtained via #opendir). If the response is EOF, then there
|
@@ -876,7 +878,7 @@ module Net; module SFTP
|
|
876
878
|
channel.on_close(&method(:when_channel_closed))
|
877
879
|
channel.on_process(&method(:when_channel_polled))
|
878
880
|
|
879
|
-
send_packet(FXP_INIT, :long, HIGHEST_PROTOCOL_VERSION_SUPPORTED)
|
881
|
+
send_packet(FXP_INIT, :long, @version || HIGHEST_PROTOCOL_VERSION_SUPPORTED)
|
880
882
|
end
|
881
883
|
|
882
884
|
# Called when the SSH server closes the underlying channel.
|
@@ -949,4 +951,4 @@ module Net; module SFTP
|
|
949
951
|
end
|
950
952
|
end
|
951
953
|
|
952
|
-
end; end
|
954
|
+
end; end
|
data/lib/net/sftp/version.rb
CHANGED
@@ -1,18 +1,68 @@
|
|
1
|
-
|
1
|
+
module Net
|
2
|
+
module SFTP
|
3
|
+
# A class for describing the current version of a library. The version
|
4
|
+
# consists of three parts: the +major+ number, the +minor+ number, and the
|
5
|
+
# +tiny+ (or +patch+) number.
|
6
|
+
#
|
7
|
+
# Two Version instances may be compared, so that you can test that a version
|
8
|
+
# of a library is what you require:
|
9
|
+
#
|
10
|
+
# require 'net/sftp/version'
|
11
|
+
#
|
12
|
+
# if Net::SFTP::Version::CURRENT < Net::SFTP::Version[2,1,0]
|
13
|
+
# abort "your software is too old!"
|
14
|
+
# end
|
15
|
+
class Version
|
16
|
+
include Comparable
|
2
17
|
|
3
|
-
|
18
|
+
# A convenience method for instantiating a new Version instance with the
|
19
|
+
# given +major+, +minor+, and +tiny+ components.
|
20
|
+
def self.[](major, minor, tiny, pre = nil)
|
21
|
+
new(major, minor, tiny, pre)
|
22
|
+
end
|
4
23
|
|
5
|
-
|
6
|
-
class Version < Net::SSH::Version
|
7
|
-
MAJOR = 2
|
8
|
-
MINOR = 1
|
9
|
-
TINY = 2
|
24
|
+
attr_reader :major, :minor, :tiny
|
10
25
|
|
11
|
-
|
12
|
-
|
26
|
+
# Create a new Version object with the given components.
|
27
|
+
def initialize(major, minor, tiny, pre = nil)
|
28
|
+
@major, @minor, @tiny, @pre = major, minor, tiny, pre
|
29
|
+
end
|
13
30
|
|
14
|
-
|
15
|
-
|
16
|
-
|
31
|
+
# Compare this version to the given +version+ object.
|
32
|
+
def <=>(version)
|
33
|
+
to_i <=> version.to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
# Converts this version object to a string, where each of the three
|
37
|
+
# version components are joined by the '.' character. E.g., 2.0.0.
|
38
|
+
def to_s
|
39
|
+
@to_s ||= [@major, @minor, @tiny, @pre].compact.join(".")
|
40
|
+
end
|
41
|
+
|
42
|
+
# Converts this version to a canonical integer that may be compared
|
43
|
+
# against other version objects.
|
44
|
+
def to_i
|
45
|
+
@to_i ||= @major * 1_000_000 + @minor * 1_000 + @tiny
|
46
|
+
end
|
47
|
+
|
48
|
+
# The major component of this version of the Net::SFTP library
|
49
|
+
MAJOR = 4
|
50
|
+
|
51
|
+
# The minor component of this version of the Net::SFTP library
|
52
|
+
MINOR = 0
|
17
53
|
|
18
|
-
|
54
|
+
# The tiny component of this version of the Net::SFTP library
|
55
|
+
TINY = 0
|
56
|
+
|
57
|
+
# The prerelease component of this version of the Net::SFTP library
|
58
|
+
# nil allowed
|
59
|
+
PRE = nil
|
60
|
+
|
61
|
+
# The current version of the Net::SFTP library as a Version instance
|
62
|
+
CURRENT = new(*[MAJOR, MINOR, TINY, PRE].compact)
|
63
|
+
|
64
|
+
# The current version of the Net::SFTP library as a String
|
65
|
+
STRING = CURRENT.to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/net/sftp.rb
CHANGED
@@ -27,9 +27,17 @@ module Net
|
|
27
27
|
# Net::SFTP.start("localhost", "user") do |sftp|
|
28
28
|
# sftp.upload! "/local/file.tgz", "/remote/file.tgz"
|
29
29
|
# end
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
#
|
31
|
+
# Extra parameters can be passed:
|
32
|
+
# - The Net::SSH connection options (see Net::SSH for more information)
|
33
|
+
# - The Net::SFTP connection options (only :version is supported, to let you
|
34
|
+
# set the SFTP protocol version to be used)
|
35
|
+
def self.start(host, user, ssh_options={}, sftp_options={}, &block)
|
36
|
+
session = Net::SSH.start(host, user, ssh_options)
|
37
|
+
# We only use a single option here, but this leaves room for more later
|
38
|
+
# without breaking the external API.
|
39
|
+
version = sftp_options.fetch(:version, nil)
|
40
|
+
sftp = Net::SFTP::Session.new(session, version, &block).connect!
|
33
41
|
|
34
42
|
if block_given?
|
35
43
|
sftp.loop
|
@@ -56,7 +64,7 @@ class Net::SSH::Connection::Session
|
|
56
64
|
# SSH session. Blocks until the SFTP session is fully open, and then
|
57
65
|
# returns the SFTP session.
|
58
66
|
#
|
59
|
-
# Net::SSH.start("localhost", "user", "password") do |ssh|
|
67
|
+
# Net::SSH.start("localhost", "user", :password => "password") do |ssh|
|
60
68
|
# ssh.sftp.upload!("/local/file.tgz", "/remote/file.tgz")
|
61
69
|
# ssh.exec! "cd /some/path && tar xf /remote/file.tgz && rm /remote/file.tgz"
|
62
70
|
# end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDQDCCAiigAwIBAgIBATANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDDBpuZXRz
|
3
|
+
c2gvREM9c29sdXRpb3VzL0RDPWNvbTAeFw0yMjA5MjIxMTUwMDJaFw0yMzA5MjIx
|
4
|
+
MTUwMDJaMCUxIzAhBgNVBAMMGm5ldHNzaC9EQz1zb2x1dGlvdXMvREM9Y29tMIIB
|
5
|
+
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxieE22fR/qmdPKUHyYTyUx2g
|
6
|
+
wskLwrCkxay+Tvc97ZZUOwf85LDDDPqhQaTWLvRwnIOMgQE2nBPzwalVclK6a+pW
|
7
|
+
x/18KDeZY15vm3Qn5p42b0wi9hUxOqPm3J2hdCLCcgtENgdX21nVzejn39WVqFJO
|
8
|
+
lntgSDNW5+kCS8QaRsmIbzj17GKKkrsw39kiQw7FhWfJFeTjddzoZiWwc59KA/Bx
|
9
|
+
fBbmDnsMLAtAtauMOxORrbx3EOY7sHku/kSrMg3FXFay7jc6BkbbUij+MjJ/k82l
|
10
|
+
4o8o0YO4BAnya90xgEmgOG0LCCxRhuXQFnMDuDjK2XnUe0h4/6NCn94C+z9GsQID
|
11
|
+
AQABo3sweTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUBfKiwO2e
|
12
|
+
M4NEiRrVG793qEPLYyMwHwYDVR0RBBgwFoEUbmV0c3NoQHNvbHV0aW91cy5jb20w
|
13
|
+
HwYDVR0SBBgwFoEUbmV0c3NoQHNvbHV0aW91cy5jb20wDQYJKoZIhvcNAQELBQAD
|
14
|
+
ggEBABI2ORK5kzUL7uOF0EHI4ECMWxQMiN+pURyGp9u7DU0H8eSdZN52jbUGHzSB
|
15
|
+
j7bB6GpqElEWjOe0IbH3vR52IVXq2bOF4P4vFchGAb4OuzJD8aJmrC/SPLHbWBuV
|
16
|
+
2GpbRQRJyYPWN6Rt/4EHOxoFnhXOBEB6CGIy0dt7YezycVbzqtHoiI2Qf/bIFJQZ
|
17
|
+
mpJAAUBkRiWksE7zrsE5DGK8kL2GVos7f8kdM71zT8p7VBwkMdY277T29TG2xD0D
|
18
|
+
66Oev0C3/x89NXqCHkl1JElSzEFbOoxan16z7xNEf2MKcBKGhsYfzWVNyEtJm785
|
19
|
+
g+97rn/AuO6dcxJnW2qBGYQa7pQ=
|
20
|
+
-----END CERTIFICATE-----
|