aspera-cli 4.10.0 → 4.11.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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +20 -0
  4. data/CHANGELOG.md +509 -0
  5. data/CONTRIBUTING.md +118 -0
  6. data/README.md +621 -378
  7. data/bin/ascli +4 -4
  8. data/bin/asession +11 -11
  9. data/docs/test_env.conf +28 -19
  10. data/examples/aoc.rb +4 -4
  11. data/examples/dascli +11 -9
  12. data/examples/faspex4.rb +8 -8
  13. data/examples/node.rb +11 -11
  14. data/examples/server.rb +9 -9
  15. data/lib/aspera/aoc.rb +273 -266
  16. data/lib/aspera/ascmd.rb +56 -54
  17. data/lib/aspera/ats_api.rb +4 -4
  18. data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
  19. data/lib/aspera/cli/extended_value.rb +5 -5
  20. data/lib/aspera/cli/formater.rb +64 -64
  21. data/lib/aspera/cli/listener/line_dump.rb +1 -1
  22. data/lib/aspera/cli/listener/logger.rb +1 -1
  23. data/lib/aspera/cli/listener/progress.rb +5 -6
  24. data/lib/aspera/cli/listener/progress_multi.rb +14 -19
  25. data/lib/aspera/cli/main.rb +66 -67
  26. data/lib/aspera/cli/manager.rb +110 -110
  27. data/lib/aspera/cli/plugin.rb +54 -37
  28. data/lib/aspera/cli/plugins/alee.rb +4 -4
  29. data/lib/aspera/cli/plugins/aoc.rb +308 -669
  30. data/lib/aspera/cli/plugins/ats.rb +44 -46
  31. data/lib/aspera/cli/plugins/bss.rb +10 -10
  32. data/lib/aspera/cli/plugins/config.rb +447 -344
  33. data/lib/aspera/cli/plugins/console.rb +12 -12
  34. data/lib/aspera/cli/plugins/cos.rb +18 -20
  35. data/lib/aspera/cli/plugins/faspex.rb +110 -112
  36. data/lib/aspera/cli/plugins/faspex5.rb +67 -46
  37. data/lib/aspera/cli/plugins/node.rb +364 -288
  38. data/lib/aspera/cli/plugins/orchestrator.rb +46 -46
  39. data/lib/aspera/cli/plugins/preview.rb +122 -114
  40. data/lib/aspera/cli/plugins/server.rb +137 -83
  41. data/lib/aspera/cli/plugins/shares.rb +30 -29
  42. data/lib/aspera/cli/plugins/sync.rb +13 -33
  43. data/lib/aspera/cli/transfer_agent.rb +57 -57
  44. data/lib/aspera/cli/version.rb +1 -1
  45. data/lib/aspera/colors.rb +3 -3
  46. data/lib/aspera/command_line_builder.rb +27 -27
  47. data/lib/aspera/cos_node.rb +22 -20
  48. data/lib/aspera/data_repository.rb +1 -1
  49. data/lib/aspera/environment.rb +30 -28
  50. data/lib/aspera/fasp/agent_base.rb +15 -15
  51. data/lib/aspera/fasp/agent_connect.rb +23 -21
  52. data/lib/aspera/fasp/agent_direct.rb +65 -67
  53. data/lib/aspera/fasp/agent_httpgw.rb +72 -68
  54. data/lib/aspera/fasp/agent_node.rb +23 -21
  55. data/lib/aspera/fasp/agent_trsdk.rb +20 -20
  56. data/lib/aspera/fasp/error.rb +3 -2
  57. data/lib/aspera/fasp/error_info.rb +11 -8
  58. data/lib/aspera/fasp/installation.rb +78 -78
  59. data/lib/aspera/fasp/listener.rb +1 -1
  60. data/lib/aspera/fasp/parameters.rb +75 -72
  61. data/lib/aspera/fasp/parameters.yaml +2 -2
  62. data/lib/aspera/fasp/resume_policy.rb +8 -8
  63. data/lib/aspera/fasp/transfer_spec.rb +35 -2
  64. data/lib/aspera/fasp/uri.rb +7 -7
  65. data/lib/aspera/faspex_gw.rb +7 -5
  66. data/lib/aspera/hash_ext.rb +3 -3
  67. data/lib/aspera/id_generator.rb +5 -5
  68. data/lib/aspera/keychain/encrypted_hash.rb +23 -28
  69. data/lib/aspera/keychain/macos_security.rb +21 -20
  70. data/lib/aspera/log.rb +7 -7
  71. data/lib/aspera/nagios.rb +19 -18
  72. data/lib/aspera/node.rb +209 -35
  73. data/lib/aspera/oauth.rb +37 -36
  74. data/lib/aspera/open_application.rb +19 -11
  75. data/lib/aspera/persistency_action_once.rb +4 -4
  76. data/lib/aspera/persistency_folder.rb +13 -13
  77. data/lib/aspera/preview/file_types.rb +8 -8
  78. data/lib/aspera/preview/generator.rb +67 -67
  79. data/lib/aspera/preview/utils.rb +27 -27
  80. data/lib/aspera/proxy_auto_config.js +41 -41
  81. data/lib/aspera/proxy_auto_config.rb +16 -16
  82. data/lib/aspera/rest.rb +56 -60
  83. data/lib/aspera/rest_call_error.rb +2 -1
  84. data/lib/aspera/rest_error_analyzer.rb +18 -17
  85. data/lib/aspera/rest_errors_aspera.rb +16 -16
  86. data/lib/aspera/secret_hider.rb +15 -13
  87. data/lib/aspera/ssh.rb +11 -10
  88. data/lib/aspera/sync.rb +158 -44
  89. data/lib/aspera/temp_file_manager.rb +2 -2
  90. data/lib/aspera/uri_reader.rb +4 -4
  91. data/lib/aspera/web_auth.rb +14 -13
  92. data.tar.gz.sig +0 -0
  93. metadata +8 -5
  94. metadata.gz.sig +0 -0
@@ -28,7 +28,7 @@ module Aspera
28
28
  module Cli
29
29
  module Plugins
30
30
  # manage the CLI config file
31
- class Config < Plugin
31
+ class Config < Aspera::Cli::Plugin
32
32
  # folder in $HOME for application files (config, cache)
33
33
  ASPERA_HOME_FOLDER_NAME = '.aspera'
34
34
  # default config file
@@ -74,13 +74,33 @@ module Aspera
74
74
  DEFAULT_CHECK_NEW_VERSION_DAYS = 7
75
75
  DEFAULT_PRIV_KEY_FILENAME = 'aspera_aoc_key' # pragma: allowlist secret
76
76
  DEFAULT_PRIVKEY_LENGTH = 4096
77
- private_constant :DEFAULT_CONFIG_FILENAME,:CONF_PRESET_CONFIG,:CONF_PRESET_VERSION,:CONF_PRESET_DEFAULT,
78
- :CONF_PRESET_GLOBAL,:PROGRAM_NAME_V1,:PROGRAM_NAME_V2,:DEFAULT_REDIRECT,:ASPERA_PLUGINS_FOLDERNAME,
79
- :RUBY_FILE_EXT,:AOC_COMMAND_V1,:AOC_COMMAND_V2,:AOC_COMMAND_V3,:AOC_COMMAND_CURRENT,:DEMO,
80
- :TRANSFER_SDK_ARCHIVE_URL,:AOC_PATH_API_CLIENTS,:DEMO_SERVER_PRESET,:EMAIL_TEST_TEMPLATE,:EXTV_INCLUDE_PRESETS,
81
- :EXTV_PRESET,:EXTV_VAULT,:DEFAULT_CHECK_NEW_VERSION_DAYS,:DEFAULT_PRIV_KEY_FILENAME,:SERVER_COMMAND,
77
+ private_constant :DEFAULT_CONFIG_FILENAME,
78
+ :CONF_PRESET_CONFIG,
79
+ :CONF_PRESET_VERSION,
80
+ :CONF_PRESET_DEFAULT,
81
+ :CONF_PRESET_GLOBAL,
82
+ :PROGRAM_NAME_V1,
83
+ :PROGRAM_NAME_V2,
84
+ :DEFAULT_REDIRECT,
85
+ :ASPERA_PLUGINS_FOLDERNAME,
86
+ :RUBY_FILE_EXT,
87
+ :AOC_COMMAND_V1,
88
+ :AOC_COMMAND_V2,
89
+ :AOC_COMMAND_V3,
90
+ :AOC_COMMAND_CURRENT,
91
+ :DEMO,
92
+ :TRANSFER_SDK_ARCHIVE_URL,
93
+ :AOC_PATH_API_CLIENTS,
94
+ :DEMO_SERVER_PRESET,
95
+ :EMAIL_TEST_TEMPLATE,
96
+ :EXTV_INCLUDE_PRESETS,
97
+ :EXTV_PRESET,
98
+ :EXTV_VAULT,
99
+ :DEFAULT_CHECK_NEW_VERSION_DAYS,
100
+ :DEFAULT_PRIV_KEY_FILENAME,
101
+ :SERVER_COMMAND,
82
102
  :PRESET_DIG_SEPARATOR
83
- def initialize(env,params)
103
+ def initialize(env, params)
84
104
  raise 'env and params must be Hash' unless env.is_a?(Hash) && params.is_a?(Hash)
85
105
  raise 'missing param' unless %i[name help version gem].sort.eql?(params.keys.sort)
86
106
  super(env)
@@ -92,69 +112,69 @@ module Aspera
92
112
  @config_presets = nil
93
113
  @connect_versions = nil
94
114
  @vault = nil
95
- @conf_file_default = File.join(@main_folder,DEFAULT_CONFIG_FILENAME)
115
+ @conf_file_default = File.join(@main_folder, DEFAULT_CONFIG_FILENAME)
96
116
  @option_config_file = @conf_file_default
97
117
  @pac_exec = nil
98
- Log.log.debug("#{@info[:name]} folder: #{@main_folder}")
118
+ Log.log.debug{"#{@info[:name]} folder: #{@main_folder}"}
99
119
  # set folder for FASP SDK
100
120
  add_plugin_lookup_folder(self.class.gem_plugins_folder)
101
- add_plugin_lookup_folder(File.join(@main_folder,ASPERA_PLUGINS_FOLDERNAME))
121
+ add_plugin_lookup_folder(File.join(@main_folder, ASPERA_PLUGINS_FOLDERNAME))
102
122
  # do file parameter first
103
- options.set_obj_attr(:config_file,self,:option_config_file)
104
- options.add_opt_simple(:config_file,"read parameters from file in YAML format, current=#{@option_config_file}")
123
+ options.set_obj_attr(:config_file, self, :option_config_file)
124
+ options.add_opt_simple(:config_file, "read parameters from file in YAML format, current=#{@option_config_file}")
105
125
  options.parse_options!
106
- # read correct file
126
+ # read correct file (set @config_presets)
107
127
  read_config_file
108
128
  # add preset handler (needed for smtp)
109
- ExtendedValue.instance.set_handler(EXTV_PRESET,:reader,lambda{|v|preset_by_name(v)})
110
- ExtendedValue.instance.set_handler(EXTV_INCLUDE_PRESETS,:decoder,lambda{|v|expanded_with_preset_includes(v)})
111
- ExtendedValue.instance.set_handler(EXTV_VAULT,:decoder,lambda{|v|vault_value(v)})
129
+ ExtendedValue.instance.set_handler(EXTV_PRESET, :reader, lambda{|v|preset_by_name(v)})
130
+ ExtendedValue.instance.set_handler(EXTV_INCLUDE_PRESETS, :decoder, lambda{|v|expanded_with_preset_includes(v)})
131
+ ExtendedValue.instance.set_handler(EXTV_VAULT, :decoder, lambda{|v|vault_value(v)})
112
132
  # load defaults before it can be overriden
