aspera-cli 4.13.0 → 4.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +28 -5
  4. data/CONTRIBUTING.md +17 -1
  5. data/README.md +782 -401
  6. data/examples/dascli +1 -1
  7. data/examples/rubyc +24 -0
  8. data/lib/aspera/aoc.rb +21 -32
  9. data/lib/aspera/ascmd.rb +1 -0
  10. data/lib/aspera/cli/basic_auth_plugin.rb +6 -6
  11. data/lib/aspera/cli/formatter.rb +17 -25
  12. data/lib/aspera/cli/main.rb +21 -27
  13. data/lib/aspera/cli/manager.rb +128 -114
  14. data/lib/aspera/cli/plugin.rb +87 -38
  15. data/lib/aspera/cli/plugins/alee.rb +2 -2
  16. data/lib/aspera/cli/plugins/aoc.rb +216 -102
  17. data/lib/aspera/cli/plugins/ats.rb +16 -18
  18. data/lib/aspera/cli/plugins/bss.rb +3 -3
  19. data/lib/aspera/cli/plugins/config.rb +177 -367
  20. data/lib/aspera/cli/plugins/console.rb +4 -6
  21. data/lib/aspera/cli/plugins/cos.rb +12 -13
  22. data/lib/aspera/cli/plugins/faspex.rb +17 -18
  23. data/lib/aspera/cli/plugins/faspex5.rb +332 -216
  24. data/lib/aspera/cli/plugins/node.rb +171 -142
  25. data/lib/aspera/cli/plugins/orchestrator.rb +15 -18
  26. data/lib/aspera/cli/plugins/preview.rb +38 -60
  27. data/lib/aspera/cli/plugins/server.rb +22 -15
  28. data/lib/aspera/cli/plugins/shares.rb +24 -33
  29. data/lib/aspera/cli/plugins/sync.rb +3 -3
  30. data/lib/aspera/cli/transfer_agent.rb +29 -26
  31. data/lib/aspera/cli/version.rb +1 -1
  32. data/lib/aspera/colors.rb +9 -7
  33. data/lib/aspera/data/6 +0 -0
  34. data/lib/aspera/environment.rb +7 -3
  35. data/lib/aspera/fasp/agent_connect.rb +5 -0
  36. data/lib/aspera/fasp/agent_direct.rb +5 -5
  37. data/lib/aspera/fasp/agent_httpgw.rb +138 -60
  38. data/lib/aspera/fasp/agent_trsdk.rb +2 -0
  39. data/lib/aspera/fasp/error_info.rb +2 -0
  40. data/lib/aspera/fasp/installation.rb +18 -19
  41. data/lib/aspera/fasp/parameters.rb +18 -17
  42. data/lib/aspera/fasp/parameters.yaml +2 -1
  43. data/lib/aspera/fasp/resume_policy.rb +3 -3
  44. data/lib/aspera/fasp/transfer_spec.rb +6 -5
  45. data/lib/aspera/fasp/uri.rb +23 -21
  46. data/lib/aspera/faspex_postproc.rb +1 -1
  47. data/lib/aspera/hash_ext.rb +12 -2
  48. data/lib/aspera/keychain/macos_security.rb +13 -13
  49. data/lib/aspera/log.rb +1 -0
  50. data/lib/aspera/node.rb +62 -80
  51. data/lib/aspera/oauth.rb +1 -1
  52. data/lib/aspera/persistency_action_once.rb +1 -1
  53. data/lib/aspera/preview/terminal.rb +61 -15
  54. data/lib/aspera/preview/utils.rb +3 -3
  55. data/lib/aspera/proxy_auto_config.js +2 -2
  56. data/lib/aspera/rest.rb +37 -0
  57. data/lib/aspera/secret_hider.rb +6 -1
  58. data/lib/aspera/ssh.rb +1 -1
  59. data/lib/aspera/sync.rb +2 -0
  60. data.tar.gz.sig +0 -0
  61. metadata +3 -4
  62. metadata.gz.sig +0 -0
  63. data/docs/test_env.conf +0 -186
  64. data/lib/aspera/data/7 +0 -0
@@ -23,7 +23,10 @@ module Aspera
23
23
  # either in standard domain, or product name in page
24
24
  if URI.parse(base_url).host.end_with?(Aspera::AoC::PROD_DOMAIN) ||
25
25
  api.call({operation: 'GET', redirect_max: 1, headers: {'Accept' => 'text/html'}})[:http].body.include?(Aspera::AoC::PRODUCT_NAME)
26
- return {product: :aoc, version: 'SaaS' }
26
+ return {
27
+ version: 'SaaS',
28
+ name: 'Aspera on Cloud'
29
+ }
27
30
  end
