aspera-cli 4.18.0 → 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 +23 -0
- data/CONTRIBUTING.md +5 -12
- data/README.md +152 -84
- data/examples/build_exec +85 -0
- data/examples/build_package.sh +28 -0
- data/lib/aspera/agent/alpha.rb +4 -4
- data/lib/aspera/agent/base.rb +2 -0
- data/lib/aspera/agent/connect.rb +3 -4
- data/lib/aspera/agent/direct.rb +108 -104
- data/lib/aspera/agent/httpgw.rb +1 -1
- data/lib/aspera/api/aoc.rb +2 -2
- data/lib/aspera/api/httpgw.rb +95 -57
- data/lib/aspera/api/node.rb +110 -77
- data/lib/aspera/ascp/installation.rb +47 -32
- data/lib/aspera/ascp/management.rb +4 -1
- data/lib/aspera/ascp/products.rb +2 -8
- data/lib/aspera/cli/extended_value.rb +27 -14
- data/lib/aspera/cli/formatter.rb +35 -28
- data/lib/aspera/cli/main.rb +11 -11
- data/lib/aspera/cli/manager.rb +109 -94
- data/lib/aspera/cli/plugin.rb +4 -7
- data/lib/aspera/cli/plugin_factory.rb +10 -1
- data/lib/aspera/cli/plugins/aoc.rb +15 -14
- data/lib/aspera/cli/plugins/config.rb +35 -29
- data/lib/aspera/cli/plugins/faspex.rb +5 -4
- data/lib/aspera/cli/plugins/faspex5.rb +16 -13
- data/lib/aspera/cli/plugins/node.rb +50 -41
- data/lib/aspera/cli/plugins/orchestrator.rb +3 -2
- data/lib/aspera/cli/plugins/preview.rb +1 -1
- data/lib/aspera/cli/plugins/server.rb +2 -2
- data/lib/aspera/cli/plugins/shares.rb +11 -7
- data/lib/aspera/cli/special_values.rb +13 -0
- data/lib/aspera/cli/sync_actions.rb +73 -32
- data/lib/aspera/cli/transfer_agent.rb +3 -2
- data/lib/aspera/cli/transfer_progress.rb +1 -1
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/environment.rb +100 -7
- 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 +7 -6
- data/lib/aspera/rest.rb +46 -15
- 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 +5 -4
- metadata.gz.sig +0 -0
- data/examples/rubyc +0 -24
- data/lib/aspera/open_application.rb +0 -69
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
|
data/lib/aspera/transfer/sync.rb
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
require 'aspera/command_line_builder'
|
|
6
6
|
require 'aspera/ascp/installation'
|
|
7
|
+
require 'aspera/agent/direct'
|
|
7
8
|
require 'aspera/log'
|
|
8
9
|
require 'aspera/assert'
|
|
9
10
|
require 'json'
|
|
@@ -13,12 +14,12 @@ require 'English'
|
|
|
13
14
|
|
|
14
15
|
module Aspera
|
|
15
16
|
module Transfer
|
|
16
|
-
# builds command line arg for async
|
|
17
|
+
# builds command line arg for async and execute it
|
|
17
18
|
module Sync
|
|
18
19
|
# sync direction, default is push
|
|
19
20
|
DIRECTIONS = %i[push pull bidi].freeze
|
|
20
|
-
#
|
|
21
|
-
|
|
21
|
+
# JSON for async instance command line options
|
|
22
|
+
CMDLINE_PARAMS_INSTANCE =
|
|
22
23
|
{
|
|
23
24
|
'alt_logdir' => { cli: { type: :opt_with_arg}, accepted_types: :string},
|
|
24
25
|
'watchd' => { cli: { type: :opt_with_arg}, accepted_types: :string},
|
|
@@ -28,7 +29,7 @@ module Aspera
|
|
|
28
29
|
}.freeze
|
|
29
30
|
|
|
30
31
|
# map sync session parameters to transfer spec: sync -> ts, true if same
|
|
31
|
-
|
|
32
|
+
CMDLINE_PARAMS_SESSION =
|
|
32
33
|
{
|
|
33
34
|
'name' => { cli: { type: :opt_with_arg}, accepted_types: :string},
|
|
34
35
|
'local_dir' => { cli: { type: :opt_with_arg}, accepted_types: :string},
|
|
@@ -65,13 +66,13 @@ module Aspera
|
|
|
65
66
|
'license' => { cli: { type: :envvar, variable: 'ASPERA_SCP_LICENSE'}}
|
|
66
67
|
}.freeze
|
|
67
68
|
|
|
68
|
-
CommandLineBuilder.normalize_description(
|
|
69
|
-
CommandLineBuilder.normalize_description(
|
|
69
|
+
CommandLineBuilder.normalize_description(CMDLINE_PARAMS_INSTANCE)
|
|
70
|
+
CommandLineBuilder.normalize_description(CMDLINE_PARAMS_SESSION)
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
CMDLINE_PARAMS_KEYS = %w[instance sessions].freeze
|
|
72
73
|
|
|
73
74
|
# Translation of transfer spec parameters to async v2 API (asyncs)
|
|
74
|
-
|
|
75
|
+
TSPEC_TO_ASYNC_CONF = {
|
|
75
76
|
'remote_host' => 'remote.host',
|
|
76
77
|
'remote_user' => 'remote.user',
|
|
77
78
|
'remote_password' => 'remote.pass',
|
|
@@ -83,10 +84,9 @@ module Aspera
|
|
|
83
84
|
'tags' => 'tags'
|
|
84
85
|
}.freeze
|
|
85
86
|
|
|
86
|
-
ASYNC_EXECUTABLE = 'async'
|
|
87
87
|
ASYNC_ADMIN_EXECUTABLE = 'asyncadmin'
|
|
88
88
|
|
|
89
|
-
private_constant :
|
|
89
|
+
private_constant :CMDLINE_PARAMS_INSTANCE, :CMDLINE_PARAMS_SESSION, :CMDLINE_PARAMS_KEYS, :TSPEC_TO_ASYNC_CONF, :ASYNC_ADMIN_EXECUTABLE
|
|
90
90
|
|
|
91
91
|
class << self
|
|
92
92
|
# Set remote_dir in sync parameters based on transfer spec
|
|
@@ -126,7 +126,7 @@ module Aspera
|
|
|
126
126
|
remote.delete('ws_port')
|
|
127
127
|
# add SSH bypass keys when authentication is token and no auth is provided
|
|
128
128
|
if remote.key?('token') && !remote.key?('pass')
|
|
129
|
-
certificates_to_use.concat(Ascp::Installation.instance.aspera_token_ssh_key_paths)
|
|
129
|
+
certificates_to_use.concat(Ascp::Installation.instance.aspera_token_ssh_key_paths(:rsa))
|
|
130
130
|
end
|
|
131
131
|
end
|
|
132
132
|
return certificates_to_use
|
|
@@ -134,23 +134,27 @@ module Aspera
|
|
|
134
134
|
|
|
135
135
|
# @param sync_params [Hash] sync parameters, old or new format
|
|
136
136
|
# @param block [nil, Proc] block to generate transfer spec, takes: direction (one of DIRECTIONS), local_dir, remote_dir
|
|
137
|
-
def start(
|
|
137
|
+
def start(
|
|
138
|
+
sync_params,
|
|
139
|
+
&block
|
|
140
|
+
)
|
|
141
|
+
Log.log.debug{Log.dump(:sync_params_initial, sync_params)}
|
|
138
142
|
Aspera.assert_type(sync_params, Hash)
|
|
139
143
|
env_args = {
|
|
140
144
|
args: [],
|
|
141
145
|
env: {}
|
|
142
146
|
}
|
|
143
147
|
if sync_params.key?('local')
|
|
148
|
+
# async native JSON format (conf option)
|
|
149
|
+
Aspera.assert_type(sync_params['local'], Hash){'local'}
|
|
144
150
|
remote = sync_params['remote']
|
|
145
|
-
|
|
146
|
-
Aspera.assert_type(remote,
|
|
151
|
+
Aspera.assert_type(remote, Hash){'remote'}
|
|
152
|
+
Aspera.assert_type(remote['path'], String){'remote path'}
|
|
147
153
|
# get transfer spec if possible, and feed back to new structure
|
|
148
154
|
if block
|
|
149
155
|
transfer_spec = yield((sync_params['direction'] || 'push').to_sym, sync_params['local']['path'], remote['path'])
|
|
150
|
-
# async native JSON format
|
|
151
|
-
Aspera.assert_type(sync_params['local'], Hash)
|
|
152
156
|
# translate transfer spec to async parameters
|
|
153
|
-
|
|
157
|
+
TSPEC_TO_ASYNC_CONF.each do |ts_param, sy_path|
|
|
154
158
|
next unless transfer_spec.key?(ts_param)
|
|
155
159
|
sy_dig = sy_path.split('.')
|
|
156
160
|
param = sy_dig.pop
|
|
@@ -160,36 +164,41 @@ module Aspera
|
|
|
160
164
|
end
|
|
161
165
|
update_remote_dir(remote, 'path', transfer_spec)
|
|
162
166
|
end
|
|
163
|
-
remote['connect_mode'] ||=
|
|
167
|
+
remote['connect_mode'] ||= transfer_spec['wss_enabled'] ? 'ws' : 'ssh'
|
|
164
168
|
add_certificates = remote_certificates(remote)
|
|
165
169
|
if !add_certificates.empty?
|
|
166
170
|
remote['private_key_paths'] ||= []
|
|
167
171
|
remote['private_key_paths'].concat(add_certificates)
|
|
168
172
|
end
|
|
169
|
-
|
|
173
|
+
# '--exclusive-mgmt-port=12345', '--arg-err-path=-',
|
|
170
174
|
env_args[:args] = ["--conf64=#{Base64.strict_encode64(JSON.generate(sync_params))}"]
|
|
175
|
+
Log.log.debug{Log.dump(:sync_params_enriched, sync_params)}
|
|
176
|
+
agent = Agent::Direct.new
|
|
177
|
+
agent.start_and_monitor_process(session: {}, name: :async, **env_args)
|
|
171
178
|
elsif sync_params.key?('sessions')
|
|
172
|
-
# ascli JSON format (
|
|
179
|
+
# ascli JSON format (cmdline)
|
|
180
|
+
raise StandardError, "Only 'sessions', and optionally 'instance' keys are allowed" unless
|
|
181
|
+
sync_params.keys.push('instance').uniq.sort.eql?(CMDLINE_PARAMS_KEYS)
|
|
182
|
+
Aspera.assert_type(sync_params['sessions'], Array)
|
|
183
|
+
Aspera.assert_type(sync_params['sessions'].first, Hash)
|
|
173
184
|
if block
|
|
174
185
|
sync_params['sessions'].each do |session|
|
|
186
|
+
Aspera.assert_type(session['local_dir'], String){'local_dir'}
|
|
187
|
+
Aspera.assert_type(session['remote_dir'], String){'remote_dir'}
|
|
175
188
|
transfer_spec = yield((session['direction'] || 'push').to_sym, session['local_dir'], session['remote_dir'])
|
|
176
|
-
|
|
189
|
+
CMDLINE_PARAMS_SESSION.each do |async_param, behavior|
|
|
177
190
|
if behavior.key?(:ts)
|
|
178
191
|
tspec_param = behavior[:ts].is_a?(TrueClass) ? async_param : behavior[:ts].to_s
|
|
179
192
|
session[async_param] ||= transfer_spec[tspec_param] if transfer_spec.key?(tspec_param)
|
|
180
193
|
end
|
|
181
194
|
end
|
|
182
|
-
session['private_key_paths'] = Ascp::Installation.instance.aspera_token_ssh_key_paths if transfer_spec.key?('token')
|
|
195
|
+
session['private_key_paths'] = Ascp::Installation.instance.aspera_token_ssh_key_paths(:rsa) if transfer_spec.key?('token')
|
|
183
196
|
update_remote_dir(session, 'remote_dir', transfer_spec)
|
|
184
197
|
end
|
|
185
198
|
end
|
|
186
|
-
raise StandardError, "Only 'sessions', and optionally 'instance' keys are allowed" unless
|
|
187
|
-
sync_params.keys.push('instance').uniq.sort.eql?(PARAMS_VX_KEYS)
|
|
188
|
-
Aspera.assert_type(sync_params['sessions'], Array)
|
|
189
|
-
Aspera.assert_type(sync_params['sessions'].first, Hash)
|
|
190
199
|
if sync_params.key?('instance')
|
|
191
200
|
Aspera.assert_type(sync_params['instance'], Hash)
|
|
192
|
-
instance_builder = CommandLineBuilder.new(sync_params['instance'],
|
|
201
|
+
instance_builder = CommandLineBuilder.new(sync_params['instance'], CMDLINE_PARAMS_INSTANCE)
|
|
193
202
|
instance_builder.process_params
|
|
194
203
|
instance_builder.add_env_args(env_args)
|
|
195
204
|
end
|
|
@@ -197,23 +206,19 @@ module Aspera
|
|
|
197
206
|
sync_params['sessions'].each do |session_params|
|
|
198
207
|
Aspera.assert_type(session_params, Hash)
|
|
199
208
|
Aspera.assert(session_params.key?('name')){'session must contain at least name'}
|
|
200
|
-
session_builder = CommandLineBuilder.new(session_params,
|
|
209
|
+
session_builder = CommandLineBuilder.new(session_params, CMDLINE_PARAMS_SESSION)
|
|
201
210
|
session_builder.process_params
|
|
202
211
|
session_builder.add_env_args(env_args)
|
|
203
212
|
end
|
|
213
|
+
async_exec = Ascp::Installation.instance.path(:async)
|
|
214
|
+
Process.wait(Environment.secure_spawn(env: env_args[:env], exec: async_exec, args: env_args[:args]))
|
|
215
|
+
if $CHILD_STATUS.exitstatus != 0
|
|
216
|
+
raise "Sync failed with exit: #{$CHILD_STATUS.exitstatus}"
|
|
217
|
+
end
|
|
204
218
|
else
|
|
205
219
|
raise 'At least one of `local` or `sessions` must be present in async parameters'
|
|
206
220
|
end
|
|
207
|
-
|
|
208
|
-
Log.log.debug{"execute: #{env_args[:env].map{|k, v| "#{k}=\"#{v}\""}.join(' ')} \"#{ASYNC_EXECUTABLE}\" \"#{env_args[:args].join('" "')}\""}
|
|
209
|
-
res = system(env_args[:env], [ASYNC_EXECUTABLE, ASYNC_EXECUTABLE], *env_args[:args])
|
|
210
|
-
Log.log.debug{"result=#{res}"}
|
|
211
|
-
case res
|
|
212
|
-
when true then return nil
|
|
213
|
-
when false then raise "failed: #{$CHILD_STATUS}"
|
|
214
|
-
when nil then raise "not started: #{$CHILD_STATUS}"
|
|
215
|
-
else Aspera.error_unexpected_value(res)
|
|
216
|
-
end
|
|
221
|
+
return nil
|
|
217
222
|
end
|
|
218
223
|
|
|
219
224
|
def parse_status(stdout)
|
|
@@ -234,15 +239,15 @@ module Aspera
|
|
|
234
239
|
end
|
|
235
240
|
|
|
236
241
|
def admin_status(sync_params, session_name)
|
|
237
|
-
|
|
242
|
+
arguments = ['--quiet']
|
|
238
243
|
if sync_params.key?('local')
|
|
239
244
|
Aspera.assert(!sync_params['name'].nil?){'Missing session name'}
|
|
240
245
|
Aspera.assert(session_name.nil? || session_name.eql?(sync_params['name'])){'Session not found'}
|
|
241
|
-
|
|
246
|
+
arguments.push("--name=#{sync_params['name']}")
|
|
242
247
|
if sync_params.key?('local_db_dir')
|
|
243
|
-
|
|
248
|
+
arguments.push("--local-db-dir=#{sync_params['local_db_dir']}")
|
|
244
249
|
elsif sync_params.dig('local', 'path')
|
|
245
|
-
|
|
250
|
+
arguments.push("--local-dir=#{sync_params.dig('local', 'path')}")
|
|
246
251
|
else
|
|
247
252
|
raise 'Missing either local_db_dir or local.path'
|
|
248
253
|
end
|
|
@@ -250,19 +255,19 @@ module Aspera
|
|
|
250
255
|
session = session_name.nil? ? sync_params['sessions'].first : sync_params['sessions'].find{|s|s['name'].eql?(session_name)}
|
|
251
256
|
raise "Session #{session_name} not found in #{sync_params['sessions'].map{|s|s['name']}.join(',')}" if session.nil?
|
|
252
257
|
raise 'Missing session name' if session['name'].nil?
|
|
253
|
-
|
|
258
|
+
arguments.push("--name=#{session['name']}")
|
|
254
259
|
if session.key?('local_db_dir')
|
|
255
|
-
|
|
260
|
+
arguments.push("--local-db-dir=#{session['local_db_dir']}")
|
|
256
261
|
elsif session.key?('local_dir')
|
|
257
|
-
|
|
262
|
+
arguments.push("--local-dir=#{session['local_dir']}")
|
|
258
263
|
else
|
|
259
264
|
raise 'Missing either local_db_dir or local_dir'
|
|
260
265
|
end
|
|
261
266
|
else
|
|
262
267
|
raise 'At least one of `local` or `sessions` must be present in async parameters'
|
|
263
268
|
end
|
|
264
|
-
|
|
265
|
-
stdout, stderr, status = Open3.capture3(*
|
|
269
|
+
Environment.secure_spawn(env: {}, exec: ASYNC_ADMIN_EXECUTABLE, args: arguments, log_only: true)
|
|
270
|
+
stdout, stderr, status = Open3.capture3(*[ASYNC_ADMIN_EXECUTABLE].concat(arguments))
|
|
266
271
|
Log.log.debug{"status=#{status}, stderr=#{stderr}"}
|
|
267
272
|
Log.log.trace1{"stdout=#{stdout}"}
|
|
268
273
|
raise "Sync failed: #{status.exitstatus} : #{stderr}" unless status.success?
|
data/lib/aspera/web_auth.rb
CHANGED
|
@@ -4,12 +4,13 @@ require 'webrick'
|
|
|
4
4
|
require 'webrick/https'
|
|
5
5
|
require 'aspera/log'
|
|
6
6
|
require 'aspera/assert'
|
|
7
|
+
require 'aspera/hash_ext'
|
|
7
8
|
require 'openssl'
|
|
8
9
|
|
|
9
10
|
module Aspera
|
|
10
11
|
# Simple WEBrick server with HTTPS support
|
|
11
12
|
class WebServerSimple < WEBrick::HTTPServer
|
|
12
|
-
CERT_PARAMETERS = %i[key cert chain].freeze
|
|
13
|
+
CERT_PARAMETERS = %i[key cert chain pkcs12].freeze
|
|
13
14
|
GENERIC_ISSUER = '/C=FR/O=Test/OU=Test/CN=Test'
|
|
14
15
|
ONE_YEAR_SECONDS = 365 * 24 * 60 * 60
|
|
15
16
|
|
|
@@ -58,19 +59,29 @@ module Aspera
|
|
|
58
59
|
Aspera.assert_type(certificate, Hash)
|
|
59
60
|
certificate = certificate.symbolize_keys
|
|
60
61
|
raise "unexpected key in certificate config: only: #{CERT_PARAMETERS.join(', ')}" if certificate.keys.any?{|key|!CERT_PARAMETERS.include?(key)}
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
if certificate.key?(:pkcs12)
|
|
63
|
+
Log.log.debug('Using PKCS12 certificate')
|
|
64
|
+
raise 'pkcs12 requires a password' unless certificate.key?(:key)
|
|
65
|
+
pkcs12 = OpenSSL::PKCS12.new(File.read(certificate[:pkcs12]), certificate[:key])
|
|
66
|
+
webrick_options[:SSLCertificate] = pkcs12.certificate
|
|
67
|
+
webrick_options[:SSLPrivateKey] = pkcs12.key
|
|
68
|
+
webrick_options[:SSLExtraChainCert] = pkcs12.ca_certs
|
|
63
69
|
else
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
Log.log.debug('Using PEM certificate')
|
|
71
|
+
webrick_options[:SSLPrivateKey] = if certificate.key?(:key)
|
|
72
|
+
OpenSSL::PKey::RSA.new(File.read(certificate[:key]))
|
|
73
|
+
else
|
|
74
|
+
OpenSSL::PKey::RSA.new(4096)
|
|
75
|
+
end
|
|
76
|
+
if certificate.key?(:cert)
|
|
77
|
+
webrick_options[:SSLCertificate] = OpenSSL::X509::Certificate.new(File.read(certificate[:cert]))
|
|
78
|
+
else
|
|
79
|
+
webrick_options[:SSLCertificate] = OpenSSL::X509::Certificate.new
|
|
80
|
+
self.class.fill_self_signed_cert(webrick_options[:SSLCertificate], webrick_options[:SSLPrivateKey])
|
|
81
|
+
end
|
|
82
|
+
if certificate.key?(:chain)
|
|
83
|
+
webrick_options[:SSLExtraChainCert] = [OpenSSL::X509::Certificate.new(File.read(certificate[:chain]))]
|
|
84
|
+
end
|
|
74
85
|
end
|
|
75
86
|
end
|
|
76
87
|
end
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aspera-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.19.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Laurent Martin
|
|
@@ -37,7 +37,7 @@ cert_chain:
|
|
|
37
37
|
eTf9kxhVM40wGQOECVNA8UsEEZHD48eF+csUYZtAJOF5oxTI8UyV9T/o6CgO0c9/
|
|
38
38
|
Gzz+Qm5ULOUcPiJLjSpaiTrkiIVYiDGnqNSr6R1Hb1c=
|
|
39
39
|
-----END CERTIFICATE-----
|
|
40
|
-
date: 2024-
|
|
40
|
+
date: 2024-10-02 00:00:00.000000000 Z
|
|
41
41
|
dependencies:
|
|
42
42
|
- !ruby/object:Gem::Dependency
|
|
43
43
|
name: blankslate
|
|
@@ -390,9 +390,10 @@ files:
|
|
|
390
390
|
- README.md
|
|
391
391
|
- bin/ascli
|
|
392
392
|
- bin/asession
|
|
393
|
+
- examples/build_exec
|
|
394
|
+
- examples/build_package.sh
|
|
393
395
|
- examples/dascli
|
|
394
396
|
- examples/proxy.pac
|
|
395
|
-
- examples/rubyc
|
|
396
397
|
- lib/aspera/agent/alpha.rb
|
|
397
398
|
- lib/aspera/agent/base.rb
|
|
398
399
|
- lib/aspera/agent/connect.rb
|
|
@@ -435,6 +436,7 @@ files:
|
|
|
435
436
|
- lib/aspera/cli/plugins/preview.rb
|
|
436
437
|
- lib/aspera/cli/plugins/server.rb
|
|
437
438
|
- lib/aspera/cli/plugins/shares.rb
|
|
439
|
+
- lib/aspera/cli/special_values.rb
|
|
438
440
|
- lib/aspera/cli/sync_actions.rb
|
|
439
441
|
- lib/aspera/cli/transfer_agent.rb
|
|
440
442
|
- lib/aspera/cli/transfer_progress.rb
|
|
@@ -468,7 +470,6 @@ files:
|
|
|
468
470
|
- lib/aspera/oauth/jwt.rb
|
|
469
471
|
- lib/aspera/oauth/url_json.rb
|
|
470
472
|
- lib/aspera/oauth/web.rb
|
|
471
|
-
- lib/aspera/open_application.rb
|
|
472
473
|
- lib/aspera/persistency_action_once.rb
|
|
473
474
|
- lib/aspera/persistency_folder.rb
|
|
474
475
|
- lib/aspera/preview/file_types.rb
|
metadata.gz.sig
CHANGED
|
Binary file
|
data/examples/rubyc
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# https://github.com/you54f/ruby-packer
|
|
3
|
-
# https://github.com/YOU54F/ruby-packer/releases
|
|
4
|
-
set -e
|
|
5
|
-
FOLDER="$(dirname $0)/../tmp"
|
|
6
|
-
RUBYC="$FOLDER/rubyc"
|
|
7
|
-
if test ! -e "$RUBYC"; then
|
|
8
|
-
mkdir -p "$FOLDER"
|
|
9
|
-
case $(uname -sm|tr ' ' -) in
|
|
10
|
-
Darwin-arm64)
|
|
11
|
-
curl -L https://github.com/YOU54F/ruby-packer/releases/download/rel-20230812/rubyc-Darwin-arm64.tar.gz | tar -xz -C "$FOLDER"
|
|
12
|
-
mv "$FOLDER/rubyc-Darwin-arm64" "$RUBYC"
|
|
13
|
-
;;
|
|
14
|
-
Linux-x86_64)
|
|
15
|
-
curl -L https://github.com/YOU54F/ruby-packer/releases/download/rel-20230812/rubyc-Linux-x86_64.tar.gz | tar -xz -C "$FOLDER"
|
|
16
|
-
mv "$FOLDER/rubyc-Linux-x86_64" "$RUBYC"
|
|
17
|
-
;;
|
|
18
|
-
*)
|
|
19
|
-
echo "This architecture is not supported." >&2
|
|
20
|
-
exit 1
|
|
21
|
-
;;
|
|
22
|
-
esac
|
|
23
|
-
fi
|
|
24
|
-
exec "$RUBYC" "$@"
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'aspera/log'
|
|
4
|
-
require 'aspera/environment'
|
|
5
|
-
require 'rbconfig'
|
|
6
|
-
require 'singleton'
|
|
7
|
-
|
|
8
|
-
module Aspera
|
|
9
|
-
# Allows a user to open a Url
|
|
10
|
-
# if method is "text", then URL is displayed on terminal
|
|
11
|
-
# if method is "graphical", then the URL will be opened with the default browser.
|
|
12
|
-
class OpenApplication
|
|
13
|
-
include Singleton
|
|
14
|
-
USER_INTERFACES = %i[text graphical].freeze
|
|
15
|
-
class << self
|
|
16
|
-
def default_gui_mode
|
|
17
|
-
# assume not remotely connected on macos and windows
|
|
18
|
-
return :graphical if [Environment::OS_WINDOWS, Environment::OS_X].include?(Environment.os)
|
|
19
|
-
# unix family
|
|
20
|
-
return :graphical if ENV.key?('DISPLAY') && !ENV['DISPLAY'].empty?
|
|
21
|
-
return :text
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# command must be non blocking
|
|
25
|
-
def uri_graphical(uri)
|
|
26
|
-
case Environment.os
|
|
27
|
-
when Environment::OS_X then return system('open', uri.to_s)
|
|
28
|
-
when Environment::OS_WINDOWS then return system('start', 'explorer', %Q{"#{uri}"})
|
|
29
|
-
when Environment::OS_LINUX then return system('xdg-open', uri.to_s)
|
|
30
|
-
else
|
|
31
|
-
raise "no graphical open method for #{Environment.os}"
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def editor(file_path)
|
|
36
|
-
if ENV.key?('EDITOR')
|
|
37
|
-
system(ENV['EDITOR'], file_path.to_s)
|
|
38
|
-
elsif Environment.os.eql?(Environment::OS_WINDOWS)
|
|
39
|
-
system('notepad.exe', %Q{"#{file_path}"})
|
|
40
|
-
else
|
|
41
|
-
uri_graphical(file_path.to_s)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
attr_accessor :url_method
|
|
47
|
-
|
|
48
|
-
def initialize
|
|
49
|
-
@url_method = self.class.default_gui_mode
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# this is non blocking
|
|
53
|
-
def uri(the_url)
|
|
54
|
-
case @url_method
|
|
55
|
-
when :graphical
|
|
56
|
-
self.class.uri_graphical(the_url)
|
|
57
|
-
when :text
|
|
58
|
-
case the_url.to_s
|
|
59
|
-
when /^http/
|
|
60
|
-
puts "USER ACTION: please enter this url in a browser:\n#{the_url.to_s.red}\n"
|
|
61
|
-
else
|
|
62
|
-
puts "USER ACTION: open this:\n#{the_url.to_s.red}\n"
|
|
63
|
-
end
|
|
64
|
-
else
|
|
65
|
-
raise StandardError, "unsupported url open method: #{@url_method}"
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|