113
133
  add_plugin_default_preset(CONF_GLOBAL_SYM)
114
134
  options.parse_options!
115
- options.set_obj_attr(:ascp_path,Fasp::Installation.instance,:ascp_path)
116
- options.set_obj_attr(:sdk_folder,Fasp::Installation.instance,:sdk_folder)
117
- options.set_obj_attr(:use_product,self,:option_use_product)
118
- options.set_obj_attr(:preset,self,:option_preset)
119
- options.set_obj_attr(:plugin_folder,self,:option_plugin_folder)
120
- options.add_opt_switch(:no_default,'-N','do not load default configuration for plugin') { @use_plugin_defaults = false }
121
- options.add_opt_boolean(:override,'Wizard: override existing value')
122
- options.add_opt_boolean(:use_generic_client,'Wizard: AoC: use global or org specific jwt client id')
123
- options.add_opt_boolean(:default,'Wizard: set as default configuration for specified plugin (also: update)')
124
- options.add_opt_boolean(:test_mode,'Wizard: skip private key check step')
125
- options.add_opt_simple(:preset,'-PVALUE','load the named option preset from current config file')
126
- options.add_opt_simple(:pkeypath,'Wizard: path to private key for JWT')
127
- options.add_opt_simple(:ascp_path,'Path to ascp')
128
- options.add_opt_simple(:use_product,'Use ascp from specified product')
129
- options.add_opt_simple(:smtp,'SMTP configuration (extended value: hash)')
130
- options.add_opt_simple(:fpac,'Proxy auto configuration script')
131
- options.add_opt_simple(:proxy_credentials,'HTTP proxy credentials (Array with user and password)')
132
- options.add_opt_simple(:secret,'Secret for access keys')
133
- options.add_opt_simple(:vault,'Vault for secrets')
134
- options.add_opt_simple(:vault_password,'Vault password')
135
- options.add_opt_simple(:sdk_url,'URL to get SDK')
136
- options.add_opt_simple(:sdk_folder,'SDK folder path')
137
- options.add_opt_simple(:notif_to,'Email recipient for notification of transfers')
138
- options.add_opt_simple(:notif_template,'Email ERB template for notification of transfers')
139
- options.add_opt_simple(:version_check_days,Integer,'Period in days to check new version (zero to disable)')
140
- options.add_opt_simple(:plugin_folder,'Folder where to find additional plugins')
141
- options.set_option(:use_generic_client,true)
142
- options.set_option(:test_mode,false)
143
- options.set_option(:default,true)
144
- options.set_option(:version_check_days,DEFAULT_CHECK_NEW_VERSION_DAYS)
145
- options.set_option(:sdk_url,TRANSFER_SDK_ARCHIVE_URL)
146
- options.set_option(:sdk_folder,File.join(@main_folder,'sdk'))
147
- options.set_option(:override,:no)
135
+ options.set_obj_attr(:ascp_path, Fasp::Installation.instance, :ascp_path)
136
+ options.set_obj_attr(:sdk_folder, Fasp::Installation.instance, :sdk_folder)
137
+ options.set_obj_attr(:use_product, self, :option_use_product)
138
+ options.set_obj_attr(:preset, self, :option_preset)
139
+ options.set_obj_attr(:plugin_folder, self, :option_plugin_folder)
140
+ options.add_opt_switch(:no_default, '-N', 'do not load default configuration for plugin') { @use_plugin_defaults = false }
141
+ options.add_opt_boolean(:override, 'Wizard: override existing value')
142
+ options.add_opt_boolean(:use_generic_client, 'Wizard: AoC: use global or org specific jwt client id')
143
+ options.add_opt_boolean(:default, 'Wizard: set as default configuration for specified plugin (also: update)')
144
+ options.add_opt_boolean(:test_mode, 'Wizard: skip private key check step')
145
+ options.add_opt_simple(:preset, '-PVALUE', 'load the named option preset from current config file')
146
+ options.add_opt_simple(:pkeypath, 'Wizard: path to private key for JWT')
147
+ options.add_opt_simple(:ascp_path, 'Path to ascp')
148
+ options.add_opt_simple(:use_product, 'Use ascp from specified product')
149
+ options.add_opt_simple(:smtp, 'SMTP configuration (extended value: hash)')
150
+ options.add_opt_simple(:fpac, 'Proxy auto configuration script')
151
+ options.add_opt_simple(:proxy_credentials, 'HTTP proxy credentials (Array with user and password)')
152
+ options.add_opt_simple(:secret, 'Secret for access keys')
153
+ options.add_opt_simple(:vault, 'Vault for secrets')
154
+ options.add_opt_simple(:vault_password, 'Vault password')
155
+ options.add_opt_simple(:sdk_url, 'URL to get SDK')
156
+ options.add_opt_simple(:sdk_folder, 'SDK folder path')
157
+ options.add_opt_simple(:notif_to, 'Email recipient for notification of transfers')
158
+ options.add_opt_simple(:notif_template, 'Email ERB template for notification of transfers')
159
+ options.add_opt_simple(:version_check_days, Integer, 'Period in days to check new version (zero to disable)')
160
+ options.add_opt_simple(:plugin_folder, 'Folder where to find additional plugins')
161
+ options.set_option(:use_generic_client, true)
162
+ options.set_option(:test_mode, false)
163
+ options.set_option(:default, true)
164
+ options.set_option(:version_check_days, DEFAULT_CHECK_NEW_VERSION_DAYS)
165
+ options.set_option(:sdk_url, TRANSFER_SDK_ARCHIVE_URL)
166
+ options.set_option(:sdk_folder, File.join(@main_folder, 'sdk'))
167
+ options.set_option(:override, :no)
148
168
  options.parse_options!
149
169
  pac_script = options.get_option(:fpac)
150
170
  # create PAC executor
151
171
  @pac_exec = Aspera::ProxyAutoConfig.new(pac_script).register_uri_generic unless pac_script.nil?
152
- proxy_creds=options.get_option(:proxy_credentials)
172
+ proxy_creds = options.get_option(:proxy_credentials)
153
173
  if !proxy_creds.nil?
154
- raise CliBadArgument,'proxy credentials shall be an array (#{proxy_creds.class})' unless proxy_creds.is_a?(Array)
155
- raise CliBadArgument,'proxy credentials shall have two elements (#{proxy_creds.length})' unless proxy_creds.length.eql?(2)
156
- @pac_exec.proxy_user=Rest.proxy_user=proxy_creds[0]
157
- @pac_exec.proxy_pass=Rest.proxy_pass=proxy_creds[1]
174
+ raise CliBadArgument, 'proxy credentials shall be an array (#{proxy_creds.class})' unless proxy_creds.is_a?(Array)
175
+ raise CliBadArgument, 'proxy credentials shall have two elements (#{proxy_creds.length})' unless proxy_creds.length.eql?(2)
176
+ @pac_exec.proxy_user = Rest.proxy_user = proxy_creds[0]
177
+ @pac_exec.proxy_pass = Rest.proxy_pass = proxy_creds[1]
158
178
  end
159
179
  end
160
180
 
@@ -170,8 +190,8 @@ module Aspera
170
190
  # if env var undefined or empty
171
191
  if app_folder.nil? || app_folder.empty?
172
192
  user_home_folder = Dir.home
173
- raise CliError,"Home folder does not exist: #{user_home_folder}. Check your user environment or use #{conf_dir_env_var}." unless Dir.exist?(user_home_folder)
174
- app_folder = File.join(user_home_folder,ASPERA_HOME_FOLDER_NAME,@info[:name])
193
+ raise CliError, "Home folder does not exist: #{user_home_folder}. Check your user environment or use #{conf_dir_env_var}." unless Dir.exist?(user_home_folder)
194
+ app_folder = File.join(user_home_folder, ASPERA_HOME_FOLDER_NAME, @info[:name])
175
195
  end
176
196
  return app_folder
177
197
  end
@@ -185,8 +205,10 @@ module Aspera
185
205
  '0'
186
206
  end
187
207
  if Gem::Version.new(Environment.ruby_version) < Gem::Version.new(RUBY_FUTURE_MINIMUM_VERSION)
188
- Log.log.warn("Note that a future version will require Ruby version #{RUBY_FUTURE_MINIMUM_VERSION} at minimum, "\
189
- "you are using #{Environment.ruby_version}")
208
+ Log.log.warn do
209
+ "Note that a future version will require Ruby version #{RUBY_FUTURE_MINIMUM_VERSION} at minimum, "\
210
+ "you are using #{Environment.ruby_version}"
211
+ end
190
212
  end