28
31
  return nil
29
32
  end
@@ -50,6 +53,7 @@ module Aspera
50
53
  client_registration_token
51
54
  client_access_key
52
55
  kms_profile].freeze
56
+ # TODO: remove this and use %name: instead
53
57
  ENTITY_NAME_SPECIFIER = 'name'
54
58
  PACKAGE_QUERY_DEFAULT = {'archived' => false, 'exclude_dropbox_packages' => true, 'has_content' => true, 'received' => true}.freeze
55
59
 
@@ -58,28 +62,23 @@ module Aspera
58
62
  @cache_workspace_info = nil
59
63
  @cache_home_node_file = nil
60
64
  @cache_api_aoc = nil
61
- options.add_opt_list(:auth, Oauth::STD_AUTH_TYPES, 'OAuth type of authentication')
62
- options.add_opt_list(:operation, %i[push pull], 'client operation for transfers')
63
- options.add_opt_simple(:client_id, 'OAuth API client identifier')
64
- options.add_opt_simple(:client_secret, 'OAuth API client secret')
65
- options.add_opt_simple(:redirect_uri, 'OAuth API client redirect URI')
66
- options.add_opt_simple(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
67
- options.add_opt_simple(:scope, 'OAuth scope for AoC API calls')
68
- options.add_opt_simple(:passphrase, 'RSA private key passphrase')
69
- options.add_opt_simple(:workspace, 'Name of workspace')
70
- options.add_opt_simple(:name, "Resource name (prefer to use keyword #{ENTITY_NAME_SPECIFIER})")
71
- options.add_opt_simple(:link, 'Public link to shared resource')
72
- options.add_opt_simple(:new_user_option, 'New user creation option for unknown package recipients')
73
- options.add_opt_simple(:from_folder, 'Source folder for Folder-to-Folder transfer')
74
- options.add_opt_boolean(:validate_metadata, 'Validate shared inbox metadata')
75
- options.set_option(:validate_metadata, :yes)
76
- options.set_option(:operation, :push)
77
- options.set_option(:auth, :jwt)
78
- options.set_option(:scope, AoC::SCOPE_FILES_USER)
79
- options.set_option(:private_key, '@file:' + env[:private_key_path]) if env[:private_key_path].is_a?(String)
80
- options.set_option(:workspace, :default)
65
+ options.declare(:auth, 'OAuth type of authentication', values: Oauth::STD_AUTH_TYPES, default: :jwt)
66
+ options.declare(:operation, 'Client operation for transfers', values: %i[push pull], default: :push)
67
+ options.declare(:client_id, 'OAuth API client identifier')
68
+ options.declare(:client_secret, 'OAuth API client secret')
69
+ options.declare(:redirect_uri, 'OAuth API client redirect URI')
70
+ options.declare(:private_key, 'OAuth JWT RSA private key PEM value (prefix file path with @file:)')
71
+ options.declare(:scope, 'OAuth scope for AoC API calls', default: AoC::SCOPE_FILES_USER)
72
+ options.declare(:passphrase, 'RSA private key passphrase')
73
+ options.declare(:workspace, 'Name of workspace', default: :default)
74
+ # TODO: remove this and use %name: instead
75
+ options.declare(:name, "Resource name (prefer to use keyword #{ENTITY_NAME_SPECIFIER})")
76
+ options.declare(:link, 'Public link to shared resource')
77
+ options.declare(:new_user_option, 'New user creation option for unknown package recipients')
78
+ options.declare(:from_folder, 'Source folder for Folder-to-Folder transfer')
79
+ options.declare(:validate_metadata, 'Validate shared inbox metadata', values: :bool, default: true)
81
80
  options.parse_options!
82
- # add node plugin options
81
+ # add node plugin options (TODO: check needed ? if yes, tell why)
83
82
  Node.new(env.merge({man_only: true, skip_basic_auth_options: true}))
84
83
  end
85
84
 
@@ -114,7 +113,7 @@ module Aspera
114
113
  Log.log.debug('Using default workspace'.green)
115
114
  raise CliError, 'No default workspace defined for user, please specify workspace' if default_workspace_id.nil?
116
115
  default_workspace_id
117
- when String then aoc_api.lookup_entity_by_name('workspaces', ws_name)['id']
116
+ when String then aoc_api.lookup_by_name('workspaces', ws_name)['id']
118
117
  when NilClass then nil
119
118
  else raise CliError, 'unexpected value type for workspace'
120
119
  end
@@ -164,11 +163,11 @@ module Aspera
164
163
  l_res_name = options.get_option(:name)
165
164
  raise 'Provide either option id or name, not both' unless l_res_id.nil? || l_res_name.nil?
166
165
  # try to find item by name (single partial match or exact match)
167
- l_res_id = aoc_api.lookup_entity_by_name(resource_class_path, l_res_name)['id'] unless l_res_name.nil?
166
+ l_res_id = aoc_api.lookup_by_name(resource_class_path, l_res_name)['id'] unless l_res_name.nil?
168
167
  # if no name or id option, taken on command line (after command)
169
168
  if l_res_id.nil?
170
169
  l_res_id = options.get_next_argument('identifier')
171
- l_res_id = aoc_api.lookup_entity_by_name(resource_class_path, options.get_next_argument('identifier'))['id'] if l_res_id.eql?(ENTITY_NAME_SPECIFIER)
170
+ l_res_id = aoc_api.lookup_by_name(resource_class_path, options.get_next_argument('identifier'))['id'] if l_res_id.eql?(ENTITY_NAME_SPECIFIER)
172
171
  end
173
172
  return l_res_id
174
173
  end
@@ -240,15 +239,15 @@ module Aspera
240
239
  # server side is protocol server
241
240
  # in same workspace
242
241
  # default is push
243
- case options.get_option(:operation, is_type: :mandatory)
242
+ case options.get_option(:operation, mandatory: true)
244
243
  when :push
245
244
  client_direction = Fasp::TransferSpec::DIRECTION_SEND
246
- client_folder = options.get_option(:from_folder, is_type: :mandatory)
245
+ client_folder = options.get_option(:from_folder, mandatory: true)
247
246
  server_folder = transfer.destination_folder(client_direction)
248
247
  when :pull
249
248
  client_direction = Fasp::TransferSpec::DIRECTION_RECEIVE
250
249
  client_folder = transfer.destination_folder(client_direction)
251
- server_folder = options.get_option(:from_folder, is_type: :mandatory)
250
+ server_folder = options.get_option(:from_folder, mandatory: true)
252
251
  end
253
252
  client_apfid = top_node_api.resolve_api_fid(file_id, client_folder)
254
253
  server_apfid = top_node_api.resolve_api_fid(file_id, server_folder)
@@ -371,12 +370,12 @@ module Aspera
371
370
  filter = options.get_option(:query) || {}
372
371
  raise 'query must be Hash' unless filter.is_a?(Hash)
373
372
  filter['limit'] ||= 100
374
- if options.get_option(:once_only, is_type: :mandatory)
373
+ if options.get_option(:once_only, mandatory: true)
375
374
  saved_date = []
376
375
  start_date_persistency = PersistencyActionOnce.new(
377
376
  manager: @agents[:persistency],
378
377
  data: saved_date,
379
- ids: IdGenerator.from_list(['aoc_ana_date', options.get_option(:url, is_type: :mandatory), current_workspace_info['name']].push(
378
+ ids: IdGenerator.from_list(['aoc_ana_date', options.get_option(:url, mandatory: true), current_workspace_info['name']].push(
380
379
  filter_resource,
381
380
  filter_id)))
382
381
  start_date_time = saved_date.first
@@ -387,7 +386,7 @@ module Aspera
387
386
  filter['start_time'] = start_date_time unless start_date_time.nil?
388
387
  filter['stop_time'] = stop_date_time
389
388
  end
390
- events = analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}", option_url_query(filter))[:data][event_type]
389
+ events = analytics_api.read("#{filter_resource}/#{filter_id}/#{event_type}", query_read_delete(default: filter))[:data][event_type]
391
390
  start_date_persistency&.save
392
391
  if !options.get_option(:notif_to).nil?
393
392
  events.each do |tr_event|
@@ -451,7 +450,7 @@ module Aspera
451
450
  when :group_membership then default_fields.push(*%w[group_id member_type member_id])
452
451
  when :workspace_membership then default_fields.push(*%w[workspace_id member_type member_id])
453
452
  end
454
- items = read_with_paging(resource_class_path, option_url_query(default_query))
453
+ items = read_with_paging(resource_class_path, query_read_delete(default: default_query))
455
454
  formatter.display_item_count(items[:list].length, items[:total])
456
455
  return {type: :object_list, data: items[:list], fields: default_fields}
457
456
  when :show
@@ -491,7 +490,7 @@ module Aspera
491
490
  case command
492
491
  when :reminder
493
492
  # send an email reminder with list of orgs
494
- user_email = options.get_option(:username, is_type: :mandatory)
493
+ user_email = options.get_option(:username, mandatory: true)
495
494
  Rest.new(base_url: "#{AoC.api_base_url}/#{AoC::API_V1}").create('organization_reminders', {email: user_email})[:data]
496
495
  return Main.result_status("List of organizations user is member of, has been sent by e-mail to #{user_email}")
497
496
  when :servers
@@ -528,7 +527,7 @@ module Aspera
528
527
  when :shared_inboxes
529
528
  case options.get_next_command(%i[list show])
530
529
  when :list
531
- query = option_url_query(nil)
530
+ query = query_read_delete
532
531
  if query.nil?
533
532
  query = {'embed[]' => 'dropbox', 'aggregate_permissions_by_dropbox' => true, 'sort' => 'dropbox_name'}
534
533
  query['workspace_id'] = current_workspace_info['id'] unless current_workspace_info['id'].eql?(:undefined)
@@ -538,8 +537,7 @@ module Aspera
538
537
  return {type: :single_object, data: aoc_api.read(get_resource_path_from_args('dropboxes'), query)[:data]}
539
538
  end
540
539
  when :send
541
- package_data = options.get_option(:value, is_type: :mandatory)
542
- raise CliBadArgument, 'value must be hash, refer to doc' unless package_data.is_a?(Hash)
540
+ package_data = value_create_modify(command: package_command, type: Hash)
543
541
  new_user_option = options.get_option(:new_user_option)
544
542
  option_validate = options.get_option(:validate_metadata)
545
543
  # works for both normal usr auth and link auth
@@ -567,20 +565,20 @@ module Aspera
567
565
  ids_to_download = instance_identifier
568
566
  skip_ids_data = []
569
567
  skip_ids_persistency = nil
570
- if options.get_option(:once_only, is_type: :mandatory)
568
+ if options.get_option(:once_only, mandatory: true)
571
569
  skip_ids_persistency = PersistencyActionOnce.new(
572
570
  manager: @agents[:persistency],
573
571
  data: skip_ids_data,
574
- id: IdGenerator.from_list(['aoc_recv', options.get_option(:url, is_type: :mandatory),
572
+ id: IdGenerator.from_list(['aoc_recv', options.get_option(:url, mandatory: true),
575
573
  current_workspace_info['id']].concat(aoc_api.additional_persistence_ids)))
576
574
  end
577
575
  if VAL_ALL.eql?(ids_to_download)
578
- query = option_url_query(PACKAGE_QUERY_DEFAULT)
576
+ query = query_read_delete(default: PACKAGE_QUERY_DEFAULT)
579
577
  raise 'option query must be Hash' unless query.is_a?(Hash)
580
578
  if query.key?('dropbox_name')
581
579
  # convenience: specify name instead of id
582
580
  raise 'not both dropbox_name and dropbox_id' if query.key?('dropbox_id')
583
- query['dropbox_id'] = aoc_api.lookup_entity_by_name('dropboxes', query['dropbox_name'])['id']
581
+ query['dropbox_id'] = aoc_api.lookup_by_name('dropboxes', query['dropbox_name'])['id']
584
582
  query.delete('dropbox_name')
585
583
  end
586
584
  query['workspace_id'] ||= current_workspace_info['id'] unless current_workspace_info['id'].eql?(:undefined)
@@ -623,12 +621,12 @@ module Aspera
623
621
  return { type: :single_object, data: package_info }
624
622
  when :list
625
623
  display_fields = %w[id name bytes_transferred]
626
- query = option_url_query(PACKAGE_QUERY_DEFAULT)
624
+ query = query_read_delete(default: PACKAGE_QUERY_DEFAULT)
627
625
  raise 'option query must be Hash' unless query.is_a?(Hash)
628
626
  if query.key?('dropbox_name')
629
627
  # convenience: specify name instead of id
630
628
  raise 'not both dropbox_name and dropbox_id' if query.key?('dropbox_id')
631
- query['dropbox_id'] = aoc_api.lookup_entity_by_name('dropboxes', query['dropbox_name'])['id']
629
+ query['dropbox_id'] = aoc_api.lookup_by_name('dropboxes', query['dropbox_name'])['id']
632
630
  query.delete('dropbox_name')
633
631
  end
634
632
  if current_workspace_info['id'].eql?(:undefined)
@@ -655,75 +653,111 @@ module Aspera
655
653
  when *NODE4_EXT_COMMANDS
656
654
  return execute_nodegen4_command(command_repo, home_info[:node_id], file_id: home_info[:file_id], scope: AoC::SCOPE_NODE_USER)
657
655
  when :short_link
658
- # TODO: move to permissions ?
659
- folder_dest = options.get_option(:to_folder)
660
- value_option = options.get_option(:value)
661
- case value_option
662
- when 'public' then value_option = {'purpose' => 'token_auth_redirection'}
663
- when 'private' then value_option = {'purpose' => 'shared_folder_auth_link'}
664
- when NilClass, Hash then nil # keep value
665
- else raise 'value must be either: public, private, Hash or nil'
656
+ # execute action on AoC API
657
+ short_link_command = options.get_next_command(%i[create delete list])
658
+ folder_dest = options.get_next_argument('path')
659
+ link_type = options.get_next_argument('link type', expected: %i[public private])
660
+ home_node_api = aoc_api.node_api_from(
661
+ node_id: home_info[:node_id],
662
+ workspace_id: current_workspace_info['id'],
663
+ workspace_name: current_workspace_info['name'])
664
+ shared_apfid = home_node_api.resolve_api_fid(home_info[:file_id], folder_dest)
665
+ folder_info = {
666
+ node_id: shared_apfid[:api].app_info[:node_info]['id'],
667
+ file_id: shared_apfid[:file_id],
668
+ workspace_id: current_workspace_info['id']
669
+ }
670
+ purpose = case link_type
671
+ when :public then 'token_auth_redirection'
672
+ when :private then 'shared_folder_auth_link'
673
+ else raise 'internal error'
666
674
  end
667
- create_params = nil
668
- shared_apfid = nil
669
- if !folder_dest.nil?
670
- home_node_api = aoc_api.node_api_from(
671
- node_id: home_info[:node_id],
672
- workspace_id: current_workspace_info['id'],
673
- workspace_name: current_workspace_info['name'])
674
- shared_apfid = home_node_api.resolve_api_fid(home_info[:file_id], folder_dest)
675
- create_params = {
676
- file_id: shared_apfid[:file_id],
677
- node_id: shared_apfid[:api].app_info[:node_info]['id'],
678
- workspace_id: current_workspace_info['id']
675
+ case short_link_command
676
+ when :delete
677
+ one_id = instance_identifier
678
+ folder_info.delete(:workspace_id)
679
+ delete_params = {
680
+ edit_access: true,
681
+ json_query: folder_info.to_json
679
682
  }
680
- end
681
- if !value_option.nil? && !create_params.nil?
682
- case value_option['purpose']
683
- when 'shared_folder_auth_link'
684
- value_option['data'] = create_params
685
- value_option['user_selected_name'] = nil
686
- when 'token_auth_redirection'
687
- create_params['name'] = ''
688
- value_option['data'] = {
683
+ aoc_api.delete("short_links/#{one_id}", delete_params)
684
+ if link_type.eql?(:public)
685
+ # TODO: get permission id..
686
+ # shared_apfid[:api].delete('permissions', {ids: })[:data]
687
+ end
688
+ return Main.result_status('deleted')
689
+ when :list
690
+ query = if link_type.eql?(:private)
691
+ folder_info
692
+ else
693
+ {
694
+ url_token_data: {
695
+ data: folder_info,
696
+ purpose: 'view_shared_file'
697
+ }
698
+ }
699
+ end
700
+ list_params = {
701
+ json_query: query.to_json,
702
+ edit_access: true,
703
+ purpose: purpose,
704
+ # embed: 'updated_by_user',
705
+ sort: '-created_at'
706
+ }
707
+ result = aoc_api.read('short_links', list_params)[:data]
708
+ result.each{|i|i.delete('data')}
709
+ return {type: :object_list, data: result}
710
+ when :create
711
+ creation_params = {
712
+ purpose: purpose,
713
+ user_selected_name: nil
714
+ }
715
+ case link_type
716
+ when :private
717
+ creation_params[:data] = folder_info
718
+ when :public
719
+ creation_params[:expires_at] = nil
720
+ creation_params[:password_enabled] = false
721
+ folder_info[:name] = ''
722
+ creation_params[:data] = {
689
723
  aoc: true,
690
724
  url_token_data: {
691
- data: create_params,
725
+ data: folder_info,
692
726
  purpose: 'view_shared_file'
693
727
  }
694
728
  }
695
- value_option['user_selected_name'] = nil
696
- else
697
- raise 'purpose must be one of: token_auth_redirection or shared_folder_auth_link'
698
729
  end
699
- options.set_option(:value, value_option)
700
- end
701
- result = entity_action(aoc_api, 'short_links', id_default: 'self')
702
- if result[:data].is_a?(Hash) && result[:data].key?('created_at') && result[:data]['resource_type'].eql?('UrlToken')
703
- # TODO: access level as arg
704
- access_levels = Aspera::Node::ACCESS_LEVELS # ['delete','list','mkdir','preview','read','rename','write']
705
- perm_data = {
706
- 'file_id' => shared_apfid[:file_id],
707
- 'access_type' => 'user',
708
- 'access_id' => result[:data]['resource_id'],
709
- 'access_levels' => access_levels,
710
- 'tags' => {
711
- 'url_token' => true,
712
- 'workspace_id' => current_workspace_info['id'],
713
- 'workspace_name' => current_workspace_info['name'],
714
- 'folder_name' => 'my folder',
715
- 'created_by_name' => aoc_api.current_user_info['name'],
716
- 'created_by_email' => aoc_api.current_user_info['email'],
717
- 'access_key' => shared_apfid[:api].app_info[:node_info]['access_key'],
718
- 'node' => shared_apfid[:api].app_info[:node_info]['host']
730
+ result_create_short_link = aoc_api.create('short_links', creation_params)[:data]
731
+ # public: Creation: permission on node
732
+ if link_type.eql?(:public)
733
+ # TODO: merge with node permissions ?
734
+ # TODO: access level as arg
735
+ access_levels = Aspera::Node::ACCESS_LEVELS # ['delete','list','mkdir','preview','read','rename','write']
736
+ folder_name = File.basename(folder_dest)
737
+ perm_data = {
738
+ 'file_id' => shared_apfid[:file_id],
739
+ 'access_id' => result_create_short_link['resource_id'],
740
+ 'access_type' => 'user',
741
+ 'access_levels' => access_levels,
742
+ 'tags' => {
743
+ 'url_token' => true,
744
+ 'workspace_id' => current_workspace_info['id'],
745
+ 'workspace_name' => current_workspace_info['name'],
746
+ 'folder_name' => folder_name,
747
+ 'created_by_name' => aoc_api.current_user_info['name'],
748
+ 'created_by_email' => aoc_api.current_user_info['email'],
749
+ 'access_key' => shared_apfid[:api].app_info[:node_info]['access_key'],
750
+ 'node' => shared_apfid[:api].app_info[:node_info]['host']
751
+ }
719
752
  }
720
- }
721
- shared_apfid[:api].create("permissions?file_id=#{shared_apfid[:file_id]}", perm_data)
722
- # TODO: event ?
723
- end
724
- return result
753
+ created_data = shared_apfid[:api].create('permissions', perm_data)[:data]
754
+ aoc_api.permissions_send_event(created_data: created_data, app_info: shared_apfid[:api].app_info)
755
+ # TODO: event ?
756
+ end
757
+ return {type: :single_object, data: result_create_short_link}
758
+ end # short_link command
725
759
  end # files command
726
- throw('Error: shall not reach this line')
760
+ raise 'Error: shall not reach this line'
727
761
  when :automation
728
762
  Log.log.warn('BETA: work under progress')
729
763
  # automation api is not in the same place
@@ -760,7 +794,7 @@ module Aspera
760
794
  return execute_admin_action
761
795
  when :gateway
762
796
  require 'aspera/faspex_gw'
763
- url = options.get_option(:value, is_type: :mandatory)
797
+ url = value_create_modify(type: String)
764
798
  uri = URI.parse(url)
765
799
  server = WebServerSimple.new(uri)
766
800
  server.mount(uri.path, Faspex4GWServlet, aoc_api, current_workspace_info['id'])
@@ -776,6 +810,86 @@ module Aspera
776
810
  raise 'internal error: command shall return'
777
811
  end
778
812
 
813
+ # @param [Hash] params : plugin_sym, instance_url
814
+ # @return [Hash] :preset_value, :test_args
815
+ def wizard(params)
816
+ if params[:prepare]
817
+ organization = AoC.parse_url(params[:instance_url]).first
818
+ # if not defined by user, generate name
819
+ params[:preset_name] ||= [params[:plugin_sym], organization].join('_')
820
+ params[:need_private_key] = true
821
+ return
822
+ end
823
+ options.set_option(:private_key, '@file:' + params[:private_key_path])
824
+ # make username mandatory for jwt, this triggers interactive input
825
+ options.get_option(:username, mandatory: true)
826
+ auto_set_pub_key = false
827
+ auto_set_jwt = false
828
+ use_browser_authentication = false
829
+ if options.get_option(:use_generic_client)
830
+ formatter.display_status('Using global client_id.')
831
+ formatter.display_status('Please Login to your Aspera on Cloud instance.'.red)
832
+ formatter.display_status('Navigate to your "Account Settings"'.red)
833
+ formatter.display_status('Check or update the value of "Public Key" to be:'.red.blink)
834
+ formatter.display_status(params[:pub_key_pem])
835
+ if !options.get_option(:test_mode)
836
+ formatter.display_status('Once updated or validated, press enter.')
837
+ OpenApplication.instance.uri(params[:instance_url])
838
+ $stdin.gets
839
+ end
840
+ else
841
+ formatter.display_status('Using organization specific client_id.')
842
+ if options.get_option(:client_id).nil? || options.get_option(:client_secret).nil?
843
+ formatter.display_status('Please login to your Aspera on Cloud instance.'.red)
844
+ formatter.display_status('Go to: Apps->Admin->Organization->Integrations')
845
+ formatter.display_status('Create or check if there is an existing integration named:')
846
+ formatter.display_status("- name: #{@info[:name]}")
847
+ formatter.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
848
+ formatter.display_status('- origin: localhost')
849
+ formatter.display_status('Once created or identified,')
850
+ formatter.display_status('Please enter:'.red)
851
+ end
852
+ OpenApplication.instance.uri("#{params[:instance_url]}/#{AOC_PATH_API_CLIENTS}")
853
+ options.get_option(:client_id, mandatory: true)
854
+ options.get_option(:client_secret, mandatory: true)
855
+ use_browser_authentication = true
856
+ end
857
+ if use_browser_authentication
858
+ formatter.display_status('We will use web authentication to bootstrap.')
859
+ auto_set_pub_key = true
860
+ auto_set_jwt = true
861
+ aoc_api.oauth.generic_parameters[:grant_method] = :web
862
+ aoc_api.oauth.generic_parameters[:scope] = AoC::SCOPE_FILES_ADMIN
863
+ aoc_api.oauth.specific_parameters[:redirect_uri] = DEFAULT_REDIRECT
864
+ end
865
+ myself = aoc_api.read('self')[:data]
866
+ if auto_set_pub_key
867
+ raise CliError, 'Public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? || option_override
868
+ formatter.display_status('Updating profile with new key')
869
+ aoc_api.update("users/#{myself['id']}", {'public_key' => params[:pub_key_pem]})
870
+ end
871
+ if auto_set_jwt
872
+ formatter.display_status('Enabling JWT for client')
873
+ aoc_api.update("clients/#{options.get_option(:client_id)}", {'jwt_grant_enabled' => true, 'explicit_authorization_required' => false})
874
+ end
875
+ formatter.display_status("Creating new config preset: #{params[:preset_name]}")
876
+ preset_result = {
877
+ url: params[:instance_url],
878
+ username: myself['email'],
879
+ auth: :jwt.to_s,
880
+ private_key: '@file:' + params[:private_key_path]
881
+ }.stringify_keys
882
+ # set only if non nil
883
+ %i[client_id client_secret].each do |s|
884
+ o = options.get_option(s)
885
+ preset_result[s.to_s] = o unless o.nil?
886
+ end
887
+ return {
888
+ preset_value: preset_result,
889
+ test_args: "#{params[:plugin_sym]} user profile show"
890
+ }
891
+ end
892
+
779
893
  private :aoc_params,
780
894
  :home_info,
781
895
  :assert_public_link_types,
@@ -7,25 +7,24 @@ module Aspera
7
7
  module Cli
8
8
  module Plugins
9
9
  # Access Aspera Transfer Service
10
- # https://52.44.83.163/docs/
11
10
  # https://developer.ibm.com/aspera/docs/ats-api-reference/creating-ats-api-keys/
12
11
  class Ats < Aspera::Cli::Plugin
13
12
  def initialize(env)
14
13
  super(env)
15
- options.add_opt_simple(:ibm_api_key, 'IBM API key, see https://cloud.ibm.com/iam/apikeys')
16
- options.add_opt_simple(:instance, 'ATS instance in ibm cloud')
17
- options.add_opt_simple(:ats_key, 'ATS key identifier (ats_xxx)')
18
- options.add_opt_simple(:ats_secret, 'ATS key secret')
19
- options.add_opt_simple(:params, 'Parameters access key creation (@json:)')
20
- options.add_opt_simple(:cloud, 'Cloud provider')
21
- options.add_opt_simple(:region, 'Cloud region')
14
+ options.declare(:ibm_api_key, 'IBM API key, see https://cloud.ibm.com/iam/apikeys')
15
+ options.declare(:instance, 'ATS instance in ibm cloud')
16
+ options.declare(:ats_key, 'ATS key identifier (ats_xxx)')
17
+ options.declare(:ats_secret, 'ATS key secret')
18
+ options.declare(:params, 'Parameters access key creation (@json:)')
19
+ options.declare(:cloud, 'Cloud provider')
20
+ options.declare(:region, 'Cloud region')
22
21
  options.parse_options!
23
22
  end
24
23
 
25
24
  def server_by_cloud_region
26
25
  # TODO: provide list ?
27
- cloud = options.get_option(:cloud, is_type: :mandatory).upcase
28
- region = options.get_option(:region, is_type: :mandatory)
26
+ cloud = options.get_option(:cloud, mandatory: true).upcase
27
+ region = options.get_option(:region, mandatory: true)
29
28
  return @ats_api_pub.read("servers/#{cloud}/#{region}")[:data]
30
29
  end
31
30
 
@@ -36,8 +35,8 @@ module Aspera
36
35
  base_url: AtsApi.base_url + '/pub/v1',
37
36
  auth: {
38
37
  type: :basic,
39
- username: options.get_option(:ats_key, is_type: :mandatory),
40
- password: options.get_option(:ats_secret, is_type: :mandatory)}
38
+ username: options.get_option(:ats_key, mandatory: true),
39
+ password: options.get_option(:ats_secret, mandatory: true)}
41
40
  })
42
41
  end
43
42
 
@@ -90,7 +89,7 @@ module Aspera
90
89
  res = ats_api_pub_v1.read("access_keys/#{access_key_id}")
91
90
  return {type: :single_object, data: res[:data]}
92
91
  when :modify
93
- params = options.get_option(:value, is_type: :mandatory)
92
+ params = value_create_modify(command: command, type: Hash)
94
93
  params['id'] = access_key_id
95
94
  ats_api_pub_v1.update("access_keys/#{access_key_id}", params)
96
95
  return Main.result_status('modified')
@@ -138,7 +137,7 @@ module Aspera
138
137
  when :list
139
138
  return {type: :object_list, data: @ats_api_pub.all_servers, fields: %w[id cloud region]}
140
139
  when :show
141
- if options.get_option(:cloud) || options.get_option(:region, is_type: :optional)
140
+ if options.get_option(:cloud) || options.get_option(:region)
142
141
  server_data = server_by_cloud_region
143
142
  else
144
143
  server_id = instance_identifier
@@ -161,7 +160,7 @@ module Aspera
161
160
  generic: {
162
161
  grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
163
162
  response_type: 'cloud_iam',
164
- apikey: options.get_option(:ibm_api_key, is_type: :mandatory)
163
+ apikey: options.get_option(:ibm_api_key, mandatory: true)
165
164
  }}})
166
165
  end
167
166
 
@@ -187,8 +186,7 @@ module Aspera
187
186
  Log.log.warn{"more instances remaining: #{instances['remaining']}"} unless instances['remaining'].to_i.eql?(0)
188
187
  return {type: :value_list, data: instances['data'], name: 'instance'}
189
188
  when :create
190
- create_value = options.get_option(:value) || {}
191
- created_key = ats_ibm_api.create('api_keys', create_value)[:data]
189
+ created_key = ats_ibm_api.create('api_keys', value_create_modify(command: command, default: {}, type: Hash))[:data]
192
190
  return {type: :single_object, data: created_key}
193
191
  when :list # list known api keys in ATS (this require an api_key ...)
194
192
  res = ats_ibm_api.read('api_keys', {'offset' => 0, 'max_results' => 1000})
@@ -221,7 +219,7 @@ module Aspera
221
219
  when :api_key # manage credential to access ATS API
222
220
  return execute_action_api_key
223
221
  when :aws_trust_policy
224
- res = ats_api_pub_v1.read('aws/trustpolicy', {region: options.get_option(:region, is_type: :mandatory)})[:data]
222
+ res = ats_api_pub_v1.read('aws/trustpolicy', {region: options.get_option(:region, mandatory: true)})[:data]
225
223
  return {type: :single_object, data: res}
226
224
  else raise 'ERROR'
227
225
  end
@@ -23,7 +23,7 @@ module Aspera
23
23
 
24
24
  def execute_action
25
25
  if @api_bss.nil?
26
- key = options.get_option(:password, is_type: :mandatory)
26
+ key = options.get_option(:password, mandatory: true)
27
27
  @api_bss = Rest.new(
28
28
  base_url: 'https://dashboard.bss.asperasoft.com/platform',
29
29
  headers: {cookie: "_dashboard_key=#{key}"})
@@ -35,8 +35,8 @@ module Aspera
35
35
  object = 'bssSubscriptions'
36
36
  case command
37
37
  when :find
38
- query = options.get_option(:query, is_type: :mandatory) # AOC_ORGANIZATION_QUERY AOC_USER_EMAIL
39
- value = options.get_option(:value, is_type: :mandatory)
38
+ query = options.get_option(:query, mandatory: true) # AOC_ORGANIZATION_QUERY AOC_USER_EMAIL
39
+ value = value_create_modify(command: command)
40
40
  request = {
41
41
  'variables' => {'filter' => {'key' => query, 'value' => value}},
42
42
  'query' => "query($filter: BssSubscriptionFilter!) {#{object}(filter: $filter) { #{all_fields('bssSubscriptions')} } }"