aspera-cli 4.18.1 → 4.19.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +13 -0
- data/CONTRIBUTING.md +5 -12
- data/README.md +60 -29
- data/examples/build_exec +85 -0
- data/lib/aspera/agent/base.rb +2 -0
- data/lib/aspera/agent/direct.rb +108 -104
- data/lib/aspera/api/aoc.rb +2 -2
- data/lib/aspera/api/httpgw.rb +91 -56
- data/lib/aspera/ascp/installation.rb +47 -32
- data/lib/aspera/ascp/management.rb +4 -1
- data/lib/aspera/ascp/products.rb +1 -7
- data/lib/aspera/cli/formatter.rb +24 -18
- data/lib/aspera/cli/manager.rb +10 -10
- data/lib/aspera/cli/plugin.rb +2 -2
- data/lib/aspera/cli/plugin_factory.rb +10 -1
- data/lib/aspera/cli/plugins/config.rb +15 -10
- data/lib/aspera/cli/plugins/node.rb +4 -3
- data/lib/aspera/cli/plugins/server.rb +1 -1
- data/lib/aspera/cli/plugins/shares.rb +11 -7
- data/lib/aspera/cli/sync_actions.rb +72 -31
- data/lib/aspera/cli/transfer_agent.rb +1 -0
- data/lib/aspera/cli/transfer_progress.rb +1 -1
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +43 -10
- data/lib/aspera/faspex_gw.rb +1 -1
- data/lib/aspera/keychain/encrypted_hash.rb +2 -0
- data/lib/aspera/log.rb +1 -0
- data/lib/aspera/node_simulator.rb +1 -1
- data/lib/aspera/oauth/jwt.rb +1 -1
- data/lib/aspera/oauth/url_json.rb +2 -0
- data/lib/aspera/oauth/web.rb +5 -4
- data/lib/aspera/secret_hider.rb +3 -2
- data/lib/aspera/ssh.rb +1 -1
- data/lib/aspera/transfer/faux_file.rb +7 -5
- data/lib/aspera/transfer/parameters.rb +27 -19
- data/lib/aspera/transfer/spec.rb +8 -10
- data/lib/aspera/transfer/sync.rb +52 -47
- data/lib/aspera/web_auth.rb +0 -1
- data/lib/aspera/web_server_simple.rb +24 -13
- data.tar.gz.sig +0 -0
- metadata +3 -3
- metadata.gz.sig +0 -0
- data/examples/rubyc +0 -24
@@ -7,11 +7,30 @@ module Aspera
|
|
7
7
|
module Cli
|
8
8
|
# Module for sync actions
|
9
9
|
module SyncActions
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
# optional simple command line arguments for sync
|
11
|
+
# in Array to keep option order
|
12
|
+
# conf: key in option --conf
|
13
|
+
# args: key for command line args
|
14
|
+
# values: possible values for argument
|
15
|
+
# type: type for validation
|
16
|
+
SYNC_ARGUMENTS_INFO = [
|
17
|
+
{
|
18
|
+
conf: 'direction',
|
19
|
+
args: 'direction',
|
20
|
+
values: Transfer::Sync::DIRECTIONS
|
21
|
+
}, {
|
22
|
+
conf: 'remote.path',
|
23
|
+
args: 'remote_dir',
|
24
|
+
type: String
|
25
|
+
}, {
|
26
|
+
conf: 'local.path',
|
27
|
+
args: 'local_dir',
|
28
|
+
type: String
|
29
|
+
}
|
30
|
+
].freeze
|
31
|
+
# name of minimal arguments required, also used to generate a session name
|
32
|
+
SYNC_SIMPLE_ARGS = SYNC_ARGUMENTS_INFO.map{|i|i[:conf]}.freeze
|
33
|
+
private_constant :SYNC_ARGUMENTS_INFO, :SYNC_SIMPLE_ARGS
|
15
34
|
|
16
35
|
class << self
|
17
36
|
def declare_options(options)
|
@@ -19,38 +38,60 @@ module Aspera
|
|
19
38
|
end
|
20
39
|
end
|
21
40
|
|
41
|
+
# Read command line arguments (3) and converts to sync_info format
|
42
|
+
def sync_args_to_params(async_params)
|
43
|
+
# sync session parameters can be provided on command line instead of sync_info
|
44
|
+
arguments = {}
|
45
|
+
SYNC_ARGUMENTS_INFO.each do |info|
|
46
|
+
value = options.get_next_argument(
|
47
|
+
info[:conf],
|
48
|
+
mandatory: false,
|
49
|
+
validation: info[:type],
|
50
|
+
accept_list: info[:values])
|
51
|
+
break if value.nil?
|
52
|
+
arguments[info[:conf]] = value.to_s
|
53
|
+
end
|
54
|
+
Log.log.debug{Log.dump('arguments', arguments)}
|
55
|
+
raise Cli::BadArgument, "Provide 0 or 3 arguments, not #{arguments.keys.length} for: #{SYNC_SIMPLE_ARGS.join(', ')}" unless
|
56
|
+
[0, 3].include?(arguments.keys.length)
|
57
|
+
if !arguments.empty?
|
58
|
+
session_info = async_params
|
59
|
+
param_path = :conf
|
60
|
+
if async_params.key?('sessions') || async_params.key?('instance')
|
61
|
+
async_params['sessions'] ||= [{}]
|
62
|
+
Aspera.assert(async_params['sessions'].length == 1){'Only one session is supported with arguments'}
|
63
|
+
session_info = async_params['sessions'][0]
|
64
|
+
param_path = :args
|
65
|
+
end
|
66
|
+
SYNC_ARGUMENTS_INFO.each do |info|
|
67
|
+
key_path = info[param_path].split('.')
|
68
|
+
hash_for_key = session_info
|
69
|
+
if key_path.length > 1
|
70
|
+
first = key_path.shift
|
71
|
+
async_params[first] ||= {}
|
72
|
+
hash_for_key = async_params[first]
|
73
|
+
end
|
74
|
+
raise "Parameter #{info[:conf]} is also set in sync_info, remove from sync_info" if hash_for_key.key?(key_path.last)
|
75
|
+
hash_for_key[key_path.last] = arguments[info[:conf]]
|
76
|
+
end
|
77
|
+
if !session_info.key?('name')
|
78
|
+
# if no name is specified, generate one from simple arguments
|
79
|
+
session_info['name'] = SYNC_SIMPLE_ARGS.map do |arg_name|
|
80
|
+
arguments[arg_name]&.gsub(/[^a-zA-Z0-9]/, '')
|
81
|
+
end.compact.reject(&:empty?).join('_')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
22
86
|
def execute_sync_action(&block)
|
23
87
|
Aspera.assert(block){'No block given'}
|
24
88
|
command = options.get_next_command(%i[start admin])
|
25
89
|
# try to get 3 arguments as simple arguments
|
26
90
|
case command
|
27
91
|
when :start
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
arg,
|
32
|
-
mandatory: false,
|
33
|
-
validation: check.is_a?(Class) ? check : nil,
|
34
|
-
accept_list: check.is_a?(Class) ? nil : check)
|
35
|
-
break if value.nil?
|
36
|
-
simple_session_args[arg] = value.to_s
|
37
|
-
end
|
38
|
-
async_params = nil
|
39
|
-
if simple_session_args.empty?
|
40
|
-
async_params = options.get_option(:sync_info, mandatory: true)
|
41
|
-
else
|
42
|
-
raise Cli::BadArgument,
|
43
|
-
"Provide zero or 3 arguments: #{SIMPLE_ARGUMENTS_SYNC.keys.join(',')}" unless simple_session_args.keys.sort == SIMPLE_ARGUMENTS_SYNC.keys.sort
|
44
|
-
async_params = options.get_option(
|
45
|
-
:sync_info,
|
46
|
-
mandatory: false,
|
47
|
-
default: {'sessions' => [{'name' => File.basename(simple_session_args['local_dir'])}]})
|
48
|
-
Aspera.assert_type(async_params, Hash){'sync_info'}
|
49
|
-
Aspera.assert_type(async_params['sessions'], Array){'sync_info[sessions]'}
|
50
|
-
Aspera.assert_type(async_params['sessions'].first, Hash){'sync_info[sessions][0]'}
|
51
|
-
async_params['sessions'].first.merge!(simple_session_args)
|
52
|
-
end
|
53
|
-
Log.log.debug{Log.dump('async_params', async_params)}
|
92
|
+
# possibilities are:
|
93
|
+
async_params = options.get_option(:sync_info, default: {})
|
94
|
+
sync_args_to_params(async_params)
|
54
95
|
Transfer::Sync.start(async_params, &block)
|
55
96
|
return Main.result_success
|
56
97
|
when :admin
|
@@ -116,6 +116,7 @@ module Aspera
|
|
116
116
|
# by default do not display ascp native progress bar
|
117
117
|
agent_options[:quiet] = true unless agent_options.key?(:quiet)
|
118
118
|
agent_options[:check_ignore_cb] = ->(host, port){@config.ignore_cert?(host, port)}
|
119
|
+
# JRuby
|
119
120
|
agent_options[:trusted_certs] = @config.trusted_cert_locations unless agent_options.key?(:trusted_certs)
|
120
121
|
when :httpgw
|
121
122
|
unless agent_options.key?(:url) || @httpgw_url_lambda.nil?
|
@@ -25,7 +25,7 @@ module Aspera
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def event(session_id:, type:, info: nil)
|
28
|
-
Log.log.
|
28
|
+
Log.log.trace1{"progress: #{type} #{session_id} #{info}"}
|
29
29
|
Aspera.assert(!session_id.nil? || type.eql?(:pre_start)){'session_id is nil'}
|
30
30
|
return if @completed
|
31
31
|
if @progress_bar.nil?
|
data/lib/aspera/cli/version.rb
CHANGED
data/lib/aspera/environment.rb
CHANGED
@@ -5,6 +5,7 @@ require 'aspera/log'
|
|
5
5
|
require 'aspera/assert'
|
6
6
|
require 'rbconfig'
|
7
7
|
require 'singleton'
|
8
|
+
require 'English'
|
8
9
|
|
9
10
|
# cspell:words MEBI mswin bccwin
|
10
11
|
|
@@ -31,7 +32,6 @@ module Aspera
|
|
31
32
|
BYTES_PER_MEBIBIT = MEBI / BITS_PER_BYTE
|
32
33
|
|
33
34
|
class << self
|
34
|
-
@terminal_supports_unicode = nil
|
35
35
|
def ruby_version
|
36
36
|
return RbConfig::CONFIG['RUBY_PROGRAM_VERSION']
|
37
37
|
end
|
@@ -66,10 +66,13 @@ module Aspera
|
|
66
66
|
raise "Unknown CPU: #{RbConfig::CONFIG['host_cpu']}"
|
67
67
|
end
|
68
68
|
|
69
|
+
# normalized architecture name
|
70
|
+
# see constants: OS_* and CPU_*
|
69
71
|
def architecture
|
70
72
|
return "#{os}-#{cpu}"
|
71
73
|
end
|
72
74
|
|
75
|
+
# executable file extension for current OS
|
73
76
|
def exe_extension
|
74
77
|
return '.exe' if os.eql?(OS_WINDOWS)
|
75
78
|
return ''
|
@@ -83,6 +86,7 @@ module Aspera
|
|
83
86
|
Log.log.debug{"Windows: set HOME to USERPROFILE: #{Dir.home}"}
|
84
87
|
end
|
85
88
|
|
89
|
+
# empty variable binding for secure eval
|
86
90
|
def empty_binding
|
87
91
|
return Kernel.binding
|
88
92
|
end
|
@@ -92,7 +96,29 @@ module Aspera
|
|
92
96
|
Kernel.send('lave'.reverse, code, empty_binding, file, line)
|
93
97
|
end
|
94
98
|
|
95
|
-
#
|
99
|
+
# start process in background, or raise exception
|
100
|
+
# caller can call Process.wait on returned value
|
101
|
+
def secure_spawn(env:, exec:, args:, log_only: false)
|
102
|
+
Log.log.debug do
|
103
|
+
[
|
104
|
+
'execute:'.red,
|
105
|
+
env.map{|k, v| "#{k}=#{Shellwords.shellescape(v)}"},
|
106
|
+
Shellwords.shellescape(exec),
|
107
|
+
args.map{|a|Shellwords.shellescape(a)}
|
108
|
+
].flatten.join(' ')
|
109
|
+
end
|
110
|
+
return if log_only
|
111
|
+
# start ascp in separate process
|
112
|
+
ascp_pid = Process.spawn(env, [exec, exec], *args, close_others: true)
|
113
|
+
Log.log.debug{"pid: #{ascp_pid}"}
|
114
|
+
return ascp_pid
|
115
|
+
end
|
116
|
+
|
117
|
+
# Write content to a file, with restricted access
|
118
|
+
# @param path [String] the file path
|
119
|
+
# @param force [Boolean] if true, overwrite the file
|
120
|
+
# @param mode [Integer] the file mode (permissions)
|
121
|
+
# @block [Proc] return the content to write to the file
|
96
122
|
def write_file_restricted(path, force: false, mode: nil)
|
97
123
|
Aspera.assert(block_given?, exception_class: Aspera::InternalError)
|
98
124
|
if force || !File.exist?(path)
|
@@ -105,6 +131,7 @@ module Aspera
|
|
105
131
|
return path
|
106
132
|
end
|
107
133
|
|
134
|
+
# restrict access to a file or folder to user only
|
108
135
|
def restrict_file_access(path, mode: nil)
|
109
136
|
if mode.nil?
|
110
137
|
# or FileUtils ?
|
@@ -121,18 +148,12 @@ module Aspera
|
|
121
148
|
Log.log.warn(e.message)
|
122
149
|
end
|
123
150
|
|
151
|
+
# @return true if we are in a terminal
|
124
152
|
def terminal?
|
125
153
|
$stdout.tty?
|
126
154
|
end
|
127
155
|
|
128
|
-
# @return
|
129
|
-
# https://www.gnu.org/software/libc/manual/html_node/Locale-Categories.html
|
130
|
-
# https://pubs.opengroup.org/onlinepubs/7908799/xbd/envvar.html
|
131
|
-
def terminal_supports_unicode?
|
132
|
-
@terminal_supports_unicode = terminal? && %w(LC_ALL LC_CTYPE LANG).any?{|var|ENV[var]&.include?('UTF-8')} if @terminal_supports_unicode.nil?
|
133
|
-
return @terminal_supports_unicode
|
134
|
-
end
|
135
|
-
|
156
|
+
# @return :text or :graphical depending on the environment
|
136
157
|
def default_gui_mode
|
137
158
|
# assume not remotely connected on macos and windows
|
138
159
|
return :graphical if [Environment::OS_WINDOWS, Environment::OS_MACOS].include?(Environment.os)
|
@@ -141,6 +162,7 @@ module Aspera
|
|
141
162
|
return :text
|
142
163
|
end
|
143
164
|
|
165
|
+
# open a URI in a graphical browser
|
144
166
|
# command must be non blocking
|
145
167
|
def open_uri_graphical(uri)
|
146
168
|
case Environment.os
|
@@ -152,6 +174,7 @@ module Aspera
|
|
152
174
|
end
|
153
175
|
end
|
154
176
|
|
177
|
+
# open a file in an editor
|
155
178
|
def open_editor(file_path)
|
156
179
|
if ENV.key?('EDITOR')
|
157
180
|
system(ENV['EDITOR'], file_path.to_s)
|
@@ -166,8 +189,18 @@ module Aspera
|
|
166
189
|
|
167
190
|
def initialize
|
168
191
|
@url_method = self.class.default_gui_mode
|
192
|
+
@terminal_supports_unicode = nil
|
169
193
|
end
|
170
194
|
|
195
|
+
# @return true if we can display Unicode characters
|
196
|
+
# https://www.gnu.org/software/libc/manual/html_node/Locale-Categories.html
|
197
|
+
# https://pubs.opengroup.org/onlinepubs/7908799/xbd/envvar.html
|
198
|
+
def terminal_supports_unicode?
|
199
|
+
@terminal_supports_unicode = self.class.terminal? && %w(LC_ALL LC_CTYPE LANG).any?{|var|ENV[var]&.include?('UTF-8')} if @terminal_supports_unicode.nil?
|
200
|
+
return @terminal_supports_unicode
|
201
|
+
end
|
202
|
+
|
203
|
+
|
171
204
|
# Allows a user to open a Url
|
172
205
|
# if method is "text", then URL is displayed on terminal
|
173
206
|
# if method is "graphical", then the URL will be opened with the default browser.
|
data/lib/aspera/faspex_gw.rb
CHANGED
@@ -29,7 +29,7 @@ module Aspera
|
|
29
29
|
'recipients' => faspex_pkg_delivery['recipients'],
|
30
30
|
'workspace_id' => @app_context
|
31
31
|
}
|
32
|
-
created_package = @app_api.create_package_simple(package_data, true,
|
32
|
+
created_package = @app_api.create_package_simple(package_data, true, nil)
|
33
33
|
# but we place it in a Faspex package creation response
|
34
34
|
return {
|
35
35
|
'links' => { 'status' => 'unused' },
|
@@ -16,10 +16,12 @@ module Aspera
|
|
16
16
|
FILE_TYPE = 'encrypted_hash_vault'
|
17
17
|
CONTENT_KEYS = %i[label username password url description].freeze
|
18
18
|
FILE_KEYS = %w[version type cipher data].sort.freeze
|
19
|
+
private_constant :LEGACY_CIPHER_NAME, :DEFAULT_CIPHER_NAME, :FILE_TYPE, :CONTENT_KEYS, :FILE_KEYS
|
19
20
|
def initialize(path, current_password)
|
20
21
|
Aspera.assert_type(path, String){'path to vault file'}
|
21
22
|
@path = path
|
22
23
|
@all_secrets = {}
|
24
|
+
@cipher_name = DEFAULT_CIPHER_NAME
|
23
25
|
vault_encrypted_data = nil
|
24
26
|
if File.exist?(@path)
|
25
27
|
vault_file = File.read(@path)
|
data/lib/aspera/log.rb
CHANGED
@@ -39,7 +39,7 @@ module Aspera
|
|
39
39
|
set_json_response(response, {
|
40
40
|
application: 'node',
|
41
41
|
current_time: Time.now.utc.iso8601(0),
|
42
|
-
version: info['
|
42
|
+
version: info['sdk_ascp_version'].gsub(/ .*$/, ''),
|
43
43
|
license_expiration_date: info['expiration_date'],
|
44
44
|
license_max_rate: info['maximum_bandwidth'],
|
45
45
|
os: %x(uname -srv).chomp,
|
data/lib/aspera/oauth/jwt.rb
CHANGED
@@ -35,7 +35,7 @@ module Aspera
|
|
35
35
|
def create_token
|
36
36
|
require 'jwt'
|
37
37
|
seconds_since_epoch = Time.new.to_i
|
38
|
-
Log.log.
|
38
|
+
Log.log.debug{"seconds_since_epoch=#{seconds_since_epoch}"}
|
39
39
|
jwt_payload = {
|
40
40
|
exp: seconds_since_epoch + OAuth::Factory.instance.parameters[:jwt_expiry_offset_sec], # expiration time
|
41
41
|
nbf: seconds_since_epoch - OAuth::Factory.instance.parameters[:jwt_accepted_offset_sec], # not before
|
data/lib/aspera/oauth/web.rb
CHANGED
@@ -8,8 +8,8 @@ module Aspera
|
|
8
8
|
module OAuth
|
9
9
|
# Authentication using Web browser
|
10
10
|
class Web < Base
|
11
|
-
# @param
|
12
|
-
# @param
|
11
|
+
# @param redirect_uri url to receive the code after auth (to be exchanged for token)
|
12
|
+
# @param path_authorize path to login page on web app
|
13
13
|
def initialize(
|
14
14
|
redirect_uri:,
|
15
15
|
path_authorize: 'authorize',
|
@@ -21,11 +21,12 @@ module Aspera
|
|
21
21
|
uri = URI.parse(@redirect_uri)
|
22
22
|
Aspera.assert(%w[http https].include?(uri.scheme)){'redirect_uri scheme must be http or https'}
|
23
23
|
Aspera.assert(!uri.port.nil?){'redirect_uri must have a port'}
|
24
|
-
# TODO: we could check that host is localhost or local address
|
24
|
+
# TODO: we could check that host is localhost or local address, as we are going to listen locally
|
25
25
|
end
|
26
26
|
|
27
27
|
def create_token
|
28
|
-
|
28
|
+
# generate secure state to check later
|
29
|
+
random_state = SecureRandom.uuid
|
29
30
|
login_page_url = Rest.build_uri(
|
30
31
|
"#{@base_url}/#{@path_authorize}",
|
31
32
|
optional_scope_client_id.merge(response_type: 'code', redirect_uri: @redirect_uri, state: random_state))
|
data/lib/aspera/secret_hider.rb
CHANGED
@@ -16,17 +16,18 @@ module Aspera
|
|
16
16
|
KEY_SECRETS = %w[password secret passphrase _key apikey crn token].freeze
|
17
17
|
HTTP_SECRETS = %w[Authorization].freeze
|
18
18
|
ALL_SECRETS = [ASCP_ENV_SECRETS, KEY_SECRETS, HTTP_SECRETS].flatten.freeze
|
19
|
+
ALL_SECRETS2 = [KEY_SECRETS, HTTP_SECRETS].flatten.freeze
|
19
20
|
KEY_FALSE_POSITIVES = [/^access_key$/, /^fallback_private_key$/].freeze
|
20
21
|
# regex that define named captures :begin and :end
|
21
22
|
REGEX_LOG_REPLACES = [
|
22
23
|
# CLI manager get/set options
|
23
24
|
/(?<begin>[sg]et (?:#{KEY_SECRETS.join('|')})=).*(?<end>)/,
|
24
25
|
# env var ascp exec
|
25
|
-
/(?<begin> (?:#{ASCP_ENV_SECRETS.join('|')})=)
|
26
|
+
/(?<begin> (?:#{ASCP_ENV_SECRETS.join('|')})=)[^ ]+(?<end> )/,
|
26
27
|
# rendered JSON or Ruby
|
27
28
|
/(?<begin>(?:(?<quote>["'])|:)[^"':=]*(?:#{ALL_SECRETS.join('|')})[^"':=]*\k<quote>?(?:=>|:) *")[^"]+(?<end>")/,
|
28
29
|
# logged data
|
29
|
-
/(?<begin>(?:#{
|
30
|
+
/(?<begin>(?:#{ALL_SECRETS2.join('|')})[ =:]+).*(?<end>$)/,
|
30
31
|
# private key values
|
31
32
|
/(?<begin>--+BEGIN [^-]+ KEY--+)[[:ascii:]]+?(?<end>--+?END [^-]+ KEY--+)/,
|
32
33
|
# cred in http dump
|
data/lib/aspera/ssh.rb
CHANGED
@@ -14,7 +14,7 @@ if ENV.fetch('ASCLI_ENABLE_ED25519', 'false').eql?('false')
|
|
14
14
|
$VERBOSE = old_verbose
|
15
15
|
end
|
16
16
|
|
17
|
-
if
|
17
|
+
if defined?(JRUBY_VERSION) && ENV.fetch('ASCLI_ENABLE_ECDSHA2', 'false').eql?('false')
|
18
18
|
Net::SSH::Transport::Algorithms::ALGORITHMS.each_value { |a| a.reject! { |a| a =~ /^ecd(sa|h)-sha2/ } }
|
19
19
|
Net::SSH::KnownHosts::SUPPORTED_TYPE.reject! { |t| t =~ /^ecd(sa|h)-sha2/ }
|
20
20
|
end
|
@@ -8,19 +8,21 @@ module Aspera
|
|
8
8
|
PREFIX = 'faux:///'
|
9
9
|
# size suffix
|
10
10
|
SUFFIX = %w[k m g t p e]
|
11
|
+
private_constant :PREFIX, :SUFFIX
|
11
12
|
class << self
|
12
|
-
|
13
|
+
# @return nil if not a faux: scheme, else a FauxFile instance
|
14
|
+
def create(name)
|
13
15
|
return nil unless name.start_with?(PREFIX)
|
14
|
-
|
15
|
-
raise 'Format: #{PREFIX}<file path>?<size>' unless
|
16
|
-
raise "Format: <integer>[#{SUFFIX.join(',')}]" unless (m =
|
16
|
+
url_parts = name[PREFIX.length..-1].split('?')
|
17
|
+
raise 'Format: #{PREFIX}<file path>?<size>' unless url_parts.length.eql?(2)
|
18
|
+
raise "Format: <integer>[#{SUFFIX.join(',')}]" unless (m = url_parts[1].downcase.match(/^(\d+)([#{SUFFIX.join('')}])$/))
|
17
19
|
size = m[1].to_i
|
18
20
|
suffix = m[2]
|
19
21
|
SUFFIX.each do |s|
|
20
22
|
size *= 1024
|
21
23
|
break if s.eql?(suffix)
|
22
24
|
end
|
23
|
-
return FauxFile.new(
|
25
|
+
return FauxFile.new(url_parts[0], size)
|
24
26
|
end
|
25
27
|
end
|
26
28
|
attr_reader :path, :size
|
@@ -21,9 +21,10 @@ module Aspera
|
|
21
21
|
class Parameters
|
22
22
|
# Agents shown in manual for parameters (sub list)
|
23
23
|
SUPPORTED_AGENTS = %i[direct node connect trsdk httpgw].freeze
|
24
|
+
FILE_LIST_OPTIONS = ['--file-list', '--file-pair-list'].freeze
|
24
25
|
# Short names of columns in manual
|
25
26
|
SUPPORTED_AGENTS_SHORT = SUPPORTED_AGENTS.map{|agent_sym|agent_sym.to_s[0].to_sym}
|
26
|
-
|
27
|
+
HTTP_FALLBACK_ACTIVATION_VALUES = ['1', 1, true, 'force'].freeze
|
27
28
|
|
28
29
|
private_constant :SUPPORTED_AGENTS, :FILE_LIST_OPTIONS
|
29
30
|
|
@@ -106,21 +107,25 @@ module Aspera
|
|
106
107
|
# @param options [Hash] key: :wss: bool, :ascp_args: array of strings
|
107
108
|
def initialize(
|
108
109
|
job_spec,
|
109
|
-
ascp_args
|
110
|
-
wss
|
111
|
-
quiet
|
112
|
-
trusted_certs
|
113
|
-
|
110
|
+
ascp_args: nil,
|
111
|
+
wss: true,
|
112
|
+
quiet: true,
|
113
|
+
trusted_certs: nil,
|
114
|
+
client_ssh_key: nil,
|
115
|
+
check_ignore_cb: nil
|
114
116
|
)
|
115
117
|
@job_spec = job_spec
|
116
|
-
@ascp_args = ascp_args
|
118
|
+
@ascp_args = ascp_args.nil? ? [] : ascp_args
|
117
119
|
@wss = wss
|
118
120
|
@quiet = quiet
|
119
|
-
@trusted_certs = trusted_certs
|
121
|
+
@trusted_certs = trusted_certs.nil? ? [] : trusted_certs
|
122
|
+
@client_ssh_key = client_ssh_key.nil? ? :rsa : client_ssh_key.to_sym
|
120
123
|
@check_ignore_cb = check_ignore_cb
|
121
|
-
Aspera.assert_type(job_spec, Hash)
|
124
|
+
Aspera.assert_type(@job_spec, Hash)
|
122
125
|
Aspera.assert_type(@ascp_args, Array){'ascp_args'}
|
123
|
-
Aspera.assert(@ascp_args.all?(String)){'ascp arguments must be
|
126
|
+
Aspera.assert(@ascp_args.all?(String)){'all ascp arguments must be String'}
|
127
|
+
Aspera.assert_type(@trusted_certs, Array){'trusted_certs'}
|
128
|
+
Aspera.assert_values(@client_ssh_key, Ascp::Installation::CLIENT_SSH_KEY_OPTIONS)
|
124
129
|
@builder = CommandLineBuilder.new(@job_spec, Spec::DESCRIPTION)
|
125
130
|
end
|
126
131
|
|
@@ -162,6 +167,7 @@ module Aspera
|
|
162
167
|
@builder.add_command_line_options(["#{file_list_option}=#{file_list_file}"]) unless file_list_option.nil?
|
163
168
|
end
|
164
169
|
|
170
|
+
# @return the list of certificates to use when token/ssh or wss are used
|
165
171
|
def remote_certificates
|
166
172
|
certificates_to_use = []
|
167
173
|
# use web socket secure for session ?
|
@@ -174,7 +180,7 @@ module Aspera
|
|
174
180
|
@job_spec.delete('fasp_port')
|
175
181
|
@job_spec.delete('sshfp')
|
176
182
|
# set location for CA bundle to be the one of Ruby, see env var SSL_CERT_FILE / SSL_CERT_DIR
|
177
|
-
certificates_to_use.concat(@trusted_certs)
|
183
|
+
certificates_to_use.concat(@trusted_certs)
|
178
184
|
# ignore cert for wss ?
|
179
185
|
if @check_ignore_cb&.call(@job_spec['remote_host'], @job_spec['wss_port'])
|
180
186
|
wss_cert_file = TempFileManager.instance.new_file_path_global('wss_cert')
|
@@ -191,7 +197,7 @@ module Aspera
|
|
191
197
|
# add SSH bypass keys when authentication is token and no auth is provided
|
192
198
|
if @job_spec.key?('token') && !@job_spec.key?('remote_password')
|
193
199
|
# @job_spec['remote_password'] = Ascp::Installation.instance.ssh_cert_uuid # not used: no passphrase
|
194
|
-
certificates_to_use.concat(Ascp::Installation.instance.aspera_token_ssh_key_paths)
|
200
|
+
certificates_to_use.concat(Ascp::Installation.instance.aspera_token_ssh_key_paths(@client_ssh_key))
|
195
201
|
end
|
196
202
|
end
|
197
203
|
return certificates_to_use
|
@@ -200,9 +206,9 @@ module Aspera
|
|
200
206
|
# translate transfer spec to env vars and command line arguments for ascp
|
201
207
|
def ascp_args
|
202
208
|
env_args = {
|
203
|
-
args:
|
204
|
-
env:
|
205
|
-
|
209
|
+
args: [],
|
210
|
+
env: {},
|
211
|
+
name: :ascp
|
206
212
|
}
|
207
213
|
|
208
214
|
# special cases
|
@@ -213,7 +219,7 @@ module Aspera
|
|
213
219
|
|
214
220
|
# add ssh or wss certificates
|
215
221
|
# (reverse, to keep order, as we unshift)
|
216
|
-
remote_certificates
|
222
|
+
remote_certificates&.reverse_each do |cert|
|
217
223
|
env_args[:args].unshift('-i', cert)
|
218
224
|
end
|
219
225
|
|
@@ -223,9 +229,9 @@ module Aspera
|
|
223
229
|
base64_destination = false
|
224
230
|
# symbol must be index of Ascp::Installation.paths
|
225
231
|
if @builder.read_param('use_ascp4')
|
226
|
-
env_args[:
|
232
|
+
env_args[:name] = :ascp4
|
227
233
|
else
|
228
|
-
env_args[:
|
234
|
+
env_args[:name] = :ascp
|
229
235
|
base64_destination = true
|
230
236
|
end
|
231
237
|
# destination will be base64 encoded, put this before source path arguments
|
@@ -243,10 +249,12 @@ module Aspera
|
|
243
249
|
@builder.add_env_args(env_args)
|
244
250
|
env_args[:args].unshift('-q') if @quiet
|
245
251
|
# add fallback cert and key as arguments if needed
|
246
|
-
if
|
252
|
+
if HTTP_FALLBACK_ACTIVATION_VALUES.include?(@job_spec['http_fallback'])
|
247
253
|
env_args[:args].unshift('-Y', Ascp::Installation.instance.path(:fallback_private_key))
|
248
254
|
env_args[:args].unshift('-I', Ascp::Installation.instance.path(:fallback_certificate))
|
249
255
|
end
|
256
|
+
# disable redis in client
|
257
|
+
env_args[:env]['ASPERA_TEST_REDIS_DISABLE'] = 'true'
|
250
258
|
Log.log.debug{"ascp args: #{env_args}"}
|
251
259
|
return env_args
|
252
260
|
end
|
data/lib/aspera/transfer/spec.rb
CHANGED
@@ -22,23 +22,21 @@ module Aspera
|
|
22
22
|
# reserved tag for Aspera
|
23
23
|
TAG_RESERVED = 'aspera'
|
24
24
|
class << self
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
# translate upload/download to send/receive
|
26
|
+
def transfer_type_to_direction(transfer_type)
|
27
|
+
case transfer_type.to_sym
|
28
28
|
when :upload then DIRECTION_SEND
|
29
29
|
when :download then DIRECTION_RECEIVE
|
30
|
-
else Aspera.error_unexpected_value(
|
30
|
+
else Aspera.error_unexpected_value(transfer_type.to_sym)
|
31
31
|
end
|
32
|
-
return tspec
|
33
32
|
end
|
34
33
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
case tspec['direction']
|
34
|
+
# translate send/receive to upload/download
|
35
|
+
def direction_to_transfer_type(direction)
|
36
|
+
case direction
|
39
37
|
when DIRECTION_SEND then :upload
|
40
38
|
when DIRECTION_RECEIVE then :download
|
41
|
-
else Aspera.error_unexpected_value(
|
39
|
+
else Aspera.error_unexpected_value(direction)
|
42
40
|
end
|
43
41
|
end
|
44
42
|
end
|