191
213
  return {
192
214
  name: @info[:gem],
@@ -198,8 +220,8 @@ module Aspera
198
220
 
199
221
  def periodic_check_newer_gem_version
200
222
  # get verification period
201
- delay_days = options.get_option(:version_check_days,is_type: :mandatory)
202
- Log.log.info("check days: #{delay_days}")
223
+ delay_days = options.get_option(:version_check_days, is_type: :mandatory)
224
+ Log.log.info{"check days: #{delay_days}"}
203
225
  # check only if not zero day
204
226
  return if delay_days.eql?(0)
205
227
  # get last date from persistency
@@ -217,28 +239,29 @@ module Aspera
217
239
  # negative value will force check
218
240
  -1
219
241
  end
220
- Log.log.debug("days elapsed: #{last_check_days}")
242
+ Log.log.debug{"days elapsed: #{last_check_days}"}
221
243
  return if last_check_days < delay_days
222
244
  # generate timestamp
223
245
  last_check_array[0] = current_date.strftime('%Y/%m/%d')
224
246
  check_date_persist.save
225
247
  # compare this version and the one on internet
226
248
  check_data = check_gem_version
227
- Log.log.warn("A new version is available: #{check_data[:latest]}. "\
228
- "You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:name]}") if check_data[:need_update]
249
+ Log.log.warn do
250
+ "A new version is available: #{check_data[:latest]}. You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:name]}"
251
+ end if check_data[:need_update]
229
252
  end
230
253
 
231
254
  # retrieve structure from cloud (CDN) with all versions available
232
255
  def connect_versions
233
256
  if @connect_versions.nil?
234
257
  api_connect_cdn = Rest.new({base_url: CONNECT_WEB_URL})
235
- javascript = api_connect_cdn.call({operation: 'GET',subpath: CONNECT_VERSIONS})
258
+ javascript = api_connect_cdn.call({operation: 'GET', subpath: CONNECT_VERSIONS})
236
259
  # get result on one line
237
- connect_versions_javascript = javascript[:http].body.gsub(/\r?\n\s*/,'')
238
- Log.log.debug("javascript=[\n#{connect_versions_javascript}\n]")
260
+ connect_versions_javascript = javascript[:http].body.gsub(/\r?\n\s*/, '')
261
+ Log.log.debug{"javascript=[\n#{connect_versions_javascript}\n]"}
239
262
  # get javascript object only
240
263
  found = connect_versions_javascript.match(/^.*? = (.*);/)
241
- raise CliError,'Problen when getting connect versions from internet' if found.nil?
264
+ raise CliError, 'Problen when getting connect versions from internet' if found.nil?
242
265
  alldata = JSON.parse(found[1])
243
266
  @connect_versions = alldata['entries']
244
267
  end
@@ -251,18 +274,18 @@ module Aspera
251
274
  # @param plugin_name_sym : symbol for plugin name
252
275
  def add_plugin_default_preset(plugin_name_sym)
253
276
  default_config_name = get_plugin_default_config_name(plugin_name_sym)
254
- Log.log.debug("add_plugin_default_preset:#{plugin_name_sym}:#{default_config_name}")
255
- options.add_option_preset(preset_by_name(default_config_name),op: :unshift) unless default_config_name.nil?
277
+ Log.log.debug{"add_plugin_default_preset:#{plugin_name_sym}:#{default_config_name}"}
278
+ options.add_option_preset(preset_by_name(default_config_name), op: :unshift) unless default_config_name.nil?
256
279
  return nil
257
280
  end
258
281
 
259
282
  private
260
283
 
261
- def generate_rsa_private_key(private_key_path,length)
284
+ def generate_rsa_private_key(private_key_path, length)
262
285
  require 'openssl'
263
286
  priv_key = OpenSSL::PKey::RSA.new(length)
264
- File.write(private_key_path,priv_key.to_s)
265
- File.write(private_key_path + '.pub',priv_key.public_key.to_s)
287
+ File.write(private_key_path, priv_key.to_s)
288
+ File.write(private_key_path + '.pub', priv_key.public_key.to_s)
266
289
  Environment.restrict_file_access(private_key_path)
267
290
  Environment.restrict_file_access(private_key_path + '.pub')
268
291
  nil
@@ -283,7 +306,7 @@ module Aspera
283
306
  # @return main folder where code is, i.e. .../lib
284
307
  # go up as many times as englobing modules (not counting class, as it is a file)
285
308
  def gem_src_root
286
- File.expand_path(module_full_name.gsub('::','/').gsub(%r{[^/]+},'..'),gem_plugins_folder)
309
+ File.expand_path(module_full_name.gsub('::', '/').gsub(%r{[^/]+}, '..'), gem_plugins_folder)
287
310
  end
288
311
 
289
312
  # instanciate a plugin
@@ -297,7 +320,7 @@ module Aspera
297
320
  # set parameter and value in global config
298
321
  # creates one if none already created
299
322
  # @return preset name that contains global default
300
- def set_global_default(key,value)
323
+ def set_global_default(key, value)
301
324
  # get default preset if it exists
302
325
  global_default_preset_name = get_plugin_default_config_name(CONF_GLOBAL_SYM)
303
326
  if global_default_preset_name.nil?
@@ -323,17 +346,17 @@ module Aspera
323
346
  # @param config_name name of the preset in config file
324
347
  # @param include_path used to detect and avoid include loops
325
348
  def preset_by_name(config_name, include_path=[])
326
- raise CliError,'loop in include' if include_path.include?(config_name)
349
+ raise CliError, 'loop in include' if include_path.include?(config_name)
327
350
  include_path = include_path.clone # avoid messing up if there are multiple branches
328
351
  current = @config_presets
329
352
  config_name.split(PRESET_DIG_SEPARATOR).each do |name|
330
- raise CliError,"not a Hash: #{include_path} (#{current.class})" unless current.is_a?(Hash)
353
+ raise CliError, "Expecting Hash for subkey: #{include_path} (#{current.class})" unless current.is_a?(Hash)
331
354
  include_path.push(name)
332
355
  current = current[name]
333
- raise CliError,"no such config preset: #{include_path}" if nil?
356
+ raise CliError, "No such config preset: #{include_path}" if current.nil?
334
357
  end
335
358
  case current
336
- when Hash then return expanded_with_preset_includes(current,include_path)
359
+ when Hash then return expanded_with_preset_includes(current, include_path)
337
360
  when String then return ExtendedValue.instance.evaluate(current)
338
361
  else return current
339
362
  end
@@ -343,8 +366,8 @@ module Aspera
343
366
  # @param hash_val
344
367
  # @param include_path to avoid inclusion loop
345
368
  def expanded_with_preset_includes(hash_val, include_path=[])
346
- raise CliError,"#{EXTV_INCLUDE_PRESETS} requires a Hash, have #{hash_val.class}" unless hash_val.is_a?(Hash)
347
- if hash_val.has_key?(EXTV_INCLUDE_PRESETS)
369
+ raise CliError, "#{EXTV_INCLUDE_PRESETS} requires a Hash, have #{hash_val.class}" unless hash_val.is_a?(Hash)
370
+ if hash_val.key?(EXTV_INCLUDE_PRESETS)
348
371
  memory = hash_val.clone
349
372
  includes = memory[EXTV_INCLUDE_PRESETS]
350
373
  memory.delete(EXTV_INCLUDE_PRESETS)
@@ -352,7 +375,7 @@ module Aspera
352
375
  raise "#{EXTV_INCLUDE_PRESETS} must be an Array" unless includes.is_a?(Array)
353
376
  raise "#{EXTV_INCLUDE_PRESETS} must contain names" unless includes.map(&:class).uniq.eql?([String])
354
377
  includes.each do |preset_name|
355
- hash_val.merge!(preset_by_name(preset_name,include_path))
378
+ hash_val.merge!(preset_by_name(preset_name, include_path))
356
379
  end
357
380
  hash_val.merge!(memory)
358
381
  end
@@ -392,124 +415,122 @@ module Aspera
392
415
  end
393
416
  end
394
417
 
395
- def convert_preset_path(old_name,new_name,files_to_copy)
396
- old_subpath = File.join('',ASPERA_HOME_FOLDER_NAME,old_name,'')
397
- new_subpath = File.join('',ASPERA_HOME_FOLDER_NAME,new_name,'')
418
+ def convert_preset_path(old_name, new_name, files_to_copy)
419
+ old_subpath = File.join('', ASPERA_HOME_FOLDER_NAME, old_name, '')
420
+ new_subpath = File.join('', ASPERA_HOME_FOLDER_NAME, new_name, '')
398
421
  # convert possible keys located in config folder
399
422
  @config_presets.values.select{|p|p.is_a?(Hash)}.each do |preset|
400
423
  preset.values.select{|v|v.is_a?(String) && v.include?(old_subpath)}.each do |value|
401
424
  old_val = value.clone
402
- included_path = File.expand_path(old_val.gsub(/^@file:/,''))
425
+ included_path = File.expand_path(old_val.gsub(/^@file:/, ''))
403
426
  files_to_copy.push(included_path) unless files_to_copy.include?(included_path) || !File.exist?(included_path)
404
- value.gsub!(old_subpath,new_subpath)
405
- Log.log.warn("Converted config value: #{old_val} -> #{value}")
427
+ value.gsub!(old_subpath, new_subpath)
428
+ Log.log.warn{"Converted config value: #{old_val} -> #{value}"}
406
429
  end
407
430
  end
408
431
  end
409
432
 
410
- def convert_preset_plugin_name(old_name,new_name)
433
+ def convert_preset_plugin_name(old_name, new_name)
411
434
  default_preset = @config_presets[CONF_PRESET_DEFAULT]
412
- return unless default_preset.is_a?(Hash) && default_preset.has_key?(old_name)
435
+ return unless default_preset.is_a?(Hash) && default_preset.key?(old_name)
413
436
  default_preset[new_name] = default_preset[old_name]
414
437
  default_preset.delete(old_name)
415
- Log.log.warn("Converted plugin default: #{old_name} -> #{new_name}")
438
+ Log.log.warn{"Converted plugin default: #{old_name} -> #{new_name}"}
416
439
  end
417
440
 
418
441
  # read config file and validate format
419
442
  # tries to convert from older version if possible and required
420
443
  def read_config_file
421
- begin
422
- Log.log.debug("config file is: #{@option_config_file}".red)
423
- conf_file_v1 = File.join(Dir.home,ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME_V1,DEFAULT_CONFIG_FILENAME)
424
- conf_file_v2 = File.join(Dir.home,ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME_V2,DEFAULT_CONFIG_FILENAME)
425
- # files search for configuration, by default the one given by user
426
- search_files = [@option_config_file]
427
- # if default file, then also look for older versions
428
- search_files.push(conf_file_v2,conf_file_v1) if @option_config_file.eql?(@conf_file_default)
429
- # find first existing file (or nil)
430
- conf_file_to_load = search_files.find{|f| File.exist?(f)}
431
- # require save if old version of file
432
- save_required = !@option_config_file.eql?(conf_file_to_load)
433
- # if no file found, create default config
434
- if conf_file_to_load.nil?
435
- Log.log.warn("No config file found. Creating empty configuration file: #{@option_config_file}")
436
- @config_presets = {CONF_PRESET_CONFIG => {CONF_PRESET_VERSION => @info[:version]}}
437
- else
438
- Log.log.debug("loading #{@option_config_file}")
439
- @config_presets = YAML.load_file(conf_file_to_load)
440
- end
441
- files_to_copy = []
442
- Log.log.debug("Available_presets: #{@config_presets}")
443
- raise 'Expecting YAML Hash' unless @config_presets.is_a?(Hash)
444
- # check there is at least the config section
445
- if !@config_presets.has_key?(CONF_PRESET_CONFIG)
446
- raise "Cannot find key: #{CONF_PRESET_CONFIG}"
447
- end
448
- version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]
449
- if version.nil?
450
- raise 'No version found in config section.'
451
- end
452
- # oldest compatible conf file format, update to latest version when an incompatible change is made
453
- # check compatibility of version of conf file
454
- config_tested_version = '0.4.5'
455
- if Gem::Version.new(version) < Gem::Version.new(config_tested_version)
456
- raise "Unsupported config file version #{version}. Expecting min version #{config_tested_version}"
457
- end
458
- config_tested_version = '0.6.15'
459
- if Gem::Version.new(version) < Gem::Version.new(config_tested_version)
460
- convert_preset_plugin_name(AOC_COMMAND_V1,AOC_COMMAND_V2)
461
- version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = config_tested_version
462
- save_required = true
463
- end
464
- config_tested_version = '0.8.10'
465
- if Gem::Version.new(version) <= Gem::Version.new(config_tested_version)
466
- convert_preset_path(PROGRAM_NAME_V1,PROGRAM_NAME_V2,files_to_copy)
467
- version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = config_tested_version
468
- save_required = true
469
- end
470
- config_tested_version = '1.0'
471
- if Gem::Version.new(version) <= Gem::Version.new(config_tested_version)
472
- convert_preset_plugin_name(AOC_COMMAND_V2,AOC_COMMAND_V3)
473
- convert_preset_path(PROGRAM_NAME_V2,@info[:name],files_to_copy)
474
- version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = config_tested_version
475
- save_required = true
476
- end
477
- Log.log.debug("conf version: #{version}")
478
- # Place new compatibility code here
479
- if save_required
480
- Log.log.warn('Saving automatic conversion.')
481
- @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = @info[:version]
482
- save_presets_to_config_file
483
- Log.log.warn('Copying referenced files')
484
- files_to_copy.each do |file|
485
- FileUtils.cp(file,@main_folder)
486
- Log.log.warn("..#{file} -> #{@main_folder}")
487
- end
488
- end
489
- rescue Psych::SyntaxError => e
490
- Log.log.error('YAML error in config file')
491
- raise e
492
- rescue StandardError => e
493
- Log.log.debug("-> #{e.class.name} : #{e}")
494
- if File.exist?(@option_config_file)
495
- # then there is a problem with that file.
496
- new_name = "#{@option_config_file}.pre#{@info[:version]}.manual_conversion_needed"
497
- File.rename(@option_config_file,new_name)
498
- Log.log.warn("Renamed config file to #{new_name}.")
499
- Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
444
+ Log.log.debug{"config file is: #{@option_config_file}".red}
445
+ conf_file_v1 = File.join(Dir.home, ASPERA_HOME_FOLDER_NAME, PROGRAM_NAME_V1, DEFAULT_CONFIG_FILENAME)
446
+ conf_file_v2 = File.join(Dir.home, ASPERA_HOME_FOLDER_NAME, PROGRAM_NAME_V2, DEFAULT_CONFIG_FILENAME)
447
+ # files search for configuration, by default the one given by user
448
+ search_files = [@option_config_file]
449
+ # if default file, then also look for older versions
450
+ search_files.push(conf_file_v2, conf_file_v1) if @option_config_file.eql?(@conf_file_default)
451
+ # find first existing file (or nil)
452
+ conf_file_to_load = search_files.find{|f| File.exist?(f)}
453
+ # require save if old version of file
454
+ save_required = !@option_config_file.eql?(conf_file_to_load)
455
+ # if no file found, create default config
456
+ if conf_file_to_load.nil?
457
+ Log.log.warn{"No config file found. Creating empty configuration file: #{@option_config_file}"}
458
+ @config_presets = {CONF_PRESET_CONFIG => {CONF_PRESET_VERSION => @info[:version]}}
459
+ else
460
+ Log.log.debug{"loading #{@option_config_file}"}
461
+ @config_presets = YAML.load_file(conf_file_to_load)
462
+ end
463
+ files_to_copy = []
464
+ Log.log.debug{"Available_presets: #{@config_presets}"}
465
+ raise 'Expecting YAML Hash' unless @config_presets.is_a?(Hash)
466
+ # check there is at least the config section
467
+ if !@config_presets.key?(CONF_PRESET_CONFIG)
468
+ raise "Cannot find key: #{CONF_PRESET_CONFIG}"
469
+ end
470
+ version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]
471
+ if version.nil?
472
+ raise 'No version found in config section.'
473
+ end
474
+ # oldest compatible conf file format, update to latest version when an incompatible change is made
475
+ # check compatibility of version of conf file
476
+ config_tested_version = '0.4.5'
477
+ if Gem::Version.new(version) < Gem::Version.new(config_tested_version)
478
+ raise "Unsupported config file version #{version}. Expecting min version #{config_tested_version}"
479
+ end
480
+ config_tested_version = '0.6.15'
481
+ if Gem::Version.new(version) < Gem::Version.new(config_tested_version)
482
+ convert_preset_plugin_name(AOC_COMMAND_V1, AOC_COMMAND_V2)
483
+ version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = config_tested_version
484
+ save_required = true
485
+ end
486
+ config_tested_version = '0.8.10'
487
+ if Gem::Version.new(version) <= Gem::Version.new(config_tested_version)
488
+ convert_preset_path(PROGRAM_NAME_V1, PROGRAM_NAME_V2, files_to_copy)
489
+ version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = config_tested_version
490
+ save_required = true
491
+ end
492
+ config_tested_version = '1.0'
493
+ if Gem::Version.new(version) <= Gem::Version.new(config_tested_version)
494
+ convert_preset_plugin_name(AOC_COMMAND_V2, AOC_COMMAND_V3)
495
+ convert_preset_path(PROGRAM_NAME_V2, @info[:name], files_to_copy)
496
+ version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = config_tested_version
497
+ save_required = true
498
+ end
499
+ Log.log.debug{"conf version: #{version}"}
500
+ # Place new compatibility code here
501
+ if save_required
502
+ Log.log.warn('Saving automatic conversion.')
503
+ @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = @info[:version]
504
+ save_presets_to_config_file
505
+ Log.log.warn('Copying referenced files')
506
+ files_to_copy.each do |file|
507
+ FileUtils.cp(file, @main_folder)
508
+ Log.log.warn{"..#{file} -> #{@main_folder}"}
500
509
  end
