aspera-cli 4.25.6 → 4.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +74 -47
- data/CONTRIBUTING.md +1 -1
- data/lib/aspera/api/aoc.rb +118 -78
- data/lib/aspera/api/node.rb +101 -49
- data/lib/aspera/ascp/installation.rb +94 -30
- data/lib/aspera/cli/extended_value.rb +1 -0
- data/lib/aspera/cli/formatter.rb +47 -40
- data/lib/aspera/cli/manager.rb +30 -4
- data/lib/aspera/cli/plugins/aoc.rb +214 -136
- data/lib/aspera/cli/plugins/ats.rb +3 -3
- data/lib/aspera/cli/plugins/base.rb +17 -42
- data/lib/aspera/cli/plugins/config.rb +5 -3
- data/lib/aspera/cli/plugins/console.rb +3 -3
- data/lib/aspera/cli/plugins/faspex.rb +5 -5
- data/lib/aspera/cli/plugins/faspex5.rb +20 -18
- data/lib/aspera/cli/plugins/node.rb +66 -70
- data/lib/aspera/cli/plugins/oauth.rb +5 -12
- data/lib/aspera/cli/plugins/orchestrator.rb +13 -13
- data/lib/aspera/cli/plugins/preview.rb +116 -80
- data/lib/aspera/cli/plugins/server.rb +2 -10
- data/lib/aspera/cli/plugins/shares.rb +7 -7
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/dot_container.rb +7 -3
- data/lib/aspera/environment.rb +3 -2
- data/lib/aspera/log.rb +1 -1
- data/lib/aspera/preview/file_types.rb +1 -1
- data/lib/aspera/preview/generator.rb +146 -91
- data/lib/aspera/preview/options.rb +4 -1
- data/lib/aspera/preview/terminal.rb +50 -20
- data/lib/aspera/preview/utils.rb +76 -34
- data/lib/aspera/products/transferd.rb +1 -1
- data/lib/aspera/rest.rb +1 -0
- data/lib/aspera/rest_list.rb +23 -16
- data/lib/aspera/secret_hider.rb +3 -1
- data/lib/aspera/uri_reader.rb +17 -2
- data.tar.gz.sig +0 -0
- metadata +5 -5
- metadata.gz.sig +0 -0
data/lib/aspera/api/aoc.rb
CHANGED
|
@@ -12,12 +12,52 @@ require 'base64'
|
|
|
12
12
|
|
|
13
13
|
module Aspera
|
|
14
14
|
module Api
|
|
15
|
+
# information relative to Files or Packages App
|
|
16
|
+
|
|
15
17
|
# Aspera on Cloud API client
|
|
16
18
|
class AoC < Rest
|
|
17
19
|
include RestList
|
|
18
20
|
|
|
21
|
+
module AppType
|
|
22
|
+
FILES = 'files'
|
|
23
|
+
PACKAGES = 'packages'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class AppInfo
|
|
27
|
+
# @return [Aspera::Api::AoC] Rest Api object
|
|
28
|
+
attr_reader :api
|
|
29
|
+
# @return [Hash, nil] Package information, `"files"` or `"packages"`
|
|
30
|
+
attr_reader :package
|
|
31
|
+
# @return [Hash] Result of GET /nodes/:id
|
|
32
|
+
attr_reader :node_info
|
|
33
|
+
# @return [String] Workspace id
|
|
34
|
+
attr_reader :workspace_id
|
|
35
|
+
# @return [String] Workspace name
|
|
36
|
+
attr_reader :workspace_name
|
|
37
|
+
# @return [String, nil] "Share as" link name
|
|
38
|
+
attr_accessor :opt_link_name
|
|
39
|
+
|
|
40
|
+
# @param api [Api::Aoc] Rest Api object
|
|
41
|
+
# @param package [Hash,nil] package information or nil
|
|
42
|
+
# @param node_info [Hash] Result of GET /nodes/:id
|
|
43
|
+
# @param workspace_id [String]
|
|
44
|
+
# @param workspace_name [String]
|
|
45
|
+
def initialize(api, package, node_info, workspace_id, workspace_name)
|
|
46
|
+
@api = api
|
|
47
|
+
@package = package
|
|
48
|
+
@node_info = node_info
|
|
49
|
+
@workspace_id = workspace_id
|
|
50
|
+
@workspace_name = workspace_name
|
|
51
|
+
@opt_link_name = nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @return ["files", "packages"] Type of application
|
|
55
|
+
def app
|
|
56
|
+
package.nil? ? AppType::FILES : AppType::PACKAGES
|
|
57
|
+
end
|
|
58
|
+
end
|
|
19
59
|
PRODUCT_NAME = 'Aspera on Cloud'
|
|
20
|
-
#
|
|
60
|
+
# `''` Use default workspace if it is set, else none
|
|
21
61
|
DEFAULT_WORKSPACE = ''
|
|
22
62
|
# Production domain of AoC
|
|
23
63
|
SAAS_DOMAIN_PROD = 'ibmaspera.com' # cspell:disable-line
|
|
@@ -39,6 +79,7 @@ module Aspera
|
|
|
39
79
|
PERMISSIONS_CREATED = ['permission.created'].freeze
|
|
40
80
|
# Special user identifier when creating workspace shared folders
|
|
41
81
|
ID_AK_ADMIN = 'ASPERA_ACCESS_KEY_ADMIN'
|
|
82
|
+
HEADER_X_TOTAL_COUNT = 'X-Total-Count'
|
|
42
83
|
|
|
43
84
|
private_constant :MAX_AOC_URL_REDIRECT,
|
|
44
85
|
:CLIENT_ID_PREFIX,
|
|
@@ -49,18 +90,19 @@ module Aspera
|
|
|
49
90
|
:OAUTH_API_SUBPATH,
|
|
50
91
|
:USER_INFO_FIELDS_MIN,
|
|
51
92
|
:PERMISSIONS_CREATED,
|
|
52
|
-
:ID_AK_ADMIN
|
|
93
|
+
:ID_AK_ADMIN,
|
|
94
|
+
:HEADER_X_TOTAL_COUNT
|
|
53
95
|
|
|
54
96
|
# Various API scopes supported
|
|
55
97
|
module Scope
|
|
56
98
|
SELF = 'self'
|
|
99
|
+
# Scope `user:all`
|
|
57
100
|
USER = 'user:all'
|
|
101
|
+
# Scope `admin:all`
|
|
58
102
|
ADMIN = 'admin:all'
|
|
59
103
|
ADMIN_USER = 'admin-user:all'
|
|
60
104
|
ADMIN_USER_USER = "#{ADMIN_USER}+#{USER}"
|
|
61
105
|
end
|
|
62
|
-
FILES_APP = 'files'
|
|
63
|
-
PACKAGES_APP = 'packages'
|
|
64
106
|
API_V1 = 'api/v1'
|
|
65
107
|
|
|
66
108
|
# class static methods
|
|
@@ -92,8 +134,9 @@ module Aspera
|
|
|
92
134
|
false
|
|
93
135
|
end
|
|
94
136
|
|
|
137
|
+
# Get information from link
|
|
95
138
|
# @param url [String] URL of AoC public link
|
|
96
|
-
# @return [Hash]
|
|
139
|
+
# @return [Hash{Symbol => String, Hash}] Information about public link, or nil if not a public link
|
|
97
140
|
def link_info(url)
|
|
98
141
|
final_uri = Rest.new(base_url: url, redirect_max: MAX_AOC_URL_REDIRECT).call(operation: 'GET', ret: :resp).uri
|
|
99
142
|
Log.dump(:final_uri, final_uri, level: :trace1)
|
|
@@ -169,7 +212,7 @@ module Aspera
|
|
|
169
212
|
new_query['page'] = current_page
|
|
170
213
|
result_data, result_http = yield(new_query)
|
|
171
214
|
Aspera.assert(result_http)
|
|
172
|
-
total_count = result_http[
|
|
215
|
+
total_count = result_http[HEADER_X_TOTAL_COUNT]&.to_i
|
|
173
216
|
page_count += 1
|
|
174
217
|
current_page += 1
|
|
175
218
|
add_items = result_data
|
|
@@ -221,21 +264,23 @@ module Aspera
|
|
|
221
264
|
end
|
|
222
265
|
|
|
223
266
|
attr_reader :private_link
|
|
267
|
+
attr_accessor :ws_ids
|
|
224
268
|
|
|
269
|
+
# By default: no workspace
|
|
225
270
|
def initialize(
|
|
271
|
+
scope: nil,
|
|
272
|
+
subpath: API_V1,
|
|
273
|
+
secret_finder: nil,
|
|
274
|
+
# below: OAuth::AUTH_OPTIONS
|
|
226
275
|
url:,
|
|
227
276
|
auth:,
|
|
228
|
-
subpath: API_V1,
|
|
229
277
|
client_id: nil,
|
|
230
278
|
client_secret: nil,
|
|
231
|
-
scope: nil,
|
|
232
279
|
redirect_uri: nil,
|
|
233
280
|
private_key: nil,
|
|
234
281
|
passphrase: nil,
|
|
235
282
|
username: nil,
|
|
236
|
-
password: nil
|
|
237
|
-
workspace: nil,
|
|
238
|
-
secret_finder: nil
|
|
283
|
+
password: nil
|
|
239
284
|
)
|
|
240
285
|
# Test here because link may set url
|
|
241
286
|
Aspera.assert(url, 'Missing mandatory option: url', type: ParameterError)
|
|
@@ -246,10 +291,12 @@ module Aspera
|
|
|
246
291
|
# key: access key
|
|
247
292
|
# value: associated secret
|
|
248
293
|
@secret_finder = secret_finder
|
|
249
|
-
@workspace_name = workspace
|
|
250
294
|
@cache_user_info = nil
|
|
251
295
|
@cache_url_token_info = nil
|
|
296
|
+
# @type [Hash]
|
|
252
297
|
@workspace_info = nil
|
|
298
|
+
# Used only for init: provided by user
|
|
299
|
+
@ws_ids = {id: nil, name: nil}
|
|
253
300
|
@home_info = nil
|
|
254
301
|
auth_params = {
|
|
255
302
|
type: :oauth2,
|
|
@@ -350,34 +397,38 @@ module Aspera
|
|
|
350
397
|
return @cache_user_info
|
|
351
398
|
end
|
|
352
399
|
|
|
353
|
-
|
|
354
|
-
|
|
400
|
+
def default_workspace?
|
|
401
|
+
@ws_ids[:name].eql?(DEFAULT_WORKSPACE)
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# Cached workspace information.
|
|
405
|
+
# Always with `:name`.
|
|
406
|
+
# If no workspace, then no `:id`
|
|
407
|
+
# @return [Hash{Symbol=>String}] Workspace info.
|
|
408
|
+
def workspace_info
|
|
355
409
|
return @workspace_info unless @workspace_info.nil?
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
elsif @workspace_name.nil?
|
|
369
|
-
nil
|
|
410
|
+
if !public_link.nil?
|
|
411
|
+
Log.log.debug('Using workspace of public link')
|
|
412
|
+
@ws_ids[:id] = public_link['data']['workspace_id']
|
|
413
|
+
elsif !private_link.nil?
|
|
414
|
+
Log.log.debug('Using workspace of private link')
|
|
415
|
+
@ws_ids[:id] = private_link[:workspace_id]
|
|
416
|
+
elsif @ws_ids[:id]
|
|
417
|
+
Log.log.debug("Using workspace id: #{@ws_ids[:id]}")
|
|
418
|
+
elsif default_workspace?
|
|
419
|
+
if current_user_info['default_workspace_id'].nil?
|
|
420
|
+
@ws_ids[:name] = nil
|
|
421
|
+
Log.log.warn('No default workspace')
|
|
370
422
|
else
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
@workspace_info =
|
|
374
|
-
if ws_id.nil?
|
|
375
|
-
{
|
|
376
|
-
name: 'Shared (no workspace)'
|
|
377
|
-
}
|
|
378
|
-
else
|
|
379
|
-
read("workspaces/#{ws_id}").slice('id', 'name', 'home_node_id', 'home_file_id').symbolize_keys
|
|
423
|
+
Log.log.debug('Using default workspace'.green)
|
|
424
|
+
@ws_ids[:id] = current_user_info['default_workspace_id']
|
|
380
425
|
end
|
|
426
|
+
elsif !@ws_ids[:name].nil?
|
|
427
|
+
@workspace_info = lookup_with_q('workspaces', value: @ws_ids[:name])
|
|
428
|
+
end
|
|
429
|
+
@workspace_info = read("workspaces/#{@ws_ids[:id]}") unless @ws_ids[:id].nil?
|
|
430
|
+
@workspace_info ||= {name: 'Shared (no workspace)'}
|
|
431
|
+
@workspace_info = @workspace_info.slice('name', 'id', 'home_node_id', 'home_file_id').symbolize_keys
|
|
381
432
|
Log.dump(:workspace_info, @workspace_info)
|
|
382
433
|
@workspace_info
|
|
383
434
|
end
|
|
@@ -397,10 +448,10 @@ module Aspera
|
|
|
397
448
|
node_id: private_link[:node_id],
|
|
398
449
|
file_id: private_link[:file_id]
|
|
399
450
|
}
|
|
400
|
-
elsif
|
|
451
|
+
elsif workspace_info[:home_node_id] && workspace_info[:home_file_id]
|
|
401
452
|
{
|
|
402
|
-
node_id:
|
|
403
|
-
file_id:
|
|
453
|
+
node_id: workspace_info[:home_node_id],
|
|
454
|
+
file_id: workspace_info[:home_file_id]
|
|
404
455
|
}
|
|
405
456
|
else
|
|
406
457
|
# not part of any workspace, but has some folder shared
|
|
@@ -426,18 +477,7 @@ module Aspera
|
|
|
426
477
|
Aspera.assert_type(node_id, String)
|
|
427
478
|
node_info = read("nodes/#{node_id}")
|
|
428
479
|
workspace_name = read("workspaces/#{workspace_id}")['name'] if workspace_name.nil? && !workspace_id.nil?
|
|
429
|
-
app_info =
|
|
430
|
-
api: self, # for callback
|
|
431
|
-
app: package_info.nil? ? FILES_APP : PACKAGES_APP,
|
|
432
|
-
node_info: node_info,
|
|
433
|
-
workspace_id: workspace_id,
|
|
434
|
-
workspace_name: workspace_name
|
|
435
|
-
}
|
|
436
|
-
if PACKAGES_APP.eql?(app_info[:app])
|
|
437
|
-
Aspera.assert(!package_info.nil?){'package info required'}
|
|
438
|
-
app_info[:package_id] = package_info['id']
|
|
439
|
-
app_info[:package_name] = package_info['name']
|
|
440
|
-
end
|
|
480
|
+
app_info = AppInfo.new(self, package_info, node_info, workspace_id, workspace_name)
|
|
441
481
|
node_params = {base_url: node_info['url']}
|
|
442
482
|
ak_secret = @secret_finder&.lookup_secret(url: node_info['url'], username: node_info['access_key'])
|
|
443
483
|
# If secret is available, or no scope, use basic auth
|
|
@@ -514,7 +554,7 @@ module Aspera
|
|
|
514
554
|
# email: user, else dropbox
|
|
515
555
|
entity_type = short_recipient_info.include?('@') ? 'contacts' : 'dropboxes'
|
|
516
556
|
begin
|
|
517
|
-
full_recipient_info =
|
|
557
|
+
full_recipient_info = lookup_with_q(entity_type, value: short_recipient_info, query: {'workspace_id' => ws_id})
|
|
518
558
|
rescue EntityNotFound
|
|
519
559
|
# dropboxes cannot be created on the fly
|
|
520
560
|
Aspera.assert_values(entity_type, 'contacts', type: Error){"No such shared inbox in workspace #{ws_id}"}
|
|
@@ -609,13 +649,13 @@ module Aspera
|
|
|
609
649
|
transfer_spec.deep_merge!({
|
|
610
650
|
'tags' => {
|
|
611
651
|
Transfer::Spec::TAG_RESERVED => {
|
|
612
|
-
'app' => app_info
|
|
613
|
-
'usage_id' => "aspera.files.workspace.#{app_info
|
|
652
|
+
'app' => app_info.app,
|
|
653
|
+
'usage_id' => "aspera.files.workspace.#{app_info.workspace_id}", # activity tracking
|
|
614
654
|
'files' => {
|
|
615
|
-
'node_id' => app_info
|
|
616
|
-
'files_transfer_action' => "#{transfer_type}_#{app_info
|
|
617
|
-
'workspace_name' => app_info
|
|
618
|
-
'workspace_id' => app_info
|
|
655
|
+
'node_id' => app_info.node_info['id'],
|
|
656
|
+
'files_transfer_action' => "#{transfer_type}_#{app_info.app.gsub(/s$/, '')}",
|
|
657
|
+
'workspace_name' => app_info.workspace_name, # activity tracking
|
|
658
|
+
'workspace_id' => app_info.workspace_id
|
|
619
659
|
}
|
|
620
660
|
}
|
|
621
661
|
}
|
|
@@ -623,30 +663,30 @@ module Aspera
|
|
|
623
663
|
# Console cookie
|
|
624
664
|
################
|
|
625
665
|
# we are sure that fields are not nil
|
|
626
|
-
cookie_elements = [app_info
|
|
666
|
+
cookie_elements = [app_info.app, current_user_info['name'] || 'public link', current_user_info['email'] || 'none'].map{ |e| Base64.strict_encode64(e)}
|
|
627
667
|
cookie_elements.unshift(COOKIE_PREFIX_CONSOLE_AOC)
|
|
628
668
|
transfer_spec['cookie'] = cookie_elements.join(':')
|
|
629
669
|
# Application tags
|
|
630
670
|
##################
|
|
631
|
-
case app_info
|
|
632
|
-
when
|
|
671
|
+
case app_info.app
|
|
672
|
+
when AppType::FILES
|
|
633
673
|
file_id = transfer_spec['tags'][Transfer::Spec::TAG_RESERVED]['node']['file_id']
|
|
634
674
|
transfer_spec.deep_merge!({
|
|
635
675
|
'tags' => {
|
|
636
676
|
Transfer::Spec::TAG_RESERVED => {
|
|
637
677
|
'files' => {
|
|
638
|
-
'parentCwd' => "#{app_info
|
|
678
|
+
'parentCwd' => "#{app_info.node_info['id']}:#{file_id}"
|
|
639
679
|
}
|
|
640
680
|
}
|
|
641
681
|
}
|
|
642
682
|
}) unless transfer_spec.key?('remote_access_key')
|
|
643
|
-
when
|
|
683
|
+
when AppType::PACKAGES
|
|
644
684
|
transfer_spec.deep_merge!({
|
|
645
685
|
'tags' => {
|
|
646
686
|
Transfer::Spec::TAG_RESERVED => {
|
|
647
687
|
'files' => {
|
|
648
|
-
'package_id' => app_info[
|
|
649
|
-
'package_name' => app_info[
|
|
688
|
+
'package_id' => app_info.package['id'],
|
|
689
|
+
'package_name' => app_info.package['name'],
|
|
650
690
|
'package_operation' => transfer_type
|
|
651
691
|
}
|
|
652
692
|
}
|
|
@@ -658,21 +698,21 @@ module Aspera
|
|
|
658
698
|
# Callback from Plugins::Node
|
|
659
699
|
# add application specific tags to permissions creation
|
|
660
700
|
# @param perm_data [Hash] parameters for creating permissions
|
|
661
|
-
# @param app_info [
|
|
701
|
+
# @param app_info [AppInfo] application information
|
|
662
702
|
def permissions_set_create_params(perm_data:, app_info:)
|
|
663
703
|
defaults = {
|
|
664
704
|
'tags' => {
|
|
665
705
|
Transfer::Spec::TAG_RESERVED => {
|
|
666
706
|
'files' => {
|
|
667
707
|
'workspace' => {
|
|
668
|
-
'id' => app_info
|
|
669
|
-
'workspace_name' => app_info
|
|
708
|
+
'id' => app_info.workspace_id,
|
|
709
|
+
'workspace_name' => app_info.workspace_name,
|
|
670
710
|
'user_name' => current_user_info['name'],
|
|
671
711
|
'shared_by_user_id' => current_user_info['id'],
|
|
672
712
|
'shared_by_name' => current_user_info['name'],
|
|
673
713
|
'shared_by_email' => current_user_info['email'],
|
|
674
|
-
'access_key' => app_info
|
|
675
|
-
'node' => app_info
|
|
714
|
+
'access_key' => app_info.node_info['access_key'],
|
|
715
|
+
'node' => app_info.node_info['name']
|
|
676
716
|
}
|
|
677
717
|
}
|
|
678
718
|
}
|
|
@@ -685,10 +725,10 @@ module Aspera
|
|
|
685
725
|
when NilClass
|
|
686
726
|
when ''
|
|
687
727
|
# workspace shared folder
|
|
688
|
-
perm_data.merge!(self.class.workspace_access(app_info
|
|
728
|
+
perm_data.merge!(self.class.workspace_access(app_info.workspace_id))
|
|
689
729
|
tag_workspace['shared_with_name'] = perm_data['access_id']
|
|
690
730
|
else
|
|
691
|
-
entity_info =
|
|
731
|
+
entity_info = lookup_with_q('contacts', value: shared_with, query: {'current_workspace_id' => app_info.workspace_id})
|
|
692
732
|
perm_data['access_type'] = entity_info['source_type']
|
|
693
733
|
perm_data['access_id'] = entity_info['source_id']
|
|
694
734
|
tag_workspace['shared_with_name'] = entity_info['email'] # TODO: check that ???
|
|
@@ -698,26 +738,26 @@ module Aspera
|
|
|
698
738
|
perm_data.delete('as')
|
|
699
739
|
end
|
|
700
740
|
# optional
|
|
701
|
-
app_info
|
|
741
|
+
app_info.opt_link_name = perm_data.delete('link_name')
|
|
702
742
|
end
|
|
703
743
|
|
|
704
744
|
# Callback from Plugins::Node
|
|
705
745
|
# send shared folder event to AoC
|
|
706
746
|
# @param event_data [Hash] response from permission creation
|
|
707
|
-
# @param app_info [
|
|
747
|
+
# @param app_info [AppInfo] hash with app info
|
|
708
748
|
# @param types [Array] event types
|
|
709
749
|
def permissions_send_event(event_data:, app_info:, types: PERMISSIONS_CREATED)
|
|
710
750
|
Aspera.assert_type(types, Array)
|
|
711
751
|
Aspera.assert(!types.empty?)
|
|
712
752
|
event_creation = {
|
|
713
753
|
'types' => types,
|
|
714
|
-
'node_id' => app_info
|
|
715
|
-
'workspace_id' => app_info
|
|
754
|
+
'node_id' => app_info.node_info['id'],
|
|
755
|
+
'workspace_id' => app_info.workspace_id,
|
|
716
756
|
'data' => event_data
|
|
717
757
|
}
|
|
718
758
|
# (optional). The name of the folder to be displayed to the destination user.
|
|
719
759
|
# Use it if its value is different from the "share_as" field.
|
|
720
|
-
event_creation['link_name'] = app_info
|
|
760
|
+
event_creation['link_name'] = app_info.opt_link_name unless app_info.opt_link_name.nil?
|
|
721
761
|
create('events', event_creation, query: {admin: true})
|
|
722
762
|
end
|
|
723
763
|
end
|