aspera-cli 4.10.0 → 4.11.0

Sign up to get free protection for your applications and to get access to all the features.
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