501
- raise CliError,e.to_s
502
510
  end
511
+ rescue Psych::SyntaxError => e
512
+ Log.log.error('YAML error in config file')
513
+ raise e
514
+ rescue StandardError => e
515
+ Log.log.debug{"-> #{e.class.name} : #{e}"}
516
+ if File.exist?(@option_config_file)
517
+ # then there is a problem with that file.
518
+ new_name = "#{@option_config_file}.pre#{@info[:version]}.manual_conversion_needed"
519
+ File.rename(@option_config_file, new_name)
520
+ Log.log.warn{"Renamed config file to #{new_name}."}
521
+ Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
522
+ end
523
+ raise CliError, e.to_s
503
524
  end
504
525
 
505
526
  # find plugins in defined paths
506
527
  def add_plugins_from_lookup_folders
507
528
  @plugin_lookup_folders.each do |folder|
508
529
  next unless File.directory?(folder)
509
- #TODO: add gem root to load path ? and require short folder ?
510
- #$LOAD_PATH.push(folder) if i[:add_path]
530
+ # TODO: add gem root to load path ? and require short folder ?
531
+ # $LOAD_PATH.push(folder) if i[:add_path]
511
532
  Dir.entries(folder).select{|file|file.end_with?(RUBY_FILE_EXT)}.each do |source|
512
- add_plugin_info(File.join(folder,source))
533
+ add_plugin_info(File.join(folder, source))
513
534
  end
514
535
  end
515
536
  end
@@ -520,17 +541,17 @@ module Aspera
520
541
 
521
542
  def add_plugin_info(path)
522
543
  raise "ERROR: plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
