aspera-cli 4.24.2 → 4.25.0.pre
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +1064 -758
- data/CONTRIBUTING.md +43 -100
- data/README.md +671 -419
- data/lib/aspera/api/aoc.rb +71 -43
- data/lib/aspera/api/cos_node.rb +3 -2
- data/lib/aspera/api/faspex.rb +6 -5
- data/lib/aspera/api/node.rb +10 -12
- data/lib/aspera/ascmd.rb +1 -2
- data/lib/aspera/ascp/installation.rb +53 -39
- data/lib/aspera/assert.rb +25 -3
- data/lib/aspera/cli/error.rb +4 -2
- data/lib/aspera/cli/extended_value.rb +84 -60
- data/lib/aspera/cli/formatter.rb +55 -22
- data/lib/aspera/cli/main.rb +21 -14
- data/lib/aspera/cli/manager.rb +348 -247
- data/lib/aspera/cli/plugins/alee.rb +3 -3
- data/lib/aspera/cli/plugins/aoc.rb +70 -14
- data/lib/aspera/cli/plugins/base.rb +57 -49
- data/lib/aspera/cli/plugins/config.rb +69 -84
- data/lib/aspera/cli/plugins/console.rb +13 -8
- data/lib/aspera/cli/plugins/cos.rb +1 -1
- data/lib/aspera/cli/plugins/faspex.rb +32 -26
- data/lib/aspera/cli/plugins/faspex5.rb +45 -43
- data/lib/aspera/cli/plugins/faspio.rb +5 -5
- data/lib/aspera/cli/plugins/httpgw.rb +1 -1
- data/lib/aspera/cli/plugins/node.rb +131 -120
- data/lib/aspera/cli/plugins/oauth.rb +1 -1
- data/lib/aspera/cli/plugins/orchestrator.rb +114 -32
- data/lib/aspera/cli/plugins/preview.rb +26 -46
- data/lib/aspera/cli/plugins/server.rb +6 -8
- data/lib/aspera/cli/plugins/shares.rb +27 -32
- data/lib/aspera/cli/sync_actions.rb +49 -38
- data/lib/aspera/cli/transfer_agent.rb +16 -34
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +8 -5
- data/lib/aspera/command_line_builder.rb +20 -17
- data/lib/aspera/coverage.rb +1 -1
- data/lib/aspera/environment.rb +41 -34
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/keychain/factory.rb +1 -2
- data/lib/aspera/markdown.rb +31 -0
- data/lib/aspera/nagios.rb +6 -5
- data/lib/aspera/oauth/base.rb +17 -27
- data/lib/aspera/oauth/factory.rb +1 -1
- data/lib/aspera/oauth/url_json.rb +2 -1
- data/lib/aspera/preview/file_types.rb +23 -37
- data/lib/aspera/products/connect.rb +3 -3
- data/lib/aspera/rest.rb +51 -39
- data/lib/aspera/rest_error_analyzer.rb +4 -4
- data/lib/aspera/ssh.rb +5 -2
- data/lib/aspera/ssl.rb +41 -0
- data/lib/aspera/sync/conf.schema.yaml +182 -34
- data/lib/aspera/sync/database.rb +2 -1
- data/lib/aspera/sync/operations.rb +125 -69
- data/lib/aspera/transfer/parameters.rb +3 -4
- data/lib/aspera/transfer/spec.rb +2 -3
- data/lib/aspera/transfer/spec.schema.yaml +48 -18
- data/lib/aspera/transfer/spec_doc.rb +14 -14
- data/lib/aspera/uri_reader.rb +1 -1
- data/lib/transferd_pb.rb +2 -2
- data.tar.gz.sig +0 -0
- metadata +19 -6
- metadata.gz.sig +3 -2
data/lib/aspera/oauth/base.rb
CHANGED
|
@@ -59,25 +59,13 @@ module Aspera
|
|
|
59
59
|
|
|
60
60
|
attr_reader :scope, :api, :path_token, :client_id
|
|
61
61
|
|
|
62
|
-
#
|
|
62
|
+
# Helper method to create token as per RFC
|
|
63
|
+
# @return [HTTPResponse]
|
|
64
|
+
# @raise RestError if not 2XX code
|
|
63
65
|
def create_token_call(creation_params)
|
|
64
66
|
Log.log.debug{'Generating a new token'.bg_green}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
query: creation_params
|
|
68
|
-
}
|
|
69
|
-
else
|
|
70
|
-
{
|
|
71
|
-
content_type: Rest::MIME_WWW,
|
|
72
|
-
body: creation_params
|
|
73
|
-
}
|
|
74
|
-
end
|
|
75
|
-
return @api.call(
|
|
76
|
-
operation: 'POST',
|
|
77
|
-
subpath: @path_token,
|
|
78
|
-
headers: {'Accept' => Rest::MIME_JSON},
|
|
79
|
-
**payload
|
|
80
|
-
)
|
|
67
|
+
return @api.create(@path_token, nil, query: creation_params, ret: :resp) if @use_query
|
|
68
|
+
return @api.create(@path_token, creation_params, content_type: Rest::MIME_WWW, ret: :resp)
|
|
81
69
|
end
|
|
82
70
|
|
|
83
71
|
# @param add_secret [Boolean] Add secret in default call parameters
|
|
@@ -122,17 +110,18 @@ module Aspera
|
|
|
122
110
|
Factory.instance.persist_mgr.delete(@token_cache_id)
|
|
123
111
|
token_data = nil
|
|
124
112
|
# lets try the existing refresh token
|
|
113
|
+
# NOTE: AoC admin token has no refresh, and lives by default 1800secs
|
|
125
114
|
if !refresh_token.nil?
|
|
126
|
-
Log.log.info{"refresh=[#{refresh_token}]".bg_green}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
json_data = resp[:http].body
|
|
115
|
+
Log.log.info{"refresh token=[#{refresh_token}]".bg_green}
|
|
116
|
+
begin
|
|
117
|
+
http = create_token_call(optional_scope_client_id(add_secret: true).merge(grant_type: 'refresh_token', refresh_token: refresh_token))
|
|
118
|
+
# Save only if success
|
|
119
|
+
json_data = http.body
|
|
132
120
|
token_data = JSON.parse(json_data)
|
|
133
121
|
Factory.instance.persist_mgr.put(@token_cache_id, json_data)
|
|
134
|
-
|
|
135
|
-
|
|
122
|
+
rescue => e
|
|
123
|
+
# Refresh token can fail.
|
|
124
|
+
Log.log.warn{"Refresh failed: #{e}"}
|
|
136
125
|
end
|
|
137
126
|
end
|
|
138
127
|
end
|
|
@@ -140,8 +129,9 @@ module Aspera
|
|
|
140
129
|
|
|
141
130
|
# no cache, nor refresh: generate a token
|
|
142
131
|
if token_data.nil?
|
|
143
|
-
|
|
144
|
-
|
|
132
|
+
# Call the method-specific token creation
|
|
133
|
+
# which returns the result of create_token_call
|
|
134
|
+
json_data = create_token.body
|
|
145
135
|
token_data = JSON.parse(json_data)
|
|
146
136
|
Factory.instance.persist_mgr.put(@token_cache_id, json_data)
|
|
147
137
|
end
|
data/lib/aspera/oauth/factory.rb
CHANGED
|
@@ -156,7 +156,7 @@ module Aspera
|
|
|
156
156
|
def register_token_creator(creator_class)
|
|
157
157
|
Aspera.assert_type(creator_class, Class)
|
|
158
158
|
id = Factory.class_to_id(creator_class)
|
|
159
|
-
Log.log.debug{"registering
|
|
159
|
+
Log.log.debug{"registering creator for #{id}"}
|
|
160
160
|
@token_type_classes[id] = creator_class
|
|
161
161
|
end
|
|
162
162
|
|
|
@@ -25,7 +25,8 @@ module Aspera
|
|
|
25
25
|
query: @query.merge(scope: scope), # scope is here because it may change over time (node)
|
|
26
26
|
content_type: Rest::MIME_JSON,
|
|
27
27
|
body: @body,
|
|
28
|
-
headers: {'Accept' => Rest::MIME_JSON}
|
|
28
|
+
headers: {'Accept' => Rest::MIME_JSON},
|
|
29
|
+
ret: :resp
|
|
29
30
|
)
|
|
30
31
|
end
|
|
31
32
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require 'aspera/log'
|
|
4
4
|
require 'aspera/assert'
|
|
5
5
|
require 'singleton'
|
|
6
|
-
require '
|
|
6
|
+
require 'marcel'
|
|
7
7
|
|
|
8
8
|
module Aspera
|
|
9
9
|
module Preview
|
|
@@ -61,7 +61,7 @@ module Aspera
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
# @param mimetype [String] mime type
|
|
64
|
-
# @return file type, one of enum CONVERSION_TYPES, or nil if not found
|
|
64
|
+
# @return [NilClass,Symbol] file type, one of enum CONVERSION_TYPES, or nil if not found
|
|
65
65
|
def mime_to_type(mimetype)
|
|
66
66
|
Aspera.assert_type(mimetype, String)
|
|
67
67
|
return SUPPORTED_MIME_TYPES[mimetype] if SUPPORTED_MIME_TYPES.key?(mimetype)
|
|
@@ -72,19 +72,17 @@ module Aspera
|
|
|
72
72
|
return
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
# @param filepath [String]
|
|
76
|
-
# @param mimetype [String] provided by node API
|
|
75
|
+
# @param filepath [String] Full path to file
|
|
76
|
+
# @param mimetype [String] MIME typre provided by node API
|
|
77
77
|
# @return file type, one of enum CONVERSION_TYPES
|
|
78
78
|
# @raise [RuntimeError] if no conversion type found
|
|
79
79
|
def conversion_type(filepath, mimetype)
|
|
80
80
|
Log.log.debug{"conversion_type(#{filepath},mime=#{mimetype},magic=#{@use_mimemagic})"}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
mimetype
|
|
84
|
-
mimetype
|
|
85
|
-
|
|
86
|
-
mimetype ||= MIME::Types.of(File.basename(filepath)).first
|
|
87
|
-
raise "no MIME type found for #{File.basename(filepath)}" if mimetype.nil?
|
|
81
|
+
# Default type or empty means no type
|
|
82
|
+
mimetype = TYPE_NOT_FOUND if mimetype.nil? || (mimetype.is_a?(String) && mimetype.empty?)
|
|
83
|
+
mimetype = Marcel::MimeType.for(Pathname.new(filepath), name: File.basename(filepath), declared_type: mimetype)
|
|
84
|
+
mimetype = 'text/plain' if mimetype.eql?(TYPE_NOT_FOUND) && ascii_text_file?(filepath)
|
|
85
|
+
raise "no MIME type found for #{File.basename(filepath)}" if mimetype.eql?(TYPE_NOT_FOUND)
|
|
88
86
|
conversion_type = mime_to_type(mimetype)
|
|
89
87
|
raise "no conversion type found for #{File.basename(filepath)}" if conversion_type.nil?
|
|
90
88
|
Log.log.trace1{"conversion_type(#{File.basename(filepath)}): #{conversion_type.class.name} [#{conversion_type}]"}
|
|
@@ -93,33 +91,21 @@ module Aspera
|
|
|
93
91
|
|
|
94
92
|
private
|
|
95
93
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
# @return [String] mime type, or nil if not found
|
|
99
|
-
def mime_using_mimemagic(filepath)
|
|
100
|
-
return unless @use_mimemagic
|
|
101
|
-
# moved here, as `mimemagic` can cause installation issues
|
|
102
|
-
require 'mimemagic'
|
|
103
|
-
require 'mimemagic/version'
|
|
104
|
-
require 'mimemagic/overlay' if MimeMagic::VERSION.start_with?('0.3.')
|
|
105
|
-
# check magic number inside file (empty string if not found)
|
|
106
|
-
detected_mime = MimeMagic.by_magic(File.open(filepath)).to_s
|
|
107
|
-
# check extension only
|
|
108
|
-
if mime_to_type(detected_mime).nil?
|
|
109
|
-
Log.log.debug{"no conversion for #{detected_mime}, trying extension"}
|
|
110
|
-
detected_mime = MimeMagic.by_extension(File.extname(filepath)).to_s
|
|
111
|
-
end
|
|
112
|
-
detected_mime = nil if detected_mime.empty?
|
|
113
|
-
Log.log.debug{"mimemagic: #{detected_mime.class.name} [#{detected_mime}]"}
|
|
114
|
-
return detected_mime
|
|
115
|
-
end
|
|
94
|
+
TYPE_NOT_FOUND = 'application/octet-stream'
|
|
95
|
+
ACCEPT_CTRL_CHARS = [9, 10, 13]
|
|
116
96
|
|
|
117
|
-
#
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
97
|
+
# Returns true if the file looks like ASCII text (printable ASCII + \t, \r, \n, space).
|
|
98
|
+
# It reads only a small prefix (default: 64KB) and fails fast on the first bad byte.
|
|
99
|
+
def ascii_text_file?(path, sample_size: 64 * 1024)
|
|
100
|
+
File.open(path, 'rb') do |f|
|
|
101
|
+
sample = f.read(sample_size) || ''.b
|
|
102
|
+
sample.each_byte do |b|
|
|
103
|
+
next if b.between?(32, 126) || ACCEPT_CTRL_CHARS.include?(b)
|
|
104
|
+
# Any other control character => not ASCII text
|
|
105
|
+
return false
|
|
106
|
+
end
|
|
107
|
+
true
|
|
108
|
+
end
|
|
123
109
|
end
|
|
124
110
|
end
|
|
125
111
|
end
|
|
@@ -56,10 +56,10 @@ module Aspera
|
|
|
56
56
|
# Retrieve structure from cloud (CDN) with all versions available
|
|
57
57
|
def versions
|
|
58
58
|
if @connect_versions.nil?
|
|
59
|
-
|
|
59
|
+
http = cdn_api.read(VERSION_INFO_FILE, ret: :resp)
|
|
60
60
|
# get result on one line
|
|
61
|
-
connect_versions_javascript =
|
|
62
|
-
Log.
|
|
61
|
+
connect_versions_javascript = http.body.gsub(/\r?\n\s*/, '')
|
|
62
|
+
Log.dump(:javascript, connect_versions_javascript)
|
|
63
63
|
# get javascript object only
|
|
64
64
|
found = connect_versions_javascript.match(/^.*? = (.*);/)
|
|
65
65
|
raise Cli::Error, 'Problem when getting connect versions from internet' if found.nil?
|
data/lib/aspera/rest.rb
CHANGED
|
@@ -50,13 +50,13 @@ module Aspera
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
class EntityNotFound < Error
|
|
54
|
+
end
|
|
55
|
+
|
|
53
56
|
# a simple class to make HTTP calls, equivalent to rest-client
|
|
54
57
|
# rest call errors are raised as exception RestCallError
|
|
55
58
|
# and error are analyzed in RestErrorAnalyzer
|
|
56
59
|
class Rest
|
|
57
|
-
# Error message when entity not found (TODO: use specific exception)
|
|
58
|
-
ENTITY_NOT_FOUND = 'No such'
|
|
59
|
-
|
|
60
60
|
MIME_JSON = 'application/json'
|
|
61
61
|
MIME_WWW = 'application/x-www-form-urlencoded'
|
|
62
62
|
MIME_TEXT = 'text/plain'
|
|
@@ -71,7 +71,7 @@ module Aspera
|
|
|
71
71
|
def basic_authorization(user, pass); return "Basic #{Base64.strict_encode64("#{user}:#{pass}")}"; end
|
|
72
72
|
|
|
73
73
|
# Indicate that the given Hash query uses php style for array parameters
|
|
74
|
-
# a[]=1&a[]=2
|
|
74
|
+
# @param query [Hash] A key can have Array value and result will use PHP format: a[]=1&a[]=2
|
|
75
75
|
def php_style(query)
|
|
76
76
|
Aspera.assert_type(query, Hash){'query'}
|
|
77
77
|
query[:x_array_php_style] = true
|
|
@@ -300,14 +300,16 @@ module Aspera
|
|
|
300
300
|
end
|
|
301
301
|
|
|
302
302
|
# HTTP/S REST call
|
|
303
|
-
# @param operation
|
|
304
|
-
# @param subpath
|
|
305
|
-
# @param query
|
|
306
|
-
# @param content_type [String,nil] Type of body parameters (one of MIME_*) and serialization, else use headers
|
|
307
|
-
# @param body
|
|
308
|
-
# @param headers
|
|
309
|
-
# @param save_to_file (filepath)
|
|
310
|
-
# @param exception
|
|
303
|
+
# @param operation [String] HTTP operation (GET, POST, PUT, DELETE)
|
|
304
|
+
# @param subpath [String] subpath of REST API
|
|
305
|
+
# @param query [Hash] URL parameters
|
|
306
|
+
# @param content_type [String, nil] Type of body parameters (one of MIME_*) and serialization, else use headers
|
|
307
|
+
# @param body [Hash, String] body parameters
|
|
308
|
+
# @param headers [Hash] additional headers (override Content-Type)
|
|
309
|
+
# @param save_to_file [String, nil](filepath)
|
|
310
|
+
# @param exception [Bool] `true`, error raise exception
|
|
311
|
+
# @param ret [:data, :resp, :both] Tell to return only data, only http response, or both
|
|
312
|
+
# @return [Object, Array] only data, only http response, or both
|
|
311
313
|
def call(
|
|
312
314
|
operation:,
|
|
313
315
|
subpath: nil,
|
|
@@ -316,7 +318,8 @@ module Aspera
|
|
|
316
318
|
body: nil,
|
|
317
319
|
headers: nil,
|
|
318
320
|
save_to_file: nil,
|
|
319
|
-
exception: true
|
|
321
|
+
exception: true,
|
|
322
|
+
ret: :data
|
|
320
323
|
)
|
|
321
324
|
subpath = subpath.to_s if subpath.is_a?(Symbol)
|
|
322
325
|
subpath = '' if subpath.nil?
|
|
@@ -325,6 +328,8 @@ module Aspera
|
|
|
325
328
|
Log.dump(:query, query, level: :trace1)
|
|
326
329
|
Log.dump(:headers, headers, level: :trace1)
|
|
327
330
|
Aspera.assert_type(subpath, String)
|
|
331
|
+
# We must have a way to check return code
|
|
332
|
+
Aspera.assert(exception || !ret.eql?(:data))
|
|
328
333
|
if headers.nil?
|
|
329
334
|
headers = @headers.clone
|
|
330
335
|
else
|
|
@@ -348,7 +353,8 @@ module Aspera
|
|
|
348
353
|
end
|
|
349
354
|
else Aspera.error_unexpected_value(@auth_params[:type])
|
|
350
355
|
end
|
|
351
|
-
|
|
356
|
+
result_http = nil
|
|
357
|
+
result_data = nil
|
|
352
358
|
# start a block to be able to retry the actual HTTP request in case of OAuth token expiration
|
|
353
359
|
begin
|
|
354
360
|
# TODO: shall we percent encode subpath (spaces) test with access key delete with space in id
|
|
@@ -391,14 +397,14 @@ module Aspera
|
|
|
391
397
|
file_saved = false
|
|
392
398
|
# make http request (pipelined)
|
|
393
399
|
http_session.request(req) do |response|
|
|
394
|
-
|
|
395
|
-
result_mime = self.class.parse_header(
|
|
396
|
-
Log.log.debug{"response: code=#{
|
|
400
|
+
result_http = response
|
|
401
|
+
result_mime = self.class.parse_header(result_http['Content-Type'] || MIME_TEXT)[:type]
|
|
402
|
+
Log.log.debug{"response: code=#{result_http.code}, mime=#{result_mime}, mime2= #{response['Content-Type']}"}
|
|
397
403
|
# JSON data needs to be parsed, in case it contains an error code
|
|
398
404
|
if !save_to_file.nil? &&
|
|
399
|
-
|
|
405
|
+
result_http.code.to_s.start_with?('2') &&
|
|
400
406
|
!JSON_DECODE.include?(result_mime)
|
|
401
|
-
total_size =
|
|
407
|
+
total_size = result_http['Content-Length']&.to_i
|
|
402
408
|
Log.log.debug('before write file')
|
|
403
409
|
target_file = save_to_file
|
|
404
410
|
# override user's path to path in header
|
|
@@ -416,7 +422,7 @@ module Aspera
|
|
|
416
422
|
FileUtils.mkdir_p(File.dirname(target_file_tmp))
|
|
417
423
|
limiter = TimerLimiter.new(0.5)
|
|
418
424
|
File.open(target_file_tmp, 'wb') do |file|
|
|
419
|
-
|
|
425
|
+
result_http.read_body do |fragment|
|
|
420
426
|
file.write(fragment)
|
|
421
427
|
written_size += fragment.length
|
|
422
428
|
RestParameters.instance.progress_bar&.event(:transfer, session_id: session_id, info: written_size) if limiter.trigger?
|
|
@@ -429,32 +435,32 @@ module Aspera
|
|
|
429
435
|
file_saved = true
|
|
430
436
|
end
|
|
431
437
|
end
|
|
432
|
-
Log.log.debug{"result: code=#{
|
|
438
|
+
Log.log.debug{"result: code=#{result_http.code} mime=#{result_mime}"}
|
|
433
439
|
# sometimes there is a UTF8 char (e.g. (c) ), TODO : related to mime type encoding ?
|
|
434
|
-
#
|
|
435
|
-
# Log.log.debug{"result: body=#{
|
|
440
|
+
# result_http.body.force_encoding('UTF-8') if result_http.body.is_a?(String)
|
|
441
|
+
# Log.log.debug{"result: body=#{result_http.body}"}
|
|
436
442
|
case result_mime
|
|
437
443
|
when *JSON_DECODE
|
|
438
|
-
|
|
439
|
-
Log.dump(:result_data,
|
|
444
|
+
result_data = JSON.parse(result_http.body) rescue result_http.body
|
|
445
|
+
Log.dump(:result_data, result_data)
|
|
440
446
|
else # when MIME_TEXT
|
|
441
|
-
|
|
447
|
+
result_data = result_http.body
|
|
442
448
|
end
|
|
443
|
-
RestErrorAnalyzer.instance.raise_on_error(req,
|
|
449
|
+
RestErrorAnalyzer.instance.raise_on_error(req, result_data, result_http)
|
|
444
450
|
unless file_saved || save_to_file.nil?
|
|
445
451
|
FileUtils.mkdir_p(File.dirname(save_to_file))
|
|
446
|
-
File.write(save_to_file,
|
|
452
|
+
File.write(save_to_file, result_http.body, binmode: true)
|
|
447
453
|
end
|
|
448
454
|
rescue RestCallError => e
|
|
449
455
|
do_retry = false
|
|
450
456
|
# AoC have some timeout , like Connect to platform.bss.asperasoft.com:443 ...
|
|
451
457
|
do_retry ||= true if e.response.body.include?('failed: connect timed out') && RestParameters.instance.retry_on_timeout
|
|
452
458
|
# AoC sometimes not available
|
|
453
|
-
do_retry ||= true if RestParameters.instance.retry_on_unavailable && UNAVAILABLE_CODES.include?(
|
|
459
|
+
do_retry ||= true if RestParameters.instance.retry_on_unavailable && UNAVAILABLE_CODES.include?(result_http.code.to_s)
|
|
454
460
|
# possibility to retry anything if it fails
|
|
455
461
|
do_retry ||= true if RestParameters.instance.retry_on_error
|
|
456
462
|
# not authorized: oauth token expired
|
|
457
|
-
if @not_auth_codes.include?(
|
|
463
|
+
if @not_auth_codes.include?(result_http.code.to_s) && @auth_params[:type].eql?(:oauth2)
|
|
458
464
|
begin
|
|
459
465
|
# try to use refresh token
|
|
460
466
|
req['Authorization'] = oauth.authorization(refresh: true)
|
|
@@ -494,14 +500,20 @@ module Aspera
|
|
|
494
500
|
content_type: content_type,
|
|
495
501
|
save_to_file: save_to_file,
|
|
496
502
|
exception: exception,
|
|
497
|
-
headers: headers
|
|
503
|
+
headers: headers,
|
|
504
|
+
ret: ret
|
|
498
505
|
)
|
|
499
506
|
end
|
|
500
507
|
# raise exception if could not retry and not return error in result
|
|
501
508
|
raise e if exception
|
|
502
509
|
end
|
|
503
|
-
Log.log.debug{"result=http:#{
|
|
504
|
-
return
|
|
510
|
+
Log.log.debug{"result=http:#{result_http}, data:#{result_data.class}"}
|
|
511
|
+
return case ret
|
|
512
|
+
when :data then result_data
|
|
513
|
+
when :resp then result_http
|
|
514
|
+
when :both then [result_data, result_http]
|
|
515
|
+
else Aspera.error_unexpected_value(ret){'Type of result for REST'}
|
|
516
|
+
end
|
|
505
517
|
end
|
|
506
518
|
|
|
507
519
|
#
|
|
@@ -511,27 +523,27 @@ module Aspera
|
|
|
511
523
|
|
|
512
524
|
# Create: `POST`
|
|
513
525
|
def create(subpath, params, **kwargs)
|
|
514
|
-
return call(operation: 'POST', subpath: subpath, headers: {'Accept' => MIME_JSON}, body: params, content_type: MIME_JSON, **kwargs)
|
|
526
|
+
return call(operation: 'POST', subpath: subpath, headers: {'Accept' => MIME_JSON}, body: params, content_type: MIME_JSON, **kwargs)
|
|
515
527
|
end
|
|
516
528
|
|
|
517
529
|
# Read: `GET`
|
|
518
530
|
def read(subpath, query = nil, **kwargs)
|
|
519
|
-
return call(operation: 'GET', subpath: subpath, headers: {'Accept' => MIME_JSON}, query: query, **kwargs)
|
|
531
|
+
return call(operation: 'GET', subpath: subpath, headers: {'Accept' => MIME_JSON}, query: query, **kwargs)
|
|
520
532
|
end
|
|
521
533
|
|
|
522
534
|
# Update: `PUT`
|
|
523
535
|
def update(subpath, params, **kwargs)
|
|
524
|
-
return call(operation: 'PUT', subpath: subpath, headers: {'Accept' => MIME_JSON}, body: params, content_type: MIME_JSON, **kwargs)
|
|
536
|
+
return call(operation: 'PUT', subpath: subpath, headers: {'Accept' => MIME_JSON}, body: params, content_type: MIME_JSON, **kwargs)
|
|
525
537
|
end
|
|
526
538
|
|
|
527
539
|
# Delete: `DELETE`
|
|
528
540
|
def delete(subpath, params = nil, **kwargs)
|
|
529
|
-
return call(operation: 'DELETE', subpath: subpath, headers: {'Accept' => MIME_JSON}, query: params, **kwargs)
|
|
541
|
+
return call(operation: 'DELETE', subpath: subpath, headers: {'Accept' => MIME_JSON}, query: params, **kwargs)
|
|
530
542
|
end
|
|
531
543
|
|
|
532
544
|
# Cancel: `CANCEL`
|
|
533
545
|
def cancel(subpath, **kwargs)
|
|
534
|
-
return call(operation: 'CANCEL', subpath: subpath, headers: {'Accept' => MIME_JSON}, **kwargs)
|
|
546
|
+
return call(operation: 'CANCEL', subpath: subpath, headers: {'Accept' => MIME_JSON}, **kwargs)
|
|
535
547
|
end
|
|
536
548
|
|
|
537
549
|
# Query entity by general search (read with parameter `q`)
|
|
@@ -549,7 +561,7 @@ module Aspera
|
|
|
549
561
|
Aspera.assert_type(matching_items, Array)
|
|
550
562
|
case matching_items.length
|
|
551
563
|
when 1 then return matching_items.first
|
|
552
|
-
when 0 then raise %Q{
|
|
564
|
+
when 0 then raise EntityNotFound, %Q{No such #{subpath}: "#{search_name}"}
|
|
553
565
|
else
|
|
554
566
|
# multiple case insensitive partial matches, try case insensitive full match
|
|
555
567
|
# (anyway AoC does not allow creation of 2 entities with same case insensitive name)
|
|
@@ -27,13 +27,13 @@ module Aspera
|
|
|
27
27
|
# Use this method to analyze a EST result and raise an exception
|
|
28
28
|
# Analyzes REST call response and raises a RestCallError exception
|
|
29
29
|
# if HTTP result code is not 2XX
|
|
30
|
-
def raise_on_error(req,
|
|
31
|
-
Log.log.debug{"raise_on_error #{req.method} #{req.path} #{
|
|
30
|
+
def raise_on_error(req, data, http)
|
|
31
|
+
Log.log.debug{"raise_on_error #{req.method} #{req.path} #{http.code}"}
|
|
32
32
|
call_context = {
|
|
33
33
|
messages: [],
|
|
34
34
|
request: req,
|
|
35
|
-
response:
|
|
36
|
-
data:
|
|
35
|
+
response: http,
|
|
36
|
+
data: data
|
|
37
37
|
}
|
|
38
38
|
# multiple error messages can be found
|
|
39
39
|
# analyze errors from provided handlers
|
data/lib/aspera/ssh.rb
CHANGED
|
@@ -11,6 +11,7 @@ module Aspera
|
|
|
11
11
|
class Error < Aspera::Error
|
|
12
12
|
end
|
|
13
13
|
class << self
|
|
14
|
+
# HACK: disable some key type
|
|
14
15
|
def disable_ed25519_keys
|
|
15
16
|
Log.log.debug('Disabling SSH ed25519 user keys')
|
|
16
17
|
old_verbose = $VERBOSE
|
|
@@ -24,6 +25,7 @@ module Aspera
|
|
|
24
25
|
$VERBOSE = old_verbose
|
|
25
26
|
end
|
|
26
27
|
|
|
28
|
+
# HACK: disable some algorithms
|
|
27
29
|
def disable_ecd_sha2_algorithms
|
|
28
30
|
Log.log.debug('Disabling SSH ecdsa')
|
|
29
31
|
Net::SSH::Transport::Algorithms::ALGORITHMS.each_value{ |a| a.reject!{ |a| a =~ /^ecd(sa|h)-sha2/}}
|
|
@@ -38,6 +40,7 @@ module Aspera
|
|
|
38
40
|
Aspera.assert_type(host, String)
|
|
39
41
|
Aspera.assert_type(username, String)
|
|
40
42
|
Aspera.assert_type(ssh_options, Hash)
|
|
43
|
+
ssh_options[:use_agent] = false unless ssh_options.key?(:use_agent)
|
|
41
44
|
@host = host
|
|
42
45
|
@username = username
|
|
43
46
|
@ssh_options = ssh_options
|
|
@@ -62,7 +65,7 @@ module Aspera
|
|
|
62
65
|
exit_code = data.read_long
|
|
63
66
|
next if exit_code.zero?
|
|
64
67
|
error_message = "#{cmd}: exit #{exit_code}, #{error.join.chomp}"
|
|
65
|
-
raise Error, error_message if
|
|
68
|
+
raise Error, error_message if exception
|
|
66
69
|
# Happens when windows user hasn't logged in and created home account.
|
|
67
70
|
error_message += "\nHint: home not created in Windows?" if data.include?('Could not chdir to home directory')
|
|
68
71
|
Log.log.debug(error_message)
|
|
@@ -82,5 +85,5 @@ module Aspera
|
|
|
82
85
|
end
|
|
83
86
|
|
|
84
87
|
# Deactivate ed25519 and ecdsa private keys from SSH identities, as it usually causes problems
|
|
85
|
-
Aspera::Ssh.disable_ed25519_keys if Gem::Specification.find_all_by_name('ed25519').none?
|
|
88
|
+
Aspera::Ssh.disable_ed25519_keys if Gem::Specification.find_all_by_name('ed25519').none? || ENV.fetch('ASCLI_ENABLE_ED25519', 'true').eql?('false')
|
|
86
89
|
Aspera::Ssh.disable_ecd_sha2_algorithms if defined?(JRUBY_VERSION) && ENV.fetch('ASCLI_ENABLE_ECDSHA2', 'false').eql?('false')
|
data/lib/aspera/ssl.rb
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'openssl'
|
|
4
|
+
require 'aspera/assert'
|
|
5
|
+
require 'aspera/log'
|
|
6
|
+
|
|
7
|
+
module Aspera
|
|
8
|
+
# Give possibility to globally override SSL options
|
|
9
|
+
module SSL
|
|
10
|
+
@extra_options = 0
|
|
11
|
+
class << self
|
|
12
|
+
@extra_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
|
|
13
|
+
attr_reader :extra_options
|
|
14
|
+
|
|
15
|
+
def option_list=(v)
|
|
16
|
+
Aspera.assert_type(v, Array){'ssl_options'}
|
|
17
|
+
v.each do |opt|
|
|
18
|
+
Aspera.assert_type(opt, String, Integer){'Expected String or Integer in ssl_options'}
|
|
19
|
+
case opt
|
|
20
|
+
when Integer
|
|
21
|
+
@extra_options = opt
|
|
22
|
+
when String
|
|
23
|
+
name = "OP_#{opt.start_with?('-') ? opt[1..] : opt}".upcase
|
|
24
|
+
raise Cli::BadArgument, "Unknown ssl_option: #{name}, use one of: #{OpenSSL::SSL.constants.grep(/^OP_/).map{ |c| c.to_s.sub(/^OP_/, '')}.join(', ')}" if !OpenSSL::SSL.const_defined?(name)
|
|
25
|
+
if opt.start_with?('-')
|
|
26
|
+
@extra_options &= ~OpenSSL::SSL.const_get(name)
|
|
27
|
+
else
|
|
28
|
+
@extra_options |= OpenSSL::SSL.const_get(name)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
def set_params(params = {})
|
|
35
|
+
super(params)
|
|
36
|
+
self.options = Aspera::SSL.extra_options unless Aspera::SSL.extra_options.nil?
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
OpenSSL::SSL::SSLContext.prepend(Aspera::SSL)
|