aspera-cli 4.11.0 → 4.12.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/BUGS.md +0 -1
- data/CHANGELOG.md +71 -52
- data/CONTRIBUTING.md +31 -6
- data/README.md +404 -259
- data/bin/asession +2 -2
- data/docs/test_env.conf +1 -0
- data/examples/aoc.rb +2 -2
- data/examples/dascli +11 -11
- data/examples/faspex4.rb +7 -7
- data/examples/node.rb +1 -1
- data/examples/proxy.pac +2 -2
- data/examples/server.rb +3 -3
- data/lib/aspera/aoc.rb +105 -40
- data/lib/aspera/cli/extended_value.rb +4 -4
- data/lib/aspera/cli/{formater.rb → formatter.rb} +7 -7
- data/lib/aspera/cli/listener/progress.rb +1 -1
- data/lib/aspera/cli/listener/progress_multi.rb +2 -2
- data/lib/aspera/cli/main.rb +18 -18
- data/lib/aspera/cli/manager.rb +5 -5
- data/lib/aspera/cli/plugin.rb +23 -20
- data/lib/aspera/cli/plugins/aoc.rb +75 -112
- data/lib/aspera/cli/plugins/ats.rb +6 -6
- data/lib/aspera/cli/plugins/config.rb +84 -83
- data/lib/aspera/cli/plugins/cos.rb +1 -1
- data/lib/aspera/cli/plugins/faspex.rb +38 -38
- data/lib/aspera/cli/plugins/faspex5.rb +187 -43
- data/lib/aspera/cli/plugins/node.rb +30 -37
- data/lib/aspera/cli/plugins/orchestrator.rb +7 -4
- data/lib/aspera/cli/plugins/preview.rb +10 -9
- data/lib/aspera/cli/plugins/server.rb +1 -1
- data/lib/aspera/cli/plugins/shares.rb +67 -43
- data/lib/aspera/cli/transfer_agent.rb +16 -16
- data/lib/aspera/cli/version.rb +2 -1
- data/lib/aspera/command_line_builder.rb +70 -66
- data/lib/aspera/cos_node.rb +9 -9
- data/lib/aspera/fasp/agent_base.rb +3 -1
- data/lib/aspera/fasp/agent_connect.rb +23 -23
- data/lib/aspera/fasp/agent_direct.rb +13 -14
- data/lib/aspera/fasp/agent_httpgw.rb +20 -19
- data/lib/aspera/fasp/agent_node.rb +13 -15
- data/lib/aspera/fasp/agent_trsdk.rb +1 -1
- data/lib/aspera/fasp/installation.rb +5 -5
- data/lib/aspera/fasp/listener.rb +1 -1
- data/lib/aspera/fasp/parameters.rb +49 -41
- data/lib/aspera/fasp/parameters.yaml +311 -212
- data/lib/aspera/fasp/resume_policy.rb +2 -2
- data/lib/aspera/fasp/transfer_spec.rb +0 -13
- data/lib/aspera/faspex_gw.rb +80 -161
- data/lib/aspera/faspex_postproc.rb +77 -0
- data/lib/aspera/log.rb +7 -7
- data/lib/aspera/nagios.rb +6 -6
- data/lib/aspera/node.rb +24 -19
- data/lib/aspera/oauth.rb +50 -47
- data/lib/aspera/proxy_auto_config.js +22 -22
- data/lib/aspera/proxy_auto_config.rb +3 -3
- data/lib/aspera/rest.rb +12 -10
- data/lib/aspera/rest_error_analyzer.rb +5 -5
- data/lib/aspera/secret_hider.rb +4 -3
- data/lib/aspera/ssh.rb +4 -4
- data/lib/aspera/sync.rb +37 -36
- data/lib/aspera/web_auth.rb +7 -59
- data/lib/aspera/web_server_simple.rb +76 -0
- data.tar.gz.sig +0 -0
- metadata +6 -4
- metadata.gz.sig +0 -0
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'aspera/cli/basic_auth_plugin'
|
4
4
|
require 'aspera/cli/extended_value'
|
5
5
|
require 'aspera/cli/version'
|
6
|
-
require 'aspera/cli/
|
6
|
+
require 'aspera/cli/formatter'
|
7
7
|
require 'aspera/cli/info'
|
8
8
|
require 'aspera/fasp/installation'
|
9
9
|
require 'aspera/fasp/parameters'
|
@@ -129,7 +129,7 @@ module Aspera
|
|
129
129
|
ExtendedValue.instance.set_handler(EXTV_PRESET, :reader, lambda{|v|preset_by_name(v)})
|
130
130
|
ExtendedValue.instance.set_handler(EXTV_INCLUDE_PRESETS, :decoder, lambda{|v|expanded_with_preset_includes(v)})
|
131
131
|
ExtendedValue.instance.set_handler(EXTV_VAULT, :decoder, lambda{|v|vault_value(v)})
|
132
|
-
# load defaults before it can be
|
132
|
+
# load defaults before it can be overridden
|
133
133
|
add_plugin_default_preset(CONF_GLOBAL_SYM)
|
134
134
|
options.parse_options!
|
135
135
|
options.set_obj_attr(:ascp_path, Fasp::Installation.instance, :ascp_path)
|
@@ -261,16 +261,16 @@ module Aspera
|
|
261
261
|
Log.log.debug{"javascript=[\n#{connect_versions_javascript}\n]"}
|
262
262
|
# get javascript object only
|
263
263
|
found = connect_versions_javascript.match(/^.*? = (.*);/)
|
264
|
-
raise CliError, '
|
265
|
-
|
266
|
-
@connect_versions =
|
264
|
+
raise CliError, 'Problem when getting connect versions from internet' if found.nil?
|
265
|
+
all_data = JSON.parse(found[1])
|
266
|
+
@connect_versions = all_data['entries']
|
267
267
|
end
|
268
268
|
return @connect_versions
|
269
269
|
end
|
270
270
|
|
271
271
|
# loads default parameters of plugin if no -P parameter
|
272
272
|
# and if there is a section defined for the plugin in the "default" section
|
273
|
-
# try to find:
|
273
|
+
# try to find: conf[conf["default"][plugin_str]]
|
274
274
|
# @param plugin_name_sym : symbol for plugin name
|
275
275
|
def add_plugin_default_preset(plugin_name_sym)
|
276
276
|
default_config_name = get_plugin_default_config_name(plugin_name_sym)
|
@@ -297,7 +297,7 @@ module Aspera
|
|
297
297
|
File.dirname(File.expand_path(__FILE__))
|
298
298
|
end
|
299
299
|
|
300
|
-
# name of
|
300
|
+
# name of englobing module
|
301
301
|
# @return "Aspera::Cli::Plugins"
|
302
302
|
def module_full_name
|
303
303
|
return Module.nesting[2].to_s
|
@@ -309,7 +309,7 @@ module Aspera
|
|
309
309
|
File.expand_path(module_full_name.gsub('::', '/').gsub(%r{[^/]+}, '..'), gem_plugins_folder)
|
310
310
|
end
|
311
311
|
|
312
|
-
#
|
312
|
+
# instantiate a plugin
|
313
313
|
# plugins must be Capitalized
|
314
314
|
def plugin_class(plugin_name_sym)
|
315
315
|
# Module.nesting[2] is Aspera::Cli::Plugins
|
@@ -330,7 +330,7 @@ module Aspera
|
|
330
330
|
end
|
331
331
|
@config_presets[global_default_preset_name] ||= {}
|
332
332
|
@config_presets[global_default_preset_name][key.to_s] = value
|
333
|
-
|
333
|
+
formatter.display_status("Updated: #{global_default_preset_name}: #{key} <- #{value}")
|
334
334
|
save_presets_to_config_file
|
335
335
|
return global_default_preset_name
|
336
336
|
end
|
@@ -362,7 +362,7 @@ module Aspera
|
|
362
362
|
end
|
363
363
|
end
|
364
364
|
|
365
|
-
# @return the hash value with 'incps' keys
|
365
|
+
# @return the hash value with 'incps' keys expanded to include other presets
|
366
366
|
# @param hash_val
|
367
367
|
# @param include_path to avoid inclusion loop
|
368
368
|
def expanded_with_preset_includes(hash_val, include_path=[])
|
@@ -582,7 +582,8 @@ module Aspera
|
|
582
582
|
Log.log.debug{"Cannot detect #{plugin_name_sym} : #{e.message}"}
|
583
583
|
end
|
584
584
|
end
|
585
|
-
|
585
|
+
# if there is a redirect, then the detector can override the url.
|
586
|
+
return {product: plugin_name_sym, url: current_url}.merge(detection_info) unless detection_info.nil?
|
586
587
|
end # loop
|
587
588
|
raise "No known application found at #{url}"
|
588
589
|
end
|
@@ -615,9 +616,9 @@ module Aspera
|
|
615
616
|
folder_dest = transfer.destination_folder(Fasp::TransferSpec::DIRECTION_RECEIVE)
|
616
617
|
# folder_dest=self.options.get_next_argument('destination folder')
|
617
618
|
api_connect_cdn = Rest.new({base_url: CONNECT_WEB_URL})
|
618
|
-
|
619
|
-
filename =
|
620
|
-
api_connect_cdn.call({operation: 'GET', subpath:
|
619
|
+
file_url = one_link['href']
|
620
|
+
filename = file_url.gsub(%r{.*/}, '')
|
621
|
+
api_connect_cdn.call({operation: 'GET', subpath: file_url, save_to_file: File.join(folder_dest, filename)})
|
621
622
|
return Main.result_status("Downloaded: #{filename}")
|
622
623
|
when :open
|
623
624
|
OpenApplication.instance.uri(one_link['href'])
|
@@ -634,7 +635,7 @@ module Aspera
|
|
634
635
|
when :use
|
635
636
|
ascp_path = options.get_next_argument('path to ascp')
|
636
637
|
ascp_version = Fasp::Installation.instance.get_ascp_version(ascp_path)
|
637
|
-
|
638
|
+
formatter.display_status("ascp version: #{ascp_version}")
|
638
639
|
preset_name = set_global_default(:ascp_path, ascp_path)
|
639
640
|
return Main.result_status("Saved to default global preset #{preset_name}")
|
640
641
|
when :show # shows files used
|
@@ -692,7 +693,7 @@ module Aspera
|
|
692
693
|
return {
|
693
694
|
type: :object_list,
|
694
695
|
data: Fasp::Parameters.man_table,
|
695
|
-
fields: %w[name type]
|
696
|
+
fields: [%w[name type], Fasp::Parameters::SUPPORTED_AGENTS_SHORT.map(&:to_s), %w[description]].flatten.freeze
|
696
697
|
}
|
697
698
|
when :errors
|
698
699
|
error_data = []
|
@@ -706,23 +707,23 @@ module Aspera
|
|
706
707
|
|
707
708
|
# legacy actions available globally
|
708
709
|
PRESET_GBL_ACTIONS = %i[list overview lookup secure].freeze
|
709
|
-
#
|
710
|
-
|
710
|
+
# operations requiring that preset exists
|
711
|
+
PRESET_EXIST_ACTIONS = %i[show delete get unset].freeze
|
711
712
|
# require id
|
712
|
-
PRESET_INSTANCE_ACTIONS = %i[initialize update ask set].concat(
|
713
|
-
PRESET_ALL_ACTIONS = [
|
713
|
+
PRESET_INSTANCE_ACTIONS = %i[initialize update ask set].concat(PRESET_EXIST_ACTIONS).freeze
|
714
|
+
PRESET_ALL_ACTIONS = [PRESET_GBL_ACTIONS, PRESET_INSTANCE_ACTIONS].flatten.freeze
|
714
715
|
|
715
716
|
def execute_preset(action: nil, name: nil)
|
716
717
|
action = options.get_next_command(PRESET_ALL_ACTIONS) if action.nil?
|
717
718
|
name = instance_identifier if name.nil? && PRESET_INSTANCE_ACTIONS.include?(action)
|
718
719
|
# those operations require existing option
|
719
|
-
raise "no such preset: #{name}" if
|
720
|
+
raise "no such preset: #{name}" if PRESET_EXIST_ACTIONS.include?(action) && !@config_presets.key?(name)
|
720
721
|
selected_preset = @config_presets[name]
|
721
722
|
case action
|
722
723
|
when :list
|
723
724
|
return {type: :value_list, data: @config_presets.keys, name: 'name'}
|
724
725
|
when :overview
|
725
|
-
return {type: :object_list, data:
|
726
|
+
return {type: :object_list, data: Formatter.flatten_config_overview(@config_presets)}
|
726
727
|
when :show
|
727
728
|
raise "no such config: #{name}" if selected_preset.nil?
|
728
729
|
return {type: :single_object, data: selected_preset}
|
@@ -766,10 +767,10 @@ module Aspera
|
|
766
767
|
return Main.result_status("Modified: #{@option_config_file}")
|
767
768
|
when :update
|
768
769
|
# get unprocessed options
|
769
|
-
|
770
|
-
Log.log.debug{"opts=#{
|
770
|
+
unprocessed_options = options.get_options_table
|
771
|
+
Log.log.debug{"opts=#{unprocessed_options}"}
|
771
772
|
@config_presets[name] ||= {}
|
772
|
-
@config_presets[name].merge!(
|
773
|
+
@config_presets[name].merge!(unprocessed_options)
|
773
774
|
# fix bug in 4.4 (creating key "true" in "default" preset)
|
774
775
|
@config_presets[CONF_PRESET_DEFAULT].delete(true) if @config_presets[CONF_PRESET_DEFAULT].is_a?(Hash)
|
775
776
|
save_presets_to_config_file
|
@@ -777,9 +778,9 @@ module Aspera
|
|
777
778
|
when :ask
|
778
779
|
options.ask_missing_mandatory = :yes
|
779
780
|
@config_presets[name] ||= {}
|
780
|
-
options.get_next_argument('option names', expected: :multiple).each do |
|
781
|
-
option_value = options.get_interactive(:option,
|
782
|
-
@config_presets[name][
|
781
|
+
options.get_next_argument('option names', expected: :multiple).each do |option_name|
|
782
|
+
option_value = options.get_interactive(:option, option_name)
|
783
|
+
@config_presets[name][option_name] = option_value
|
783
784
|
end
|
784
785
|
save_presets_to_config_file
|
785
786
|
return Main.result_status("Updated: #{name}")
|
@@ -794,20 +795,20 @@ module Aspera
|
|
794
795
|
identifier = options.get_next_argument('config name', mandatory: false)
|
795
796
|
preset_names = identifier.nil? ? @config_presets.keys : [identifier]
|
796
797
|
secret_keywords = %w[password secret].freeze
|
797
|
-
preset_names.each do |
|
798
|
-
preset = @config_presets[
|
798
|
+
preset_names.each do |preset_name|
|
799
|
+
preset = @config_presets[preset_name]
|
799
800
|
next unless preset.is_a?(Hash)
|
800
801
|
preset.each_key do |option_name|
|
801
802
|
secret_keywords.each do |keyword|
|
802
803
|
next unless option_name.end_with?(keyword)
|
803
|
-
vault_label =
|
804
|
+
vault_label = preset_name
|
804
805
|
incr = 0
|
805
806
|
until vault.get(label: vault_label, exception: false).nil?
|
806
|
-
vault_label = "#{
|
807
|
+
vault_label = "#{preset_name}#{incr}"
|
807
808
|
incr += 1
|
808
809
|
end
|
809
810
|
to_set = {label: vault_label, password: preset[option_name]}
|
810
|
-
puts "need to encode #{
|
811
|
+
puts "need to encode #{preset_name}.#{option_name} -> #{vault_label} -> #{to_set}"
|
811
812
|
# to_copy=%i[]
|
812
813
|
vault.set(to_set)
|
813
814
|
preset[option_name] = "@vault:#{vault_label}.password"
|
@@ -925,20 +926,20 @@ module Aspera
|
|
925
926
|
raise CliBadArgument, "Supports only: aoc. Detected: #{params[:application]}"
|
926
927
|
end # product
|
927
928
|
if params[:option_default]
|
928
|
-
|
929
|
+
formatter.display_status("Setting config preset as default for #{params[:plugin_name]}")
|
929
930
|
@config_presets[CONF_PRESET_DEFAULT][params[:plugin_name]] = params[:preset_name]
|
930
931
|
else
|
931
932
|
params[:test_args] = "-P#{params[:preset_name]} #{params[:test_args]}"
|
932
933
|
end
|
933
|
-
|
934
|
+
formatter.display_status('Saving config file.')
|
934
935
|
save_presets_to_config_file
|
935
936
|
return Main.result_status("Done.\nYou can test with:\n#{@info[:name]} #{params[:test_args]}")
|
936
937
|
when :export_to_cli # this method shall be deprecated in the future: it was used to export configuration to "aspera.exe" CLI
|
937
|
-
|
938
|
+
formatter.display_status('Exporting: Aspera on Cloud')
|
938
939
|
require 'aspera/cli/plugins/aoc'
|
939
940
|
# need url / username
|
940
941
|
add_plugin_default_preset(AOC_COMMAND_V3.to_sym)
|
941
|
-
#
|
942
|
+
# instantiate AoC plugin
|
942
943
|
self.class.plugin_class(AOC_COMMAND_CURRENT).new(@agents) # TODO: is this line needed ? get options ?
|
943
944
|
url = options.get_option(:url, is_type: :mandatory)
|
944
945
|
cli_conf_file = Fasp::Installation.instance.cli_conf_file
|
@@ -961,9 +962,9 @@ module Aspera
|
|
961
962
|
entry = data['AoCAccounts'].find{|i|i['organization'].eql?(organization)}
|
962
963
|
if entry.nil?
|
963
964
|
data['AoCAccounts'].push(new_conf)
|
964
|
-
|
965
|
+
formatter.display_status("Creating new aoc entry: #{organization}")
|
965
966
|
else
|
966
|
-
|
967
|
+
formatter.display_status("Updating existing aoc entry: #{organization}")
|
967
968
|
entry.merge!(new_conf)
|
968
969
|
end
|
969
970
|
File.write(cli_conf_file, JSON.pretty_generate(data))
|
@@ -1208,12 +1209,12 @@ module Aspera
|
|
1208
1209
|
end
|
1209
1210
|
|
1210
1211
|
def wizard_aoc(params)
|
1211
|
-
|
1212
|
+
formatter.display_status('Detected: Aspera on Cloud'.bold)
|
1212
1213
|
params[:plugin_name] = AOC_COMMAND_CURRENT
|
1213
1214
|
organization = AoC.parse_url(params[:instance_url]).first
|
1214
1215
|
# if not defined by user, generate name
|
1215
1216
|
params[:preset_name] = [params[:application], organization].join('_') if params[:preset_name].nil?
|
1216
|
-
|
1217
|
+
formatter.display_status("Preparing preset: #{params[:preset_name]}")
|
1217
1218
|
# init defaults if necessary
|
1218
1219
|
@config_presets[CONF_PRESET_DEFAULT] ||= {}
|
1219
1220
|
option_override = options.get_option(:override, is_type: :mandatory)
|
@@ -1227,7 +1228,7 @@ module Aspera
|
|
1227
1228
|
private_key_path = options.get_option(:pkeypath)
|
1228
1229
|
# give a chance to provide
|
1229
1230
|
if private_key_path.nil?
|
1230
|
-
|
1231
|
+
formatter.display_status('Please provide path to your private RSA key, or empty to generate one:')
|
1231
1232
|
private_key_path = options.get_option(:pkeypath, is_type: :mandatory).to_s
|
1232
1233
|
end
|
1233
1234
|
# else generate path
|
@@ -1235,45 +1236,45 @@ module Aspera
|
|
1235
1236
|
private_key_path = File.join(@main_folder, DEFAULT_PRIV_KEY_FILENAME)
|
1236
1237
|
end
|
1237
1238
|
if File.exist?(private_key_path)
|
1238
|
-
|
1239
|
+
formatter.display_status('Using existing key:')
|
1239
1240
|
else
|
1240
|
-
|
1241
|
+
formatter.display_status("Generating #{DEFAULT_PRIVKEY_LENGTH} bit RSA key...")
|
1241
1242
|
generate_rsa_private_key(private_key_path, DEFAULT_PRIVKEY_LENGTH)
|
1242
|
-
|
1243
|
+
formatter.display_status('Created:')
|
1243
1244
|
end
|
1244
|
-
|
1245
|
+
formatter.display_status(private_key_path)
|
1245
1246
|
pub_key_pem = OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
|
1246
1247
|
# declare command line options for AoC
|
1247
1248
|
require 'aspera/cli/plugins/aoc'
|
1248
1249
|
# make username mandatory for jwt, this triggers interactive input
|
1249
1250
|
options.get_option(:username, is_type: :mandatory)
|
1250
|
-
#
|
1251
|
+
# instantiate AoC plugin, so that command line options are known
|
1251
1252
|
aoc_api = self.class.plugin_class(params[:plugin_name]).new(@agents.merge({skip_basic_auth_options: true, private_key_path: private_key_path})).aoc_api
|
1252
1253
|
auto_set_pub_key = false
|
1253
1254
|
auto_set_jwt = false
|
1254
1255
|
use_browser_authentication = false
|
1255
1256
|
if options.get_option(:use_generic_client)
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1257
|
+
formatter.display_status('Using global client_id.')
|
1258
|
+
formatter.display_status('Please Login to your Aspera on Cloud instance.'.red)
|
1259
|
+
formatter.display_status('Navigate to your "Account Settings"'.red)
|
1260
|
+
formatter.display_status('Check or update the value of "Public Key" to be:'.red.blink)
|
1261
|
+
formatter.display_status(pub_key_pem.to_s)
|
1261
1262
|
if !options.get_option(:test_mode)
|
1262
|
-
|
1263
|
+
formatter.display_status('Once updated or validated, press enter.')
|
1263
1264
|
OpenApplication.instance.uri(params[:instance_url])
|
1264
1265
|
$stdin.gets
|
1265
1266
|
end
|
1266
1267
|
else
|
1267
|
-
|
1268
|
+
formatter.display_status('Using organization specific client_id.')
|
1268
1269
|
if options.get_option(:client_id).nil? || options.get_option(:client_secret, is_type: :optional).nil?
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1270
|
+
formatter.display_status('Please login to your Aspera on Cloud instance.'.red)
|
1271
|
+
formatter.display_status('Go to: Apps->Admin->Organization->Integrations')
|
1272
|
+
formatter.display_status('Create or check if there is an existing integration named:')
|
1273
|
+
formatter.display_status("- name: #{@info[:name]}")
|
1274
|
+
formatter.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
|
1275
|
+
formatter.display_status('- origin: localhost')
|
1276
|
+
formatter.display_status('Once created or identified,')
|
1277
|
+
formatter.display_status('Please enter:'.red)
|
1277
1278
|
end
|
1278
1279
|
OpenApplication.instance.uri("#{params[:instance_url]}/#{AOC_PATH_API_CLIENTS}")
|
1279
1280
|
options.get_option(:client_id, is_type: :mandatory)
|
@@ -1281,24 +1282,24 @@ module Aspera
|
|
1281
1282
|
use_browser_authentication = true
|
1282
1283
|
end
|
1283
1284
|
if use_browser_authentication
|
1284
|
-
|
1285
|
+
formatter.display_status('We will use web authentication to bootstrap.')
|
1285
1286
|
auto_set_pub_key = true
|
1286
1287
|
auto_set_jwt = true
|
1287
|
-
aoc_api.oauth.
|
1288
|
-
aoc_api.oauth.
|
1289
|
-
aoc_api.oauth.
|
1288
|
+
aoc_api.oauth.generic_parameters[:grant_method] = :web
|
1289
|
+
aoc_api.oauth.generic_parameters[:scope] = AoC::SCOPE_FILES_ADMIN
|
1290
|
+
aoc_api.oauth.specific_parameters[:redirect_uri] = DEFAULT_REDIRECT
|
1290
1291
|
end
|
1291
1292
|
myself = aoc_api.read('self')[:data]
|
1292
1293
|
if auto_set_pub_key
|
1293
1294
|
raise CliError, 'Public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? || option_override
|
1294
|
-
|
1295
|
+
formatter.display_status('Updating profile with new key')
|
1295
1296
|
aoc_api.update("users/#{myself['id']}", {'public_key' => pub_key_pem})
|
1296
1297
|
end
|
1297
1298
|
if auto_set_jwt
|
1298
|
-
|
1299
|
+
formatter.display_status('Enabling JWT for client')
|
1299
1300
|
aoc_api.update("clients/#{options.get_option(:client_id)}", {'jwt_grant_enabled' => true, 'explicit_authorization_required' => false})
|
1300
1301
|
end
|
1301
|
-
|
1302
|
+
formatter.display_status("Creating new config preset: #{params[:preset_name]}")
|
1302
1303
|
@config_presets[params[:preset_name]] = {
|
1303
1304
|
:url.to_s => options.get_option(:url),
|
1304
1305
|
:username.to_s => myself['email'],
|
@@ -1314,11 +1315,11 @@ module Aspera
|
|
1314
1315
|
end
|
1315
1316
|
|
1316
1317
|
def wizard_faspex5(params)
|
1317
|
-
|
1318
|
+
formatter.display_status('Detected: Faspex v5'.bold)
|
1318
1319
|
# if not defined by user, generate unique name
|
1319
1320
|
params[:preset_name] = [params[:application]].concat(URI.parse(params[:instance_url]).host.gsub(/[^a-z0-9.]/, '').split('.')).join('_') \
|
1320
1321
|
if params[:preset_name].nil?
|
1321
|
-
|
1322
|
+
formatter.display_status("Preparing preset: #{params[:preset_name]}")
|
1322
1323
|
# init defaults if necessary
|
1323
1324
|
@config_presets[CONF_PRESET_DEFAULT] ||= {}
|
1324
1325
|
option_override = options.get_option(:override, is_type: :mandatory)
|
@@ -1332,7 +1333,7 @@ module Aspera
|
|
1332
1333
|
private_key_path = options.get_option(:pkeypath)
|
1333
1334
|
# give a chance to provide
|
1334
1335
|
if private_key_path.nil?
|
1335
|
-
|
1336
|
+
formatter.display_status('Please provide path to your private RSA key, or empty to generate one:')
|
1336
1337
|
private_key_path = options.get_option(:pkeypath, is_type: :mandatory).to_s
|
1337
1338
|
end
|
1338
1339
|
# else generate path
|
@@ -1340,25 +1341,25 @@ module Aspera
|
|
1340
1341
|
private_key_path = File.join(@main_folder, DEFAULT_PRIV_KEY_FILENAME)
|
1341
1342
|
end
|
1342
1343
|
if File.exist?(private_key_path)
|
1343
|
-
|
1344
|
+
formatter.display_status('Using existing key:')
|
1344
1345
|
else
|
1345
|
-
|
1346
|
+
formatter.display_status("Generating #{DEFAULT_PRIVKEY_LENGTH} bit RSA key...")
|
1346
1347
|
generate_rsa_private_key(private_key_path, DEFAULT_PRIVKEY_LENGTH)
|
1347
|
-
|
1348
|
+
formatter.display_status('Created:')
|
1348
1349
|
end
|
1349
|
-
|
1350
|
+
formatter.display_status(private_key_path)
|
1350
1351
|
pub_key_pem = OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
|
1351
1352
|
# declare command line options for AoC
|
1352
1353
|
require 'aspera/cli/plugins/faspex5'
|
1353
1354
|
self.class.plugin_class(params[:plugin_name]).new(@agents.merge({skip_basic_auth_options: true}))
|
1354
|
-
|
1355
|
+
formatter.display_status('Please login to Faspex 5.'.red)
|
1355
1356
|
OpenApplication.instance.uri(params[:instance_url])
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1357
|
+
formatter.display_status('Navigate to: 𓃑 → Admin → Configurations → API clients')
|
1358
|
+
formatter.display_status('Create a client with:')
|
1359
|
+
formatter.display_status('- JWT enabled')
|
1360
|
+
formatter.display_status('- The following public key:')
|
1361
|
+
formatter.display_status(pub_key_pem.to_s)
|
1362
|
+
formatter.display_status('Once created, copy the following parameters:')
|
1362
1363
|
@config_presets[params[:preset_name]] = {
|
1363
1364
|
:url.to_s => options.get_option(:url),
|
1364
1365
|
:username.to_s => options.get_option(:username),
|
@@ -14,7 +14,7 @@ module Aspera
|
|
14
14
|
options.add_opt_simple(:bucket, 'Bucket name')
|
15
15
|
options.add_opt_simple(:endpoint, 'Storage endpoint url')
|
16
16
|
options.add_opt_simple(:apikey, 'Storage API key')
|
17
|
-
options.add_opt_simple(:crn, '
|
17
|
+
options.add_opt_simple(:crn, 'Resource instance id')
|
18
18
|
options.add_opt_simple(:service_credentials, 'IBM Cloud service credentials (Hash)')
|
19
19
|
options.add_opt_simple(:region, 'Storage region')
|
20
20
|
options.add_opt_simple(:identity, "Authentication url (#{CosNode::IBM_CLOUD_TOKEN_URL})")
|
@@ -46,24 +46,24 @@ module Aspera
|
|
46
46
|
if result[:http].body.start_with?('<?xml')
|
47
47
|
res_s = XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
|
48
48
|
version = res_s['XRD']['application']['version']
|
49
|
-
return {version: version}
|
49
|
+
return {version: version, url: result[:http].uri}
|
50
50
|
end
|
51
51
|
return nil
|
52
52
|
end
|
53
53
|
|
54
54
|
# extract elements from anonymous faspex link
|
55
|
-
def get_link_data(
|
56
|
-
|
57
|
-
raise CliBadArgument, 'Public link does not match Faspex format' unless (m =
|
55
|
+
def get_link_data(public_url)
|
56
|
+
public_uri = URI.parse(public_url)
|
57
|
+
raise CliBadArgument, 'Public link does not match Faspex format' unless (m = public_uri.path.match(%r{^(.*)/(external.*)$}))
|
58
58
|
base = m[1]
|
59
59
|
subpath = m[2]
|
60
|
-
port_add =
|
60
|
+
port_add = public_uri.port.eql?(public_uri.default_port) ? '' : ":#{public_uri.port}"
|
61
61
|
result = {
|
62
|
-
base_url: "#{
|
62
|
+
base_url: "#{public_uri.scheme}://#{public_uri.host}#{port_add}#{base}",
|
63
63
|
subpath: subpath,
|
64
|
-
query: URI.decode_www_form(
|
64
|
+
query: URI.decode_www_form(public_uri.query).each_with_object({}){|v, h|h[v.first] = v.last; }
|
65
65
|
}
|
66
|
-
Log.dump('
|
66
|
+
Log.dump('link data', result)
|
67
67
|
return result
|
68
68
|
end
|
69
69
|
|
@@ -125,12 +125,12 @@ module Aspera
|
|
125
125
|
@api_v4 = Rest.new({
|
126
126
|
base_url: faspex_api_base + '/api',
|
127
127
|
auth: {
|
128
|
-
type:
|
129
|
-
base_url:
|
130
|
-
auth:
|
131
|
-
|
132
|
-
generic:
|
133
|
-
scope:
|
128
|
+
type: :oauth2,
|
129
|
+
base_url: faspex_api_base + '/auth/oauth2',
|
130
|
+
auth: {type: :basic, username: options.get_option(:username, is_type: :mandatory), password: options.get_option(:password, is_type: :mandatory)},
|
131
|
+
grant_method: :generic,
|
132
|
+
generic: {grant_type: 'password'},
|
133
|
+
scope: 'admin'
|
134
134
|
}})
|
135
135
|
end
|
136
136
|
return @api_v4
|
@@ -205,7 +205,7 @@ module Aspera
|
|
205
205
|
end
|
206
206
|
|
207
207
|
# retrieve transfer spec from pub link for send package
|
208
|
-
def
|
208
|
+
def send_public_link_to_ts(public_link_url, package_create_params)
|
209
209
|
delivery_info = package_create_params['delivery']
|
210
210
|
# pub link user
|
211
211
|
link_data = self.class.get_link_data(public_link_url)
|
@@ -215,28 +215,28 @@ module Aspera
|
|
215
215
|
create_path = link_data[:subpath].split('/')[0..-2].join('/')
|
216
216
|
package_create_params[:passcode] = link_data[:query]['passcode']
|
217
217
|
delivery_info[:transfer_type] = 'connect'
|
218
|
-
delivery_info[:source_paths_list] = transfer.
|
218
|
+
delivery_info[:source_paths_list] = transfer.source_list.join("\r\n")
|
219
219
|
api_public_link = Rest.new({base_url: link_data[:base_url]})
|
220
220
|
# Hum, as this does not always work (only user, but not dropbox), we get the javascript and need hack
|
221
221
|
# pkg_created=api_public_link.create(create_path,package_create_params)[:data]
|
222
222
|
# so extract data from javascript
|
223
|
-
|
223
|
+
package_creation_data = api_public_link.call({
|
224
224
|
operation: 'POST',
|
225
225
|
subpath: create_path,
|
226
226
|
json_params: package_create_params,
|
227
227
|
headers: {'Accept' => 'text/javascript'}})[:http].body
|
228
228
|
# get args of function call
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
229
|
+
package_creation_data.delete!("\n") # one line
|
230
|
+
package_creation_data.gsub!(/^[^"]+\("\{/, '{') # delete header
|
231
|
+
package_creation_data.gsub!(/"\);[^"]+$/, '"') # delete trailer
|
232
|
+
package_creation_data.gsub!(/\}", *"/, '},"') # between two args
|
233
|
+
package_creation_data.gsub!('\\"', '"') # remove protecting quote
|
234
234
|
begin
|
235
|
-
|
235
|
+
package_creation_data = JSON.parse("[#{package_creation_data}]")
|
236
236
|
rescue JSON::ParserError # => e
|
237
237
|
raise 'Unexpected response: missing metadata ?'
|
238
238
|
end
|
239
|
-
return
|
239
|
+
return package_creation_data.first
|
240
240
|
end
|
241
241
|
|
242
242
|
ACTIONS = %i[health package source me dropbox v4 address_book login_methods].freeze
|
@@ -273,7 +273,7 @@ module Aspera
|
|
273
273
|
# authenticated user
|
274
274
|
delivery_info['sources'] ||= [{'paths' => []}]
|
275
275
|
first_source = delivery_info['sources'].first
|
276
|
-
first_source['paths'].push(*transfer.
|
276
|
+
first_source['paths'].push(*transfer.source_list)
|
277
277
|
source_name = options.get_option(:source_name)
|
278
278
|
if !source_name.nil?
|
279
279
|
source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
|
@@ -294,8 +294,8 @@ module Aspera
|
|
294
294
|
transfer_spec = pkg_created['xfer_sessions'].first
|
295
295
|
# use source from cmd line, this one only contains destination (already in dest root)
|
296
296
|
transfer_spec.delete('paths')
|
297
|
-
else #
|
298
|
-
transfer_spec =
|
297
|
+
else # public link
|
298
|
+
transfer_spec = send_public_link_to_ts(public_link_url, package_create_params)
|
299
299
|
end
|
300
300
|
# Log.dump('transfer_spec',transfer_spec)
|
301
301
|
return Main.result_transfer(transfer.start(transfer_spec))
|
@@ -319,15 +319,15 @@ module Aspera
|
|
319
319
|
]))
|
320
320
|
end
|
321
321
|
# get command line parameters
|
322
|
-
|
323
|
-
raise 'empty id' if
|
322
|
+
delivery_id = instance_identifier
|
323
|
+
raise 'empty id' if delivery_id.empty?
|
324
324
|
recipient = options.get_option(:recipient)
|
325
|
-
if VAL_ALL.eql?(
|
325
|
+
if VAL_ALL.eql?(delivery_id)
|
326
326
|
pkg_id_uri = mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD], uri: self.class.get_fasp_uri_from_entry(i, raise_no_link: false)}}
|
327
327
|
elsif !recipient.nil? && recipient.start_with?('*')
|
328
|
-
found_package_link = mailbox_filtered_entries(stop_at_id:
|
328
|
+
found_package_link = mailbox_filtered_entries(stop_at_id: delivery_id).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivery_id)}['link'].first['href']
|
329
329
|
raise 'Not Found. Dropbox and Workgroup packages can use the link option with faspe:' if found_package_link.nil?
|
330
|
-
pkg_id_uri = [{id:
|
330
|
+
pkg_id_uri = [{id: delivery_id, uri: found_package_link}]
|
331
331
|
else
|
332
332
|
# TODO: delivery id is the right one if package was receive by workgroup
|
333
333
|
endpoint =
|
@@ -335,9 +335,9 @@ module Aspera
|
|
335
335
|
when :inbox, :archive then'received'
|
336
336
|
when :sent then 'sent'
|
337
337
|
end
|
338
|
-
entry_xml = api_v3.call({operation: 'GET', subpath: "#{endpoint}/#{
|
338
|
+
entry_xml = api_v3.call({operation: 'GET', subpath: "#{endpoint}/#{delivery_id}", headers: {'Accept' => 'application/xml'}})[:http].body
|
339
339
|
package_entry = XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
|
340
|
-
pkg_id_uri = [{id:
|
340
|
+
pkg_id_uri = [{id: delivery_id, uri: self.class.get_fasp_uri_from_entry(package_entry)}]
|
341
341
|
end
|
342
342
|
when /^faspe:/
|
343
343
|
pkg_id_uri = [{id: 'package', uri: link_url}]
|
@@ -348,16 +348,16 @@ module Aspera
|
|
348
348
|
end
|
349
349
|
# NOTE: unauthenticated API (authorization is in url params)
|
350
350
|
api_public_link = Rest.new({base_url: link_data[:base_url]})
|
351
|
-
|
351
|
+
package_creation_data = api_public_link.call(
|
352
352
|
operation: 'GET',
|
353
353
|
subpath: link_data[:subpath],
|
354
354
|
url_params: {passcode: link_data[:query]['passcode']},
|
355
355
|
headers: {'Accept' => 'application/xml'})
|
356
|
-
if !
|
356
|
+
if !package_creation_data[:http].body.start_with?('<?xml ')
|
357
357
|
OpenApplication.instance.uri(link_url)
|
358
358
|
raise CliError, 'Unexpected response: package not found ?'
|
359
359
|
end
|
360
|
-
package_entry = XmlSimple.xml_in(
|
360
|
+
package_entry = XmlSimple.xml_in(package_creation_data[:http].body, {'ForceArray' => false})
|
361
361
|
Log.dump(:package_entry, package_entry)
|
362
362
|
transfer_uri = self.class.get_fasp_uri_from_entry(package_entry)
|
363
363
|
pkg_id_uri = [{id: package_entry['id'], uri: transfer_uri}]
|
@@ -480,7 +480,7 @@ module Aspera
|
|
480
480
|
headers: {'Accept' => 'application/json'},
|
481
481
|
url_params: {'format' => 'json', 'count' => 100_000}
|
482
482
|
)[:data]
|
483
|
-
|
483
|
+
formatter.display_status("users: #{result['itemsPerPage']}/#{result['totalResults']}, start:#{result['startIndex']}")
|
484
484
|
users = result['entry']
|
485
485
|
# add missing entries
|
486
486
|
users.each do |u|
|