523
- plugin_symbol = File.basename(path,RUBY_FILE_EXT).to_sym
524
- req = path.gsub(/#{RUBY_FILE_EXT}$/o,'')
525
- if @plugins.has_key?(plugin_symbol)
526
- Log.log.warn("skipping plugin already registered: #{plugin_symbol}")
544
+ plugin_symbol = File.basename(path, RUBY_FILE_EXT).to_sym
545
+ req = path.gsub(/#{RUBY_FILE_EXT}$/o, '')
546
+ if @plugins.key?(plugin_symbol)
547
+ Log.log.warn{"skipping plugin already registered: #{plugin_symbol}"}
527
548
  return
528
549
  end
529
- @plugins[plugin_symbol] = {source: path,require_stanza: req}
550
+ @plugins[plugin_symbol] = {source: path, require_stanza: req}
530
551
  end
531
552
 
532
553
  def identify_plugin_for_url(url)
533
- plugins.each do |plugin_name_sym,plugin_info|
554
+ plugins.each do |plugin_name_sym, plugin_info|
534
555
  # no detection for internal plugin
535
556
  next if plugin_name_sym.eql?(CONF_PLUGIN_SYM)
536
557
  # load plugin class
@@ -546,19 +567,19 @@ module Aspera
546
567
  Log.log.warn(e.message)
547
568
  Log.log.warn('Use option --insecure=yes to ignore certificate') if e.message.include?('cert')
548
569
  rescue StandardError => e
549
- Log.log.debug("Cannot detect #{plugin_name_sym} : #{e.class}/#{e.message}")
570
+ Log.log.debug{"Cannot detect #{plugin_name_sym} : #{e.class}/#{e.message}"}
550
571
  end
551
572
  # second try : is there a redirect ?
552
573
  if detection_info.nil?
553
574
  begin
554
575
  # TODO: check if redirect ?
555
- new_url = Rest.new(base_url: url).call(operation: 'GET',subpath: '',redirect_max: 1)[:http].uri.to_s
576
+ new_url = Rest.new(base_url: url).call(operation: 'GET', subpath: '', redirect_max: 1)[:http].uri.to_s
556
577
  unless url.eql?(new_url)
557
578
  detection_info = c.detect(new_url)
558
579
  current_url = new_url
559
580
  end
560
581
  rescue StandardError => e
561
- Log.log.debug("Cannot detect #{plugin_name_sym} : #{e.message}")
582
+ Log.log.debug{"Cannot detect #{plugin_name_sym} : #{e.message}"}
562
583
  end
563
584
  end
564
585
  return detection_info.merge(product: plugin_name_sym, url: current_url) unless detection_info.nil?
@@ -571,7 +592,7 @@ module Aspera
571
592
  if %i[info version].include?(command)
572
593
  connect_id = options.get_next_argument('id or title')
573
594
  one_res = connect_versions.find{|i|i['id'].eql?(connect_id) || i['title'].eql?(connect_id)}
574
- raise CliNoSuchId.new(:connect,connect_id) if one_res.nil?
595
+ raise CliNoSuchId.new(:connect, connect_id) if one_res.nil?
575
596
  end
576
597
  case command
577
598
  when :list
@@ -592,11 +613,11 @@ module Aspera
592
613
  return {type: :object_list, data: all_links}
593
614
  when :download
594
615
  folder_dest = transfer.destination_folder(Fasp::TransferSpec::DIRECTION_RECEIVE)
595
- #folder_dest=self.options.get_next_argument('destination folder')
616
+ # folder_dest=self.options.get_next_argument('destination folder')
596
617
  api_connect_cdn = Rest.new({base_url: CONNECT_WEB_URL})
597
618
  fileurl = one_link['href']
598
- filename = fileurl.gsub(%r{.*/},'')
599
- api_connect_cdn.call({operation: 'GET',subpath: fileurl,save_to_file: File.join(folder_dest,filename)})
619
+ filename = fileurl.gsub(%r{.*/}, '')
620
+ api_connect_cdn.call({operation: 'GET', subpath: fileurl, save_to_file: File.join(folder_dest, filename)})
600
621
  return Main.result_status("Downloaded: #{filename}")
601
622
  when :open
602
623
  OpenApplication.instance.uri(one_link['href'])
@@ -614,12 +635,12 @@ module Aspera
614
635
  ascp_path = options.get_next_argument('path to ascp')
615
636
  ascp_version = Fasp::Installation.instance.get_ascp_version(ascp_path)
616
637
  self.format.display_status("ascp version: #{ascp_version}")
617
- preset_name = set_global_default(:ascp_path,ascp_path)
638
+ preset_name = set_global_default(:ascp_path, ascp_path)
618
639
  return Main.result_status("Saved to default global preset #{preset_name}")
619
640
  when :show # shows files used
620
641
  return {type: :status, data: Fasp::Installation.instance.path(:ascp)}
621
642
  when :info # shows files used
622
- data = Fasp::Installation::FILES.each_with_object({}) do |v,m|
643
+ data = Fasp::Installation::FILES.each_with_object({}) do |v, m|
623
644
  m[v.to_s] =
624
645
  begin
625
646
  Fasp::Installation.instance.path(v)
@@ -628,21 +649,26 @@ module Aspera
628
649
  end
629
650
  end
630
651
  # read PATHs from ascp directly, and pvcl modules as well
631
- Open3.popen3(Fasp::Installation.instance.path(:ascp),'-DDL-') do |_stdin, _stdout, stderr, thread|
652
+ Open3.popen3(Fasp::Installation.instance.path(:ascp), '-DDL-') do |_stdin, _stdout, stderr, thread|
632
653
  last_line = ''
633
654
  while (line = stderr.gets)
634
655
  line.chomp!
635
656
  last_line = line
636
657
  case line
637
- when %r{^DBG Path ([^ ]+) (dir|file) +: (.*)$} then data[Regexp.last_match(1)] = Regexp.last_match(3)
638
- when %r{^DBG Added module group:"([^"]+)" name:"([^"]+)", version:"([^"]+)" interface:"([^"]+)"$}
658
+ when /^DBG Path ([^ ]+) (dir|file) +: (.*)$/
659
+ data[Regexp.last_match(1)] = Regexp.last_match(3)
660
+ when /^DBG Added module group:"([^"]+)" name:"([^"]+)", version:"([^"]+)" interface:"([^"]+)"$/
639
661
  data[Regexp.last_match(2)] = "#{Regexp.last_match(4)} #{Regexp.last_match(1)} v#{Regexp.last_match(3)}"
640
- when %r{^DBG License result \(/license/(\S+)\): (.+)$} then data[Regexp.last_match(1)] = Regexp.last_match(2)
641
- when %r{^LOG (.+) version ([0-9.]+)$} then data['product_name'] = Regexp.last_match(1);data['product_version'] = Regexp.last_match(2)
642
- when %r{^LOG Initializing FASP version ([^,]+),} then data['ascp_version'] = Regexp.last_match(1)
662
+ when %r{^DBG License result \(/license/(\S+)\): (.+)$}
663
+ data[Regexp.last_match(1)] = Regexp.last_match(2)
664
+ when /^LOG (.+) version ([0-9.]+)$/
665
+ data['product_name'] = Regexp.last_match(1)
666
+ data['product_version'] = Regexp.last_match(2)
667
+ when /^LOG Initializing FASP version ([^,]+),/
668
+ data['ascp_version'] = Regexp.last_match(1)
643
669
  end
644
670
  end
645
- if !thread.value.exitstatus.eql?(1) && !data.has_key?('root')
671
+ if !thread.value.exitstatus.eql?(1) && !data.key?('root')
646
672
  raise last_line
647
673
  end
648
674
  end
@@ -656,21 +682,21 @@ module Aspera
656
682
  when :use
657
683
  default_product = options.get_next_argument('product name')
658
684
  Fasp::Installation.instance.use_ascp_from_product(default_product)
659
- preset_name = set_global_default(:ascp_path,Fasp::Installation.instance.path(:ascp))
685
+ preset_name = set_global_default(:ascp_path, Fasp::Installation.instance.path(:ascp))
660
686
  return Main.result_status("Saved to default global preset #{preset_name}")
661
687
  end
662
688
  when :install
663
- v = Fasp::Installation.instance.install_sdk(options.get_option(:sdk_url,is_type: :mandatory))
689
+ v = Fasp::Installation.instance.install_sdk(options.get_option(:sdk_url, is_type: :mandatory))
664
690
  return Main.result_status("Installed version #{v}")
665
691
  when :spec
666
692
  return {
667
693
  type: :object_list,
668
694
  data: Fasp::Parameters.man_table,
669
- fields: ['name','type',Fasp::Parameters::SUPPORTED_AGENTS_SHORT.map(&:to_s),'description'].flatten
695
+ fields: %w[name type].concat(Fasp::Parameters::SUPPORTED_AGENTS_SHORT.map(&:to_s), %w[description])
670
696
  }
671
697
  when :errors
672
698
  error_data = []
673
- Fasp::ERROR_INFO.each_pair do |code,prop|
699
+ Fasp::ERROR_INFO.each_pair do |code, prop|
674
700
  error_data.push(code: code, mnemonic: prop[:c], retry: prop[:r], info: prop[:a])
675
701
  end
676
702
  return {type: :object_list, data: error_data}
@@ -679,112 +705,168 @@ module Aspera
679
705
  end
680
706
 
681
707
  # legacy actions available globally
682
- PRESET_GBL_ACTIONS = %i[list overview].freeze
708
+ PRESET_GBL_ACTIONS = %i[list overview lookup secure].freeze
683
709
  # require existing preset
684
710
  PRESET_EXST_ACTIONS = %i[show delete get unset].freeze
685
711
  # require id
686
- PRESET_INSTANCE_ACTIONS = [PRESET_EXST_ACTIONS,%i[initialize update ask set]].flatten.freeze
687
- PRESET_ALL_ACTIONS = [PRESET_GBL_ACTIONS,PRESET_INSTANCE_ACTIONS].flatten.freeze
712
+ PRESET_INSTANCE_ACTIONS = %i[initialize update ask set].concat(PRESET_EXST_ACTIONS).freeze
713
+ PRESET_ALL_ACTIONS = [].concat(PRESET_GBL_ACTIONS, PRESET_INSTANCE_ACTIONS).freeze
688
714
 
689
- def execute_file_action(action,config_name)
715
+ def execute_preset(action: nil, name: nil)
690
716
  action = options.get_next_command(PRESET_ALL_ACTIONS) if action.nil?
691
- config_name = instance_identifier if config_name.nil? && PRESET_INSTANCE_ACTIONS.include?(action)
717
+ name = instance_identifier if name.nil? && PRESET_INSTANCE_ACTIONS.include?(action)
692
718
  # those operations require existing option
693
- raise "no such preset: #{config_name}" if PRESET_EXST_ACTIONS.include?(action) && !@config_presets.has_key?(config_name)
694
- selected_preset = @config_presets[config_name]
719
+ raise "no such preset: #{name}" if PRESET_EXST_ACTIONS.include?(action) && !@config_presets.key?(name)
720
+ selected_preset = @config_presets[name]
695
721
  case action
696
722
  when :list
697
723
  return {type: :value_list, data: @config_presets.keys, name: 'name'}
698
724
  when :overview
699
725
  return {type: :object_list, data: Formater.flatten_config_overview(@config_presets)}
700
726
  when :show
701
- raise "no such config: #{config_name}" if selected_preset.nil?
727
+ raise "no such config: #{name}" if selected_preset.nil?
702
728
  return {type: :single_object, data: selected_preset}
703
729
  when :delete
704
- @config_presets.delete(config_name)
730
+ @config_presets.delete(name)
705
731
  save_presets_to_config_file
706
- return Main.result_status("Deleted: #{config_name}")
732
+ return Main.result_status("Deleted: #{name}")
707
733
  when :get
708
734
  param_name = options.get_next_argument('parameter name')
709
735
  value = selected_preset[param_name]
710
- raise "no such option in preset #{config_name} : #{param_name}" if value.nil?
736
+ raise "no such option in preset #{name} : #{param_name}" if value.nil?
711
737
  case value
712
- when Numeric,String then return {type: :text, data: ExtendedValue.instance.evaluate(value.to_s)}
738
+ when Numeric, String then return {type: :text, data: ExtendedValue.instance.evaluate(value.to_s)}
713
739
  end
714
740
  return {type: :single_object, data: value}
715
741
  when :unset
716
742
  param_name = options.get_next_argument('parameter name')
717
743
  selected_preset.delete(param_name)
718
744
  save_presets_to_config_file
719
- return Main.result_status("Removed: #{config_name}: #{param_name}")
745
+ return Main.result_status("Removed: #{name}: #{param_name}")
720
746
  when :set
721
747
  param_name = options.get_next_argument('parameter name')
722
748
  param_value = options.get_next_argument('parameter value')
723
- if !@config_presets.has_key?(config_name)
724
- Log.log.debug("no such config name: #{config_name}, initializing")
725
- selected_preset = @config_presets[config_name] = {}
749
+ if !@config_presets.key?(name)
750
+ Log.log.debug{"no such config name: #{name}, initializing"}
751
+ selected_preset = @config_presets[name] = {}
726
752
  end
727
- if selected_preset.has_key?(param_name)
728
- Log.log.warn("overwriting value: #{selected_preset[param_name]}")
753
+ if selected_preset.key?(param_name)
754
+ Log.log.warn{"overwriting value: #{selected_preset[param_name]}"}
729
755
  end
730
756
  selected_preset[param_name] = param_value
731
757
  save_presets_to_config_file
732
- return Main.result_status("Updated: #{config_name}: #{param_name} <- #{param_value}")
758
+ return Main.result_status("Updated: #{name}: #{param_name} <- #{param_value}")
733
759
  when :initialize
734
- config_value = options.get_next_argument('extended value (Hash)')
735
- if @config_presets.has_key?(config_name)
736
- Log.log.warn("configuration already exists: #{config_name}, overwriting")
760
+ config_value = options.get_next_argument('extended value', type: Hash)
761
+ if @config_presets.key?(name)
762
+ Log.log.warn{"configuration already exists: #{name}, overwriting"}
737
763
  end
738
- @config_presets[config_name] = config_value
764
+ @config_presets[name] = config_value
739
765
  save_presets_to_config_file
740
766
  return Main.result_status("Modified: #{@option_config_file}")
741
767
  when :update
742
768
  # get unprocessed options
743
769
  theopts = options.get_options_table
744
- Log.log.debug("opts=#{theopts}")
745
- @config_presets[config_name] ||= {}
746
- @config_presets[config_name].merge!(theopts)
770
+ Log.log.debug{"opts=#{theopts}"}
771
+ @config_presets[name] ||= {}
772
+ @config_presets[name].merge!(theopts)
747
773
  # fix bug in 4.4 (creating key "true" in "default" preset)
748
774
  @config_presets[CONF_PRESET_DEFAULT].delete(true) if @config_presets[CONF_PRESET_DEFAULT].is_a?(Hash)
749
775
  save_presets_to_config_file
750
- return Main.result_status("Updated: #{config_name}")
776
+ return Main.result_status("Updated: #{name}")
751
777
  when :ask
752
778
  options.ask_missing_mandatory = :yes
753
- @config_presets[config_name] ||= {}
754
- options.get_next_argument('option names',expected: :multiple).each do |optionname|
755
- option_value = options.get_interactive(:option,optionname)
756
- @config_presets[config_name][optionname] = option_value
779
+ @config_presets[name] ||= {}
780
+ options.get_next_argument('option names', expected: :multiple).each do |optionname|
781
+ option_value = options.get_interactive(:option, optionname)
782
+ @config_presets[name][optionname] = option_value
757
783
  end
758
784
  save_presets_to_config_file
759
- return Main.result_status("Updated: #{config_name}")
785
+ return Main.result_status("Updated: #{name}")
786
+ when :lookup
787
+ BasicAuthPlugin.register_options(@agents)
788
+ url = options.get_option(:url, is_type: :mandatory)
789
+ user = options.get_option(:username, is_type: :mandatory)
790
+ result = lookup_preset(url: url, username: user)
791
+ raise 'no such config found' if result.nil?
792
+ return {type: :single_object, data: result}
793
+ when :secure
794
+ identifier = options.get_next_argument('config name', mandatory: false)
795
+ preset_names = identifier.nil? ? @config_presets.keys : [identifier]
796
+ secret_keywords = %w[password secret].freeze
797
+ preset_names.each do |pset_name|
798
+ preset = @config_presets[pset_name]
799
+ next unless preset.is_a?(Hash)
800
+ preset.each_key do |option_name|
801
+ secret_keywords.each do |keyword|
802
+ next unless option_name.end_with?(keyword)
803
+ vault_label = pset_name
804
+ incr = 0
805
+ until vault.get(label: vault_label, exception: false).nil?
806
+ vault_label = "#{pset_name}#{incr}"
807
+ incr += 1
808
+ end
809
+ to_set = {label: vault_label, password: preset[option_name]}
810
+ puts "need to encode #{pset_name}.#{option_name} -> #{vault_label} -> #{to_set}"
811
+ # to_copy=%i[]
812
+ vault.set(to_set)
813
+ preset[option_name] = "@vault:#{vault_label}.password"
814
+ end
815
+ end
816
+ end
817
+ return Main.result_status('Secrets secured in vault: Make sure to save the vault password securely.')
760
818
  end
761
819
  end
762
820
 
763
- ACTIONS = [PRESET_GBL_ACTIONS,%i[id preset open documentation genkey gem plugin flush_tokens echo wizard export_to_cli detect coffee
764
- ascp email_test smtp_settings proxy_check folder file check_update initdemo vault]].flatten.freeze
821
+ ACTIONS = %i[
822
+ id
823
+ preset
824
+ open
825
+ documentation
826
+ genkey
827
+ gem
828
+ plugin
829
+ flush_tokens
830
+ echo
831
+ wizard
832
+ export_to_cli
833
+ detect
834
+ coffee
835
+ ascp
836
+ email_test
837
+ smtp_settings
838
+ proxy_check
839
+ folder
840
+ file
841
+ check_update
842
+ initdemo
843
+ vault].concat(PRESET_GBL_ACTIONS).freeze
765
844
 
766
845
  # "config" plugin
767
846
  def execute_action
768
847
  action = options.get_next_command(ACTIONS)
769
848
  case action
770
849
  when *PRESET_GBL_ACTIONS # older syntax
771
- return execute_file_action(action,nil)
850
+ Log.log.warn{"This syntax is deprecated, use command: preset #{action}"}
851
+ return execute_preset(action: action)
772
852
  when :id # older syntax
773
- return execute_file_action(nil,options.get_next_argument('config name'))
853
+ identifier = options.get_next_argument('config name')
854
+ Log.log.warn{"This syntax is deprecated, use command: preset <verb> #{identifier}"}
855
+ return execute_preset(name: identifier)
774
856
  when :preset # newer syntax
775
- return execute_file_action(nil,nil)
857
+ return execute_preset
776
858
  when :open
777
- OpenApplication.instance.uri(@option_config_file.to_s) #file://
859
+ OpenApplication.editor(@option_config_file.to_s)
778
860
  return Main.result_nothing
779
861
  when :documentation
780
- section = options.get_next_argument('private key file path',mandatory: false)
862
+ section = options.get_next_argument('private key file path', mandatory: false)
781
863
  section = '#' + section unless section.nil?
782
864
  OpenApplication.instance.uri("#{@info[:help]}#{section}")
783
865
  return Main.result_nothing
784
866
  when :genkey # generate new rsa key
785
867
  private_key_path = options.get_next_argument('private key file path')
786
- private_key_length = options.get_next_argument('size in bits',mandatory: false) || DEFAULT_PRIVKEY_LENGTH
787
- generate_rsa_private_key(private_key_path,private_key_length)
868
+ private_key_length = options.get_next_argument('size in bits', mandatory: false) || DEFAULT_PRIVKEY_LENGTH
869
+ generate_rsa_private_key(private_key_path, private_key_length)
788
870
  return Main.result_status('Generated key: ' + private_key_path)
789
871
  when :echo # display the content of a value given on command line
790
872
  result = {type: :other_struct, data: options.get_next_argument('value')}
@@ -800,9 +882,9 @@ module Aspera
800
882
  when :list
801
883
  return {type: :object_list, data: @plugins.keys.map { |i| { 'plugin' => i.to_s, 'path' => @plugins[i][:source] } }, fields: %w[plugin path]}
802
884
  when :create
803
- plugin_name = options.get_next_argument('name',expected: :single).downcase
804
- plugin_folder = options.get_next_argument('folder',expected: :single,mandatory: false) || File.join(@main_folder,ASPERA_PLUGINS_FOLDERNAME)
805
- plugin_file = File.join(plugin_folder,"#{plugin_name}.rb")
885
+ plugin_name = options.get_next_argument('name', expected: :single).downcase
886
+ plugin_folder = options.get_next_argument('folder', expected: :single, mandatory: false) || File.join(@main_folder, ASPERA_PLUGINS_FOLDERNAME)
887
+ plugin_file = File.join(plugin_folder, "#{plugin_name}.rb")
806
888
  content = <<~END_OF_PLUGIN_CODE
807
889
  require 'aspera/cli/plugin'
808
890
  module Aspera
@@ -816,7 +898,7 @@ module Aspera
816
898
  end # Cli
817
899
  end # Aspera
818
900
  END_OF_PLUGIN_CODE
819
- File.write(plugin_file,content)
901
+ File.write(plugin_file, content)
820
902
  return Main.result_status("Created #{plugin_file}")
821
903
  end
822
904
  when :wizard
@@ -824,15 +906,15 @@ module Aspera
824
906
  options.ask_missing_mandatory = true
825
907
  # register url option
826
908
  BasicAuthPlugin.register_options(@agents)
827
- params={}
909
+ params = {}
828
910
  # get from option, or ask
829
- params[:instance_url] = options.get_option(:url,is_type: :mandatory)
911
+ params[:instance_url] = options.get_option(:url, is_type: :mandatory)
830
912
  # allow user to tell the preset name
831
913
  params[:preset_name] = options.get_option(:id)
832
914
  # allow user to specify type of application
833
915
  params[:application] = options.get_option(:value)
834
916
  params[:application] = params[:application].nil? ? identify_plugin_for_url(params[:instance_url])[:product] : params[:application].to_sym
835
- params[:plugin_name]=params[:application]
917
+ params[:plugin_name] = params[:application]
836
918
  params[:test_args] = '<replace per app>'
837
919
  case params[:application]
838
920
  when :faspex5
@@ -840,7 +922,7 @@ module Aspera
840
922
  when :aoc
841
923
  wizard_aoc(params)
842
924
  else
843
- raise CliBadArgument,"Supports only: aoc. Detected: #{params[:application]}"
925
+ raise CliBadArgument, "Supports only: aoc. Detected: #{params[:application]}"
844
926
  end # product
845
927
  if params[:option_default]
846
928
  self.format.display_status("Setting config preset as default for #{params[:plugin_name]}")
@@ -858,23 +940,23 @@ module Aspera
858
940
  add_plugin_default_preset(AOC_COMMAND_V3.to_sym)
859
941
  # instanciate AoC plugin
860
942
  self.class.plugin_class(AOC_COMMAND_CURRENT).new(@agents) # TODO: is this line needed ? get options ?
861
- url = options.get_option(:url,is_type: :mandatory)
943
+ url = options.get_option(:url, is_type: :mandatory)
862
944
  cli_conf_file = Fasp::Installation.instance.cli_conf_file
863
945
  data = JSON.parse(File.read(cli_conf_file))
864
- organization,instance_domain = AoC.parse_url(url)
946
+ organization, instance_domain = AoC.parse_url(url)
865
947
  key_basename = 'org_' + organization + '.pem'
866
- key_file = File.join(File.dirname(File.dirname(cli_conf_file)),'etc',key_basename)
867
- File.write(key_file,options.get_option(:private_key,is_type: :mandatory))
948
+ key_file = File.join(File.dirname(File.dirname(cli_conf_file)), 'etc', key_basename)
949
+ File.write(key_file, options.get_option(:private_key, is_type: :mandatory))
868
950
  new_conf = {
869
951
  'organization' => organization,
870
- 'hostname' => [organization,instance_domain].join('.'),
952
+ 'hostname' => [organization, instance_domain].join('.'),
871
953
  'privateKeyFilename' => key_basename,
872
- 'username' => options.get_option(:username,is_type: :mandatory)
954
+ 'username' => options.get_option(:username, is_type: :mandatory)
873
955
  }
874
956
  new_conf['clientId'] = options.get_option(:client_id)
875
957
  new_conf['clientSecret'] = options.get_option(:client_secret)
876
958
  if new_conf['clientId'].nil?
877
- new_conf['clientId'],new_conf['clientSecret'] = AoC.get_client_info
959
+ new_conf['clientId'], new_conf['clientSecret'] = AoC.get_client_info
878
960
  end
879
961
  entry = data['AoCAccounts'].find{|i|i['organization'].eql?(organization)}
880
962
  if entry.nil?
@@ -884,12 +966,12 @@ module Aspera
884
966
  self.format.display_status("Updating existing aoc entry: #{organization}")
885
967
  entry.merge!(new_conf)
886
968
  end
887
- File.write(cli_conf_file,JSON.pretty_generate(data))
969
+ File.write(cli_conf_file, JSON.pretty_generate(data))
888
970
  return Main.result_status("Updated: #{cli_conf_file}")
889
971
  when :detect
890
972
  # need url / username
891
973
  BasicAuthPlugin.register_options(@agents)
892
- return {type: :single_object, data: identify_plugin_for_url(options.get_option(:url,is_type: :mandatory))}
974
+ return {type: :single_object, data: identify_plugin_for_url(options.get_option(:url, is_type: :mandatory))}
893
975
  when :coffee
894
976
  OpenApplication.instance.uri('https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg')
895
977
  return Main.result_nothing
@@ -912,16 +994,16 @@ module Aspera
912
994
  return {type: :single_object, data: email_settings}
913
995
  when :proxy_check
914
996
  # ensure fpac was provided
915
- options.get_option(:fpac,is_type: :mandatory)
997
+ options.get_option(:fpac, is_type: :mandatory)
916
998
  server_url = options.get_next_argument('server url')
917
999
  return Main.result_status(@pac_exec.find_proxy_for_url(server_url))
918
1000
  when :check_update
919
1001
  return {type: :single_object, data: check_gem_version}
920
1002
  when :initdemo
921
- if @config_presets.has_key?(DEMO_SERVER_PRESET)
922
- Log.log.warn("Demo server preset already present: #{DEMO_SERVER_PRESET}")
1003
+ if @config_presets.key?(DEMO_SERVER_PRESET)
1004
+ Log.log.warn{"Demo server preset already present: #{DEMO_SERVER_PRESET}"}
923
1005
  else
924
- Log.log.info("Creating Demo server preset: #{DEMO_SERVER_PRESET}")
1006
+ Log.log.info{"Creating Demo server preset: #{DEMO_SERVER_PRESET}"}
925
1007
  @config_presets[DEMO_SERVER_PRESET] = {
926
1008
  'url' => 'ssh://' + DEMO + '.asperasoft.com:33001',
927
1009
  'username' => AOC_COMMAND_V2,
@@ -929,13 +1011,13 @@ module Aspera
929
1011
  }
930
1012
  end
931
1013
  @config_presets[CONF_PRESET_DEFAULT] ||= {}
932
- if @config_presets[CONF_PRESET_DEFAULT].has_key?(SERVER_COMMAND)
933
- Log.log.warn("Server default preset already set to: #{@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND]}")
934
- Log.log.warn("Use #{DEMO_SERVER_PRESET} for demo: -P#{DEMO_SERVER_PRESET}") unless
1014
+ if @config_presets[CONF_PRESET_DEFAULT].key?(SERVER_COMMAND)
1015
+ Log.log.warn{"Server default preset already set to: #{@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND]}"}
1016
+ Log.log.warn{"Use #{DEMO_SERVER_PRESET} for demo: -P#{DEMO_SERVER_PRESET}"} unless
935
1017
  DEMO_SERVER_PRESET.eql?(@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND])
936
1018
  else
937
1019
  @config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND] = DEMO_SERVER_PRESET
938
- Log.log.info("Setting server default preset to : #{DEMO_SERVER_PRESET}")
1020
+ Log.log.info{"Setting server default preset to : #{DEMO_SERVER_PRESET}"}
939
1021
  end
940
1022
  save_presets_to_config_file
941
1023
  return Main.result_status('Done')
@@ -946,20 +1028,20 @@ module Aspera
946
1028
 
947
1029
  # @return email server setting with defaults if not defined
948
1030
  def email_settings
949
- smtp = options.get_option(:smtp,is_type: :mandatory)
1031
+ smtp = options.get_option(:smtp, is_type: :mandatory)
950
1032
  # change string keys into symbol keys
951
- smtp = smtp.keys.each_with_object({}){|v,m|m[v.to_sym] = smtp[v];}
1033
+ smtp = smtp.keys.each_with_object({}){|v, m|m[v.to_sym] = smtp[v]; }
952
1034
  # defaults
953
1035
  smtp[:tls] ||= true
954
1036
  smtp[:port] ||= smtp[:tls] ? 587 : 25
955
- smtp[:from_email] ||= smtp[:username] if smtp.has_key?(:username)
956
- smtp[:from_name] ||= smtp[:from_email].gsub(/@.*$/,'').gsub(/[^a-zA-Z]/,' ').capitalize if smtp.has_key?(:username)
957
- smtp[:domain] ||= smtp[:from_email].gsub(/^.*@/,'') if smtp.has_key?(:from_email)
1037
+ smtp[:from_email] ||= smtp[:username] if smtp.key?(:username)
1038
+ smtp[:from_name] ||= smtp[:from_email].gsub(/@.*$/, '').gsub(/[^a-zA-Z]/, ' ').capitalize if smtp.key?(:username)
1039
+ smtp[:domain] ||= smtp[:from_email].gsub(/^.*@/, '') if smtp.key?(:from_email)
958
1040
  # check minimum required
959
1041
  %i[server port domain].each do |n|
960
- raise "Missing smtp parameter: #{n}" unless smtp.has_key?(n)
1042
+ raise "Missing smtp parameter: #{n}" unless smtp.key?(n)
961
1043
  end
962
- Log.log.debug("smtp=#{smtp}")
1044
+ Log.log.debug{"smtp=#{smtp}"}
963
1045
  return smtp
964
1046
  end
965
1047
 
@@ -969,26 +1051,26 @@ module Aspera
969
1051
  end
970
1052
 
971
1053
  def send_email_template(email_template_default: nil, values: {})
972
- values[:to] ||= options.get_option(:notif_to,is_type: :mandatory)
973
- notif_template = options.get_option(:notif_template,is_type: email_template_default.nil? ? :mandatory : :optional) || email_template_default
1054
+ values[:to] ||= options.get_option(:notif_to, is_type: :mandatory)
1055
+ notif_template = options.get_option(:notif_template, is_type: email_template_default.nil? ? :mandatory : :optional) || email_template_default
974
1056
  mail_conf = email_settings
975
1057
  values[:from_name] ||= mail_conf[:from_name]
976
1058
  values[:from_email] ||= mail_conf[:from_email]
977
1059
  %i[from_name from_email].each do |n|
978
- raise "Missing email parameter: #{n}" unless values.has_key?(n)
1060
+ raise "Missing email parameter: #{n}" unless values.key?(n)
979
1061
  end
980
1062
  start_options = [mail_conf[:domain]]
981
- start_options.push(mail_conf[:username],mail_conf[:password],:login) if mail_conf.has_key?(:username) && mail_conf.has_key?(:password)
1063
+ start_options.push(mail_conf[:username], mail_conf[:password], :login) if mail_conf.key?(:username) && mail_conf.key?(:password)
982
1064
  # create a binding with only variables defined in values
983
1065
  template_binding = empty_binding
984
1066
  # add variables to binding
985
- values.each do |k,v|
1067
+ values.each do |k, v|
986
1068
  raise "key (#{k.class}) must be Symbol" unless k.is_a?(Symbol)
987
- template_binding.local_variable_set(k,v)
1069
+ template_binding.local_variable_set(k, v)
988
1070
  end
989
1071
  # execute template
990
1072
  msg_with_headers = ERB.new(notif_template).result(template_binding)
991
- Log.dump(:msg_with_headers,msg_with_headers)
1073
+ Log.dump(:msg_with_headers, msg_with_headers)
992
1074
  smtp = Net::SMTP.new(mail_conf[:server], mail_conf[:port])
993
1075
  smtp.enable_starttls if mail_conf[:tls]
994
1076
  smtp.start(*start_options) do |smtp_session|
@@ -999,8 +1081,8 @@ module Aspera
999
1081
  def save_presets_to_config_file
1000
1082
  raise 'no configuration loaded' if @config_presets.nil?
1001
1083
  FileUtils.mkdir_p(@main_folder) unless Dir.exist?(@main_folder)
1002
- Log.log.debug("Writing #{@option_config_file}")
1003
- File.write(@option_config_file,@config_presets.to_yaml)
1084
+ Log.log.debug{"Writing #{@option_config_file}"}
1085
+ File.write(@option_config_file, @config_presets.to_yaml)
1004
1086
  Environment.restrict_file_access(@main_folder)
1005
1087
  Environment.restrict_file_access(@option_config_file)
1006
1088
  end
@@ -1013,21 +1095,23 @@ module Aspera
1013
1095
  Log.log.debug('skip default config')
1014
1096
  return nil
1015
1097
  end
1016
- if @config_presets.has_key?(CONF_PRESET_DEFAULT) &&
1017
- @config_presets[CONF_PRESET_DEFAULT].has_key?(plugin_sym.to_s)
1098
+ if @config_presets.key?(CONF_PRESET_DEFAULT) &&
1099
+ @config_presets[CONF_PRESET_DEFAULT].key?(plugin_sym.to_s)
1018
1100
  default_config_name = @config_presets[CONF_PRESET_DEFAULT][plugin_sym.to_s]
1019
- if !@config_presets.has_key?(default_config_name)
1020
- Log.log.error("Default config name [#{default_config_name}] specified for plugin [#{plugin_sym}], but it does not exist in config file.\n"\
1021
- 'Please fix the issue: either create preset with one parameter: '\
1022
- "(#{@info[:name]} config id #{default_config_name} init @json:'{}') or remove default (#{@info[:name]} config id default remove #{plugin_sym}).")
1101
+ if !@config_presets.key?(default_config_name)
1102
+ Log.log.error do
1103
+ "Default config name [#{default_config_name}] specified for plugin [#{plugin_sym}], but it does not exist in config file.\n"\
1104
+ 'Please fix the issue: either create preset with one parameter: '\
1105
+ "(#{@info[:name]} config id #{default_config_name} init @json:'{}') or remove default (#{@info[:name]} config id default remove #{plugin_sym})."
1106
+ end
1023
1107
  end
1024
- raise CliError,"Config name [#{default_config_name}] must be a hash, check config file." if !@config_presets[default_config_name].is_a?(Hash)
1108
+ raise CliError, "Config name [#{default_config_name}] must be a hash, check config file." if !@config_presets[default_config_name].is_a?(Hash)
1025
1109
  return default_config_name
1026
1110
  end
1027
1111
  return nil
1028
1112
  end # get_plugin_default_config_name
1029
1113
 
1030
- ALLOWED_KEYS=%i[password username description].freeze
1114
+ ALLOWED_KEYS = %i[password username description].freeze
1031
1115
  def execute_vault
1032
1116
  command = options.get_next_command(%i[list show create delete password])
1033
1117
  case command
@@ -1036,11 +1120,11 @@ module Aspera
1036
1120
  when :show
1037
1121
  return {type: :single_object, data: vault.get(label: options.get_next_argument('label'))}
1038
1122
  when :create
1039
- label=options.get_next_argument('label')
1040
- info=options.get_next_argument('info Hash')
1123
+ label = options.get_next_argument('label')
1124
+ info = options.get_next_argument('info Hash')
1041
1125
  raise 'info must be Hash' unless info.is_a?(Hash)
1042
- info=info.symbolize_keys
1043
- info[:label]=label
1126
+ info = info.symbolize_keys
1127
+ info[:label] = label
1044
1128
  vault.set(info)
1045
1129
  return Main.result_status('Password added')
1046
1130
  when :delete
@@ -1048,58 +1132,77 @@ module Aspera
1048
1132
  return Main.result_status('Password deleted')
1049
1133
  when :password
1050
1134
  raise 'Vault does not support password change' unless vault.respond_to?(:password=)
1051
- new_password=options.get_next_argument('new_password')
1052
- vault.password=new_password
1135
+ new_password = options.get_next_argument('new_password')
1136
+ vault.password = new_password
1053
1137
  vault.save
1054
1138
  return Main.result_status('Password updated')
1055
1139
  end
1056
1140
  end
1057
1141
 
1058
1142
  def vault_value(name)
1059
- m=name.match(/^(.+)\.(.+)$/)
1143
+ m = name.match(/^(.+)\.(.+)$/)
1060
1144
  raise 'vault name shall match <name>.<param>' if m.nil?
1061
- info=vault.get(label: m[1])
1062
- #raise "no such vault entry: #{m[1]}" if info.nil?
1063
- value=info[m[2].to_sym]
1145
+ info = vault.get(label: m[1])
1146
+ # raise "no such vault entry: #{m[1]}" if info.nil?
1147
+ value = info[m[2].to_sym]
1064
1148
  raise "no such entry value: #{m[2]}" if value.nil?
1065
1149
  return value
1066
1150
  end
1067
1151
 
1068
1152
  def vault
1069
1153
  if @vault.nil?
1070
- vault_info = options.get_option(:vault) || {'type'=>'file','name'=>'vault.bin'}
1071
- vault_password = options.get_option(:vault_password,is_type: :mandatory)
1154
+ vault_info = options.get_option(:vault) || {'type' => 'file', 'name' => 'vault.bin'}
1155
+ vault_password = options.get_option(:vault_password, is_type: :mandatory)
1072
1156
  raise 'vault must be Hash' unless vault_info.is_a?(Hash)
1073
1157
  vault_type = vault_info['type'] || 'file'
1074
1158
  vault_name = vault_info['name'] || (vault_type.eql?('file') ? 'vault.bin' : PROGRAM_NAME)
1075
1159
  case vault_type
1076
1160
  when 'file'
1077
- vault_path=vault_name
1078
- @vault = Keychain::EncryptedHash.new(vault_path,vault_password)
1161
+ # absolute_path? introduced in ruby 2.7
1162
+ vault_path = vault_name.eql?(File.absolute_path(vault_name)) ? vault_name : File.join(@main_folder, vault_name)
1163
+ @vault = Keychain::EncryptedHash.new(vault_path, vault_password)
1079
1164
  when 'system'
1080
1165
  case Environment.os
1081
1166
  when Environment::OS_X
1082
- @vault = Keychain::MacosSystem.new(vault_name,vault_password)
1083
- when Environment::OS_WINDOWS,Environment::OS_LINUX,Environment::OS_AIX
1167
+ @vault = Keychain::MacosSystem.new(vault_name, vault_password)
1168
+ when Environment::OS_WINDOWS, Environment::OS_LINUX, Environment::OS_AIX
1084
1169
  raise 'not implemented'
1085
1170
  else raise 'Error, OS not supported'
1086
1171
  end
1087
1172
  else
1088
- raise CliBadArgument,"Unknown vault type: #{vault_type}"
1173
+ raise CliBadArgument, "Unknown vault type: #{vault_type}"
1089
1174
  end
1090
1175
  end
1091
1176
  raise 'No vault defined' if @vault.nil?
1092
1177
  @vault
1093
1178
  end
1094
1179
 
1095
- def get_secret(options)
1096
- raise 'options shall be Hash' unless options.is_a?(Hash)
1097
- raise 'options shall have username' unless options.has_key?(:username)
1098
- secret = self.options.get_option(:secret)
1180
+ # version of URL without trailing "/" and removing default port
1181
+ def canonical_url(url)
1182
+ url.gsub(%r{/+$}, '').gsub(%r{^(https://[^/]+):443$}, '\1')
1183
+ end
1184
+
1185
+ def lookup_preset(url:, username:)
1186
+ # remove extra info to maximize match
1187
+ url = canonical_url(url)
1188
+ Log.log.debug{"Lookup preset for #{username}@#{url}"}
1189
+ @config_presets.each do |_k, v|
1190
+ next unless v.is_a?(Hash)
1191
+ conf_url = v['url'].is_a?(String) ? canonical_url(v['url']) : nil
1192
+ return v if conf_url.eql?(url) && v['username'].eql?(username)
1193
+ end
1194
+ nil
1195
+ end
1196
+
1197
+ def lookup_secret(url:, username:, mandatory: false)
1198
+ secret = options.get_option(:secret)
1099
1199
  if secret.nil?
1100
- secret = vault.get(options) rescue nil
1101
- # mandatory by default
1102
- raise "please provide secret for #{options[:username]}" if secret.nil? && (options[:mandatory].nil? || options[:mandatory])
1200
+ conf = lookup_preset(url: url, username: username)
1201
+ if conf.is_a?(Hash)
1202
+ Log.log.debug{"Found preset #{conf} with URL and username"}
1203
+ secret = conf['password']
1204
+ end
1205
+ raise "Please provide secret for #{username} using option: secret or by setting a preset for #{username}@#{url}." if secret.nil? && mandatory
1103
1206
  end
1104
1207
  return secret
1105
1208
  end
@@ -1109,33 +1212,33 @@ module Aspera
1109
1212
  params[:plugin_name] = AOC_COMMAND_CURRENT
1110
1213
  organization = AoC.parse_url(params[:instance_url]).first
1111
1214
  # if not defined by user, generate name
1112
- params[:preset_name] = [params[:application],organization].join('_') if params[:preset_name].nil?
1215
+ params[:preset_name] = [params[:application], organization].join('_') if params[:preset_name].nil?
1113
1216
  self.format.display_status("Preparing preset: #{params[:preset_name]}")
1114
1217
  # init defaults if necessary
1115
1218
  @config_presets[CONF_PRESET_DEFAULT] ||= {}
1116
- option_override = options.get_option(:override,is_type: :mandatory)
1117
- params[:option_default] = options.get_option(:default,is_type: :mandatory)
1118
- Log.log.error("override=#{option_override} -> #{option_override.class}")
1119
- raise CliError,"A default configuration already exists for plugin '#{params[:plugin_name]}' (use --override=yes or --default=no)" \
1120
- if !option_override && params[:option_default] && @config_presets[CONF_PRESET_DEFAULT].has_key?(params[:plugin_name])
1121
- raise CliError,"Preset already exists: #{params[:preset_name]} (use --override=yes or --id=<name>)" \
1122
- if !option_override && @config_presets.has_key?(params[:preset_name])
1219
+ option_override = options.get_option(:override, is_type: :mandatory)
1220
+ params[:option_default] = options.get_option(:default, is_type: :mandatory)
1221
+ Log.log.error{"override=#{option_override} -> #{option_override.class}"}
1222
+ raise CliError, "A default configuration already exists for plugin '#{params[:plugin_name]}' (use --override=yes or --default=no)" \
1223
+ if !option_override && params[:option_default] && @config_presets[CONF_PRESET_DEFAULT].key?(params[:plugin_name])
1224
+ raise CliError, "Preset already exists: #{params[:preset_name]} (use --override=yes or --id=<name>)" \
1225
+ if !option_override && @config_presets.key?(params[:preset_name])
1123
1226
  # lets see if path to priv key is provided
1124
1227
  private_key_path = options.get_option(:pkeypath)
1125
1228
  # give a chance to provide
1126
1229
  if private_key_path.nil?
1127
1230
  self.format.display_status('Please provide path to your private RSA key, or empty to generate one:')
1128
- private_key_path = options.get_option(:pkeypath,is_type: :mandatory).to_s
1231
+ private_key_path = options.get_option(:pkeypath, is_type: :mandatory).to_s
1129
1232
  end
1130
1233
  # else generate path
1131
1234
  if private_key_path.empty?
1132
- private_key_path = File.join(@main_folder,DEFAULT_PRIV_KEY_FILENAME)
1235
+ private_key_path = File.join(@main_folder, DEFAULT_PRIV_KEY_FILENAME)
1133
1236
  end
1134
1237
  if File.exist?(private_key_path)
1135
1238
  self.format.display_status('Using existing key:')
1136
1239
  else
1137
1240
  self.format.display_status("Generating #{DEFAULT_PRIVKEY_LENGTH} bit RSA key...")
1138
- generate_rsa_private_key(private_key_path,DEFAULT_PRIVKEY_LENGTH)
1241
+ generate_rsa_private_key(private_key_path, DEFAULT_PRIVKEY_LENGTH)
1139
1242
  self.format.display_status('Created:')
1140
1243
  end
1141
1244
  self.format.display_status(private_key_path)
@@ -1143,7 +1246,7 @@ module Aspera
1143
1246
  # declare command line options for AoC
1144
1247
  require 'aspera/cli/plugins/aoc'
1145
1248
  # make username mandatory for jwt, this triggers interactive input
1146
- options.get_option(:username,is_type: :mandatory)
1249
+ options.get_option(:username, is_type: :mandatory)
1147
1250
  # instanciate AoC plugin, so that command line options are known
1148
1251
  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
1149
1252
  auto_set_pub_key = false
@@ -1162,7 +1265,7 @@ module Aspera
1162
1265
  end
1163
1266
  else
1164
1267
  self.format.display_status('Using organization specific client_id.')
1165
- if options.get_option(:client_id).nil? || options.get_option(:client_secret,is_type: :optional).nil?
1268
+ if options.get_option(:client_id).nil? || options.get_option(:client_secret, is_type: :optional).nil?
1166
1269
  self.format.display_status('Please login to your Aspera on Cloud instance.'.red)
1167
1270
  self.format.display_status('Go to: Apps->Admin->Organization->Integrations')
1168
1271
  self.format.display_status('Create or check if there is an existing integration named:')
@@ -1173,8 +1276,8 @@ module Aspera
1173
1276
  self.format.display_status('Please enter:'.red)
1174
1277
  end
1175
1278
  OpenApplication.instance.uri("#{params[:instance_url]}/#{AOC_PATH_API_CLIENTS}")
1176
- options.get_option(:client_id,is_type: :mandatory)
1177
- options.get_option(:client_secret,is_type: :mandatory)
1279
+ options.get_option(:client_id, is_type: :mandatory)
1280
+ options.get_option(:client_secret, is_type: :mandatory)
1178
1281
  use_browser_authentication = true
1179
1282
  end
1180
1283
  if use_browser_authentication
@@ -1187,13 +1290,13 @@ module Aspera
1187
1290
  end
1188
1291
  myself = aoc_api.read('self')[:data]
1189
1292
  if auto_set_pub_key
1190
- raise CliError,'Public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? || option_override
1293
+ raise CliError, 'Public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? || option_override
1191
1294
  self.format.display_status('Updating profile with new key')
1192
- aoc_api.update("users/#{myself['id']}",{'public_key' => pub_key_pem})
1295
+ aoc_api.update("users/#{myself['id']}", {'public_key' => pub_key_pem})
1193
1296
  end
1194
1297
  if auto_set_jwt
1195
1298
  self.format.display_status('Enabling JWT for client')
1196
- aoc_api.update("clients/#{options.get_option(:client_id)}",{'jwt_grant_enabled' => true,'explicit_authorization_required' => false})
1299
+ aoc_api.update("clients/#{options.get_option(:client_id)}", {'jwt_grant_enabled' => true, 'explicit_authorization_required' => false})
1197
1300
  end
1198
1301
  self.format.display_status("Creating new config preset: #{params[:preset_name]}")
1199
1302
  @config_presets[params[:preset_name]] = {
@@ -1213,34 +1316,34 @@ module Aspera
1213
1316
  def wizard_faspex5(params)
1214
1317
  self.format.display_status('Detected: Faspex v5'.bold)
1215
1318
  # if not defined by user, generate unique name
1216
- params[:preset_name] = [params[:application],URI.parse(params[:instance_url]).host.gsub(/[^a-z0-9.]/,'').split('.')].flatten.join('_') \
1319
+ params[:preset_name] = [params[:application]].concat(URI.parse(params[:instance_url]).host.gsub(/[^a-z0-9.]/, '').split('.')).join('_') \
1217
1320
  if params[:preset_name].nil?
1218
1321
  self.format.display_status("Preparing preset: #{params[:preset_name]}")
1219
1322
  # init defaults if necessary
1220
1323
  @config_presets[CONF_PRESET_DEFAULT] ||= {}
1221
- option_override = options.get_option(:override,is_type: :mandatory)
1222
- params[:option_default] = options.get_option(:default,is_type: :mandatory)
1223
- Log.log.error("override=#{option_override} -> #{option_override.class}")
1224
- raise CliError,"A default configuration already exists for plugin '#{params[:plugin_name]}' (use --override=yes or --default=no)" \
1225
- if !option_override && params[:option_default] && @config_presets[CONF_PRESET_DEFAULT].has_key?(params[:plugin_name])
1226
- raise CliError,"Preset already exists: #{params[:preset_name]} (use --override=yes or --id=<name>)" \
1227
- if !option_override && @config_presets.has_key?(params[:preset_name])
1324
+ option_override = options.get_option(:override, is_type: :mandatory)
1325
+ params[:option_default] = options.get_option(:default, is_type: :mandatory)
1326
+ Log.log.error{"override=#{option_override} -> #{option_override.class}"}
1327
+ raise CliError, "A default configuration already exists for plugin '#{params[:plugin_name]}' (use --override=yes or --default=no)" \
1328
+ if !option_override && params[:option_default] && @config_presets[CONF_PRESET_DEFAULT].key?(params[:plugin_name])
1329
+ raise CliError, "Preset already exists: #{params[:preset_name]} (use --override=yes or --id=<name>)" \
1330
+ if !option_override && @config_presets.key?(params[:preset_name])
1228
1331
  # lets see if path to priv key is provided
1229
1332
  private_key_path = options.get_option(:pkeypath)
1230
1333
  # give a chance to provide
1231
1334
  if private_key_path.nil?
1232
1335
  self.format.display_status('Please provide path to your private RSA key, or empty to generate one:')
1233
- private_key_path = options.get_option(:pkeypath,is_type: :mandatory).to_s
1336
+ private_key_path = options.get_option(:pkeypath, is_type: :mandatory).to_s
1234
1337
  end
1235
1338
  # else generate path
1236
1339
  if private_key_path.empty?
1237
- private_key_path = File.join(@main_folder,DEFAULT_PRIV_KEY_FILENAME)
1340
+ private_key_path = File.join(@main_folder, DEFAULT_PRIV_KEY_FILENAME)
1238
1341
  end
1239
1342
  if File.exist?(private_key_path)
1240
1343
  self.format.display_status('Using existing key:')
1241
1344
  else
1242
1345
  self.format.display_status("Generating #{DEFAULT_PRIVKEY_LENGTH} bit RSA key...")
1243
- generate_rsa_private_key(private_key_path,DEFAULT_PRIVKEY_LENGTH)
1346
+ generate_rsa_private_key(private_key_path, DEFAULT_PRIVKEY_LENGTH)
1244
1347
  self.format.display_status('Created:')
1245
1348
  end
1246
1349
  self.format.display_status(private_key_path)
@@ -1261,8 +1364,8 @@ module Aspera
1261
1364
  :username.to_s => options.get_option(:username),
1262
1365
  :auth.to_s => :jwt.to_s,
1263
1366
  :private_key.to_s => '@file:' + private_key_path,
1264
- :client_id.to_s => options.get_option(:client_id,is_type: :mandatory),
1265
- :client_secret.to_s => options.get_option(:client_secret,is_type: :mandatory)
1367
+ :client_id.to_s => options.get_option(:client_id, is_type: :mandatory),
1368
+ :client_secret.to_s => options.get_option(:client_secret, is_type: :mandatory)
1266
1369
  }
1267
1370
  params[:test_args] = "#{params[:plugin_name]} user profile show"
1268
1371
  end