aspera-cli 4.27.0 → 4.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +29 -0
  4. data/CONTRIBUTING.md +1 -7
  5. data/TODO.md +50 -0
  6. data/docs/README.md +708 -488
  7. data/lib/aspera/agent/base.rb +10 -2
  8. data/lib/aspera/agent/connect.rb +7 -7
  9. data/lib/aspera/agent/desktop.rb +3 -3
  10. data/lib/aspera/agent/direct.rb +48 -19
  11. data/lib/aspera/agent/factory.rb +3 -3
  12. data/lib/aspera/agent/httpgw.rb +55 -14
  13. data/lib/aspera/agent/node.rb +2 -2
  14. data/lib/aspera/agent/transferd.rb +12 -12
  15. data/lib/aspera/api/aoc.rb +28 -28
  16. data/lib/aspera/api/cos_node.rb +10 -9
  17. data/lib/aspera/api/faspex.rb +2 -2
  18. data/lib/aspera/api/httpgw.rb +20 -20
  19. data/lib/aspera/api/node.rb +31 -53
  20. data/lib/aspera/ascmd.rb +13 -13
  21. data/lib/aspera/ascp/installation.rb +43 -36
  22. data/lib/aspera/ascp/management.rb +6 -6
  23. data/lib/aspera/assert.rb +12 -13
  24. data/lib/aspera/cli/ascp_actions.rb +7 -7
  25. data/lib/aspera/cli/async_transfer_store.rb +49 -5
  26. data/lib/aspera/cli/bootstrapper.rb +9 -9
  27. data/lib/aspera/cli/command_registry.rb +1 -1
  28. data/lib/aspera/cli/command_spec.rb +6 -3
  29. data/lib/aspera/cli/context.rb +3 -3
  30. data/lib/aspera/cli/extended_value.rb +26 -26
  31. data/lib/aspera/cli/formatter.rb +76 -54
  32. data/lib/aspera/cli/gem_checker.rb +1 -1
  33. data/lib/aspera/cli/hints.rb +2 -2
  34. data/lib/aspera/cli/http.rb +22 -29
  35. data/lib/aspera/cli/mailer.rb +7 -7
  36. data/lib/aspera/cli/mcp_tool.rb +31 -4
  37. data/lib/aspera/cli/option_declarator.rb +77 -0
  38. data/lib/aspera/cli/options.schema.yaml +273 -3
  39. data/lib/aspera/cli/parser.rb +539 -280
  40. data/lib/aspera/cli/plugins/alee.rb +1 -1
  41. data/lib/aspera/cli/plugins/aoc.rb +297 -313
  42. data/lib/aspera/cli/plugins/ats.rb +25 -21
  43. data/lib/aspera/cli/plugins/base.rb +357 -186
  44. data/lib/aspera/cli/plugins/basic_auth.rb +0 -12
  45. data/lib/aspera/cli/plugins/config.rb +76 -73
  46. data/lib/aspera/cli/plugins/console.rb +8 -8
  47. data/lib/aspera/cli/plugins/cos.rb +4 -3
  48. data/lib/aspera/cli/plugins/factory.rb +2 -2
  49. data/lib/aspera/cli/plugins/faspex5.rb +259 -248
  50. data/lib/aspera/cli/plugins/faspio.rb +7 -2
  51. data/lib/aspera/cli/plugins/httpgw.rb +1 -1
  52. data/lib/aspera/cli/plugins/mcp.rb +11 -11
  53. data/lib/aspera/cli/plugins/node.rb +227 -283
  54. data/lib/aspera/cli/plugins/orchestrator.rb +23 -23
  55. data/lib/aspera/cli/plugins/preview.rb +61 -64
  56. data/lib/aspera/cli/plugins/server.rb +36 -31
  57. data/lib/aspera/cli/plugins/shares.rb +174 -135
  58. data/lib/aspera/cli/preset_actions.rb +39 -19
  59. data/lib/aspera/cli/preset_manager.rb +74 -32
  60. data/lib/aspera/cli/result.rb +18 -16
  61. data/lib/aspera/cli/runner.rb +75 -39
  62. data/lib/aspera/cli/secret_finder.rb +1 -1
  63. data/lib/aspera/cli/sync_actions.rb +36 -35
  64. data/lib/aspera/cli/terminal_formatter.rb +2 -2
  65. data/lib/aspera/cli/transfer_actions.rb +17 -10
  66. data/lib/aspera/cli/transfer_agent.rb +44 -44
  67. data/lib/aspera/cli/transfer_progress.rb +7 -7
  68. data/lib/aspera/cli/vault_manager.rb +34 -12
  69. data/lib/aspera/cli/version.rb +1 -1
  70. data/lib/aspera/cli/wizard.rb +17 -20
  71. data/lib/aspera/colors.rb +3 -3
  72. data/lib/aspera/command_line_builder.rb +16 -16
  73. data/lib/aspera/command_line_converter.rb +1 -1
  74. data/lib/aspera/coverage.rb +1 -2
  75. data/lib/aspera/data_repository.rb +1 -1
  76. data/lib/aspera/dot_container.rb +8 -8
  77. data/lib/aspera/environment.rb +12 -12
  78. data/lib/aspera/faspex_gw.rb +4 -4
  79. data/lib/aspera/faspex_postproc.rb +14 -9
  80. data/lib/aspera/graphql.rb +4 -2
  81. data/lib/aspera/hash_ext.rb +2 -2
  82. data/lib/aspera/json_rpc/client.rb +1 -1
  83. data/lib/aspera/keychain/base.rb +10 -3
  84. data/lib/aspera/keychain/encrypted_hash.rb +92 -17
  85. data/lib/aspera/keychain/factory.rb +17 -5
  86. data/lib/aspera/keychain/hashicorp_vault.rb +1 -1
  87. data/lib/aspera/keychain/macos_security.rb +23 -25
  88. data/lib/aspera/keychain/one_password_api.rb +86 -0
  89. data/lib/aspera/keychain/one_password_base.rb +34 -0
  90. data/lib/aspera/keychain/one_password_cli.rb +98 -0
  91. data/lib/aspera/link_header.rb +2 -2
  92. data/lib/aspera/log.rb +13 -13
  93. data/lib/aspera/markdown.rb +5 -5
  94. data/lib/aspera/nagios.rb +8 -8
  95. data/lib/aspera/node_simulator.rb +33 -27
  96. data/lib/aspera/oauth/base.rb +4 -5
  97. data/lib/aspera/oauth/boot.rb +3 -3
  98. data/lib/aspera/oauth/factory.rb +5 -5
  99. data/lib/aspera/oauth/jwt.rb +5 -7
  100. data/lib/aspera/oauth/web.rb +4 -4
  101. data/lib/aspera/persistency_action_once.rb +4 -4
  102. data/lib/aspera/persistency_folder.rb +8 -8
  103. data/lib/aspera/preview/file_types.rb +4 -4
  104. data/lib/aspera/preview/generator.rb +49 -46
  105. data/lib/aspera/preview/options.rb +3 -2
  106. data/lib/aspera/preview/terminal.rb +5 -5
  107. data/lib/aspera/preview/utils.rb +65 -18
  108. data/lib/aspera/products/connect.rb +2 -2
  109. data/lib/aspera/products/desktop.rb +1 -1
  110. data/lib/aspera/products/other.rb +2 -2
  111. data/lib/aspera/products/transferd.rb +3 -3
  112. data/lib/aspera/proxy_auto_config.rb +10 -10
  113. data/lib/aspera/rest.rb +149 -115
  114. data/lib/aspera/rest_error_analyzer.rb +3 -3
  115. data/lib/aspera/rest_list.rb +10 -9
  116. data/lib/aspera/schema/IBM Aspera Node API-4.4.6.yaml +6232 -0
  117. data/lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0.yaml +249 -0
  118. data/lib/aspera/schema/IBM_Aspera_Shares.yaml +4653 -0
  119. data/lib/aspera/schema/documentation.rb +17 -11
  120. data/lib/aspera/schema/reader.rb +78 -4
  121. data/lib/aspera/schema/registry.rb +26 -7
  122. data/lib/aspera/secret_hider.rb +5 -5
  123. data/lib/aspera/ssh.rb +64 -31
  124. data/lib/aspera/ssl.rb +3 -3
  125. data/lib/aspera/sync/database.rb +2 -2
  126. data/lib/aspera/sync/operations.rb +13 -13
  127. data/lib/aspera/temp_file_manager.rb +24 -4
  128. data/lib/aspera/transfer/faux_file.rb +2 -2
  129. data/lib/aspera/transfer/parameters.rb +15 -15
  130. data/lib/aspera/transfer/resumer.rb +9 -9
  131. data/lib/aspera/transfer/spec.rb +1 -1
  132. data/lib/aspera/uri_reader.rb +52 -15
  133. data/lib/aspera/web_auth.rb +6 -5
  134. data/lib/aspera/web_server_simple.rb +9 -9
  135. data/lib/aspera/yaml.rb +4 -4
  136. data.tar.gz.sig +0 -0
  137. metadata +10 -4
  138. metadata.gz.sig +0 -0
  139. data/lib/aspera/cli/plugins/faspex.rb +0 -576
  140. data/lib/aspera/transfer/uri.rb +0 -56
@@ -21,9 +21,9 @@ module Aspera
21
21
  def create(name)
22
22
  return unless name.start_with?(PREFIX)
23
23
  name_params = name.delete_prefix(PREFIX).split('?', 2)
24
- Aspera.assert(name_params.length.eql?(2), type: Error){"Format: #{PREFIX}<file path>?<size>"}
24
+ Aspera.assert(name_params.length.eql?(2), type: Error) { "Format: #{PREFIX}<file path>?<size>" }
25
25
  m = name_params[1].downcase.match(/^(\d+)([#{SIZE_UNITS.join('')}]?)$/)
26
- Aspera.assert(m, type: Error){"Format: <integer>[#{SIZE_UNITS.join(',')}]"}
26
+ Aspera.assert(m, type: Error) { "Format: <integer>[#{SIZE_UNITS.join(',')}]" }
27
27
  size = m[2].empty? ? m[1].to_i : m[1].to_i * (1024**(SIZE_UNITS.index(m[2]) + 1))
28
28
  return FauxFile.new(name_params[0], size)
29
29
  end
@@ -36,14 +36,14 @@ module Aspera
36
36
  # because of garbage collection takes any file there
37
37
  # this could be refined, as, for example, on macos, temp folder is already user specific
38
38
  def file_list_folder
39
- @file_list_folder ||= TempFileManager.instance.new_file_path_global('asession_filelists')
39
+ @file_list_folder ||= TempFileManager.instance.new_dir_path_global('asession_filelists')
40
40
  end
41
41
 
42
42
  # Check whether a file list option is already present in the `ascp` argument list
43
43
  # @param ascp_args [Array, nil] `ascp` arguments
44
44
  # @return [Boolean] true if a file list option is present
45
45
  def ascp_args_file_list?(ascp_args)
46
- ascp_args&.any?{ |i| FILE_LIST_OPTIONS.include?(i)}
46
+ ascp_args&.any? { |i| FILE_LIST_OPTIONS.include?(i) }
47
47
  end
48
48
  end
49
49
 
@@ -68,12 +68,12 @@ module Aspera
68
68
  @job_spec = job_spec
69
69
  Aspera.assert_type(@job_spec, Hash)
70
70
  @ascp_args = ascp_args.nil? ? [] : ascp_args
71
- Aspera.assert_array_all(@ascp_args, String){'ascp_args'}
71
+ Aspera.assert_array_all(@ascp_args, String) { 'ascp_args' }
72
72
  @wss = wss
73
73
  @quiet = quiet
74
74
  @file_list = file_list
75
75
  @trusted_certs = trusted_certs.nil? ? [] : trusted_certs
76
- Aspera.assert_type(@trusted_certs, Array){'trusted_certs'}
76
+ Aspera.assert_type(@trusted_certs, Array) { 'trusted_certs' }
77
77
  @client_ssh_key = client_ssh_key.nil? ? :rsa : client_ssh_key.to_sym
78
78
  Aspera.assert_values(@client_ssh_key, Ascp::Installation::CLIENT_SSH_KEY_OPTIONS)
79
79
  @check_ignore_cb = check_ignore_cb
@@ -92,27 +92,27 @@ module Aspera
92
92
  # transfer spec contains paths ?
93
93
  if !ts_paths_array.nil?
94
94
  Aspera.assert(!ascp_file_list_provided, 'file list provided both in transfer spec and ascp file list. Remove one of them.')
95
- Aspera.assert(ts_paths_array.all?{ |i| i.key?('source')}, "All elements of paths must have a 'source' key")
96
- is_pair_list = ts_paths_array.any?{ |i| i.key?('destination')}
97
- Aspera.assert(!(is_pair_list && !ts_paths_array.all?{ |i| i.key?('destination')})){"All elements of paths must be consistent with 'destination' key"}
95
+ Aspera.assert(ts_paths_array.all? { |i| i.key?('source') }, "All elements of paths must have a 'source' key")
96
+ is_pair_list = ts_paths_array.any? { |i| i.key?('destination') }
97
+ Aspera.assert(!(is_pair_list && !ts_paths_array.all? { |i| i.key?('destination') })) { "All elements of paths must be consistent with 'destination' key" }
98
98
  if !@file_list || self.class.file_list_folder.nil?
99
99
  Aspera.assert(!is_pair_list, 'file pair list is not supported when file list folder is not set')
100
100
  # not safe for special characters ? (maybe not, depends on OS)
101
101
  Log.log.debug('placing source file list on command line (no file list file)')
102
- @builder.add_command_line_options(ts_paths_array.map{ |i| i['source']})
102
+ @builder.add_command_line_options(ts_paths_array.map { |i| i['source'] })
103
103
  else
104
104
  # safer option: generate a file list file if there is storage defined for it
105
105
  if is_pair_list
106
106
  file_list_option = '--file-pair-list'
107
- lines = ts_paths_array.each_with_object([]){ |e, m| m.push(e['source'], e['destination'])}
107
+ lines = ts_paths_array.each_with_object([]) { |e, m| m.push(e['source'], e['destination']) }
108
108
  else
109
109
  file_list_option = '--file-list'
110
- lines = ts_paths_array.map{ |i| i['source']}
110
+ lines = ts_paths_array.map { |i| i['source'] }
111
111
  end
112
112
  file_list_file = TempFileManager.instance.new_file_path_in_folder(self.class.file_list_folder)
113
113
  Log.dump(:file_list, lines)
114
114
  File.write(file_list_file, lines.join("\n"), encoding: 'UTF-8')
115
- Log.log.debug{"#{file_list_option}=\n#{File.read(file_list_file)}".red}
115
+ Log.log.debug { "#{file_list_option}=\n#{File.read(file_list_file)}".red }
116
116
  end
117
117
  end
118
118
  @builder.add_command_line_options("#{file_list_option}=#{file_list_file}") unless file_list_option.nil?
@@ -172,11 +172,11 @@ module Aspera
172
172
 
173
173
  case (delete_source = @builder.read_param('delete_source'))
174
174
  when true
175
- DELETE_EQUIV.each{ |i| @job_spec[i] = true}
175
+ DELETE_EQUIV.each { |i| @job_spec[i] = true }
176
176
  when false
177
- DELETE_EQUIV.each{ |i| @job_spec.delete(i)}
177
+ DELETE_EQUIV.each { |i| @job_spec.delete(i) }
178
178
  when nil
179
- else Aspera.error_unexpected_value(delete_source){'delete_source'}
179
+ else Aspera.error_unexpected_value(delete_source) { 'delete_source' }
180
180
  end
181
181
 
182
182
  # process parameters as specified in table
@@ -211,7 +211,7 @@ module Aspera
211
211
  end
212
212
  # disable redis in client, only for ascp, this makes ascp4 fail
213
213
  exec_spec.env['ASPERA_TEST_REDIS_DISABLE'] = 'true' if exec_spec.exec.eql?(:ascp)
214
- Log.log.debug{"ascp args: #{exec_spec}"}
214
+ Log.log.debug { "ascp args: #{exec_spec}" }
215
215
  return exec_spec
216
216
  end
217
217
  DELETE_EQUIV = %w[remove_after_transfer remove_empty_directories remove_empty_source_directory]
@@ -19,13 +19,13 @@ module Aspera
19
19
  sleep_factor: 2,
20
20
  sleep_max: 60
21
21
  )
22
- Aspera.assert_type(iter_max, Integer){'iter_max'}
22
+ Aspera.assert_type(iter_max, Integer) { 'iter_max' }
23
23
  @iter_max = iter_max
24
- Aspera.assert_type(sleep_initial, Integer){'sleep_initial'}
24
+ Aspera.assert_type(sleep_initial, Integer) { 'sleep_initial' }
25
25
  @sleep_initial = sleep_initial
26
- Aspera.assert_type(sleep_factor, Integer){'sleep_factor'}
26
+ Aspera.assert_type(sleep_factor, Integer) { 'sleep_factor' }
27
27
  @sleep_factor = sleep_factor
28
- Aspera.assert_type(sleep_max, Integer){'sleep_max'}
28
+ Aspera.assert_type(sleep_max, Integer) { 'sleep_max' }
29
29
  @sleep_max = sleep_max
30
30
  end
31
31
 
@@ -38,7 +38,7 @@ module Aspera
38
38
  # maximum of retry
39
39
  remaining_resumes = @iter_max
40
40
  sleep_seconds = @sleep_initial
41
- Log.log.debug{"retries=#{remaining_resumes}"}
41
+ Log.log.debug { "retries=#{remaining_resumes}" }
42
42
  # try to send the file until ascp is successful
43
43
  loop do
44
44
  Log.log.debug('Starting task execution')
@@ -48,17 +48,17 @@ module Aspera
48
48
  # Exit retry loop if success
49
49
  break
50
50
  rescue Error => e
51
- Log.log.warn{"An error occurred during task: #{e.message}"}
52
- Log.log.debug{"Retryable ? #{e.retryable?}"}
51
+ Log.log.warn { "An error occurred during task: #{e.message}" }
52
+ Log.log.debug { "Retryable ? #{e.retryable?}" }
53
53
  # do not retry non-retryable
54
54
  raise unless e.retryable?
55
55
  # exit if we exceed the max number of retry
56
- Aspera.assert(remaining_resumes > 0, type: Error){"Maximum number of retry reached: #{@iter_max}"}
56
+ Aspera.assert(remaining_resumes > 0, type: Error) { "Maximum number of retry reached: #{@iter_max}" }
57
57
  end
58
58
 
59
59
  # take this retry in account
60
60
  remaining_resumes -= 1
61
- Log.log.warn{"Resuming in #{sleep_seconds} seconds (retry left:#{remaining_resumes})"}
61
+ Log.log.warn { "Resuming in #{sleep_seconds} seconds (retry left:#{remaining_resumes})" }
62
62
 
63
63
  # wait a bit before retrying, maybe network condition will be better
64
64
  sleep(sleep_seconds)
@@ -57,7 +57,7 @@ module Aspera
57
57
  # @return [Integer] value in kbps
58
58
  def rate_string_to_kbps(value)
59
59
  m = value.to_s.strip.match(/\A(\d+)([kKmMgG])?\z/)
60
- Aspera.assert(m){"Invalid rate value: #{value.inspect}. Expected integer with optional suffix k/K, m/M or g/G."}
60
+ Aspera.assert(m) { "Invalid rate value: #{value.inspect}. Expected integer with optional suffix k/K, m/M or g/G." }
61
61
  multiplier = m[2] ? RATE_SUFFIX_KBPS.fetch(m[2].downcase) : 1
62
62
  return m[1].to_i * multiplier
63
63
  end
@@ -7,31 +7,66 @@ require 'aspera/rest'
7
7
  require 'aspera/temp_file_manager'
8
8
 
9
9
  module Aspera
10
- # Read some content from some URI, support file: , http: and https: schemes
10
+ # Read content from a URI; supported schemes: file:, http:, https:, data:
11
+ #
12
+ # == file: URL convention
13
+ # Two equivalent forms are accepted:
14
+ #
15
+ # file:///relative/path -> relative path "relative/path"
16
+ # file:////absolute/path -> absolute path "/absolute/path"
17
+ #
18
+ # A shorter form is also accepted (no authority component):
19
+ #
20
+ # file:relative/path -> relative path "relative/path"
21
+ # file:/absolute/path -> absolute path "/absolute/path"
22
+ #
23
+ # The short form is consistent with RFC 8089 (file:///<path> = absolute,
24
+ # file:<path> = relative). Both forms are handled identically by this module.
25
+ # The canonical form built by {file_url} uses the +file:///+ prefix.
11
26
  module UriReader
12
27
  SCHEME_FILE = 'file'
13
28
  SCHEME_FILE_PFX1 = "#{SCHEME_FILE}:"
29
+ # Canonical prefix for file: URLs (no host, three slashes).
30
+ # What follows is the literal path: relative or absolute (starting with a second slash).
14
31
  SCHEME_FILE_PFX2 = "#{SCHEME_FILE_PFX1}///"
15
32
  private_constant :SCHEME_FILE, :SCHEME_FILE_PFX1, :SCHEME_FILE_PFX2
16
33
  class << self
17
- # @return [Boolean] true if the URL is a file:// URL
34
+ # @return [Boolean] true if +url+ uses the file: scheme recognised by this module
18
35
  def file?(url)
19
- url.start_with?(SCHEME_FILE_PFX2)
36
+ url.start_with?(SCHEME_FILE_PFX1)
20
37
  end
21
38
 
22
- # @return [String] a file:// URL for the given path
39
+ # Build a file: URL from +path+.
40
+ # A relative path yields +file:///path+; an absolute path yields +file:////path+.
41
+ # @param path [String] relative or absolute file-system path
42
+ # @return [String] corresponding file: URL
23
43
  def file_url(path)
24
44
  return "#{SCHEME_FILE_PFX2}#{path}"
25
45
  end
26
46
 
27
- # @return [String] the path of a file:// URL
47
+ # Extract the file-system path from a file: URL.
48
+ # Accepts both the canonical +file:///+ form and the short +file:+ form.
49
+ # Returns the literal path (relative or absolute) without working-directory expansion.
50
+ # @param url [String] a file: URL (canonical or short form)
51
+ # @return [String] the literal path encoded in the URL
28
52
  def file_path(url)
29
- Aspera.assert(file?(url)){"use format: #{file_url('<path>')}"}
30
- File.expand_path(url.delete_prefix(SCHEME_FILE_PFX2))
53
+ Aspera.assert(file?(url)) { "use format: #{file_url('<path>')}" }
54
+ # Strip canonical prefix "file:///" first (covers relative and absolute canonical forms).
55
+ # If absent, strip only the short "file:" prefix.
56
+ return url.start_with?(SCHEME_FILE_PFX2) ? url.delete_prefix(SCHEME_FILE_PFX2) : url.delete_prefix(SCHEME_FILE_PFX1)
31
57
  end
32
58
 
33
- # Read some content from some URI, support file: , http: and https: schemes
59
+ # Read content from a URI and return it as a String.
60
+ # Supported schemes: +http+, +https+, +data+, +file+, and bare paths (no scheme).
61
+ # For file: URLs the path is extracted via {file_path} to respect the module convention
62
+ # (see module-level documentation). Ruby's URI parser is not used for file: URLs because
63
+ # it interprets the three-slash prefix differently (it always produces an absolute path).
64
+ # Bare paths (no scheme) are passed to File.read directly; leading +/~/+, +/./+, +/../+
65
+ # are expanded via +File.expand_path+ after stripping the synthetic leading slash added by
66
+ # URI.
34
67
  def read(uri_to_read)
68
+ # Handle file: URLs directly to honour the file:///relative vs file:////absolute convention.
69
+ return File.read(file_path(uri_to_read)) if file?(uri_to_read)
35
70
  uri = URI.parse(uri_to_read)
36
71
  case uri.scheme
37
72
  when 'http', 'https'
@@ -43,20 +78,22 @@ module Aspera
43
78
  else
44
79
  URI.decode_www_form_component(encoded_data)
45
80
  end
46
- when SCHEME_FILE, NilClass
81
+ when NilClass
47
82
  local_file_path = uri.path
48
- Aspera.assert(!local_file_path.nil?, type: Error){'URL shall have a path, check syntax'}
83
+ Aspera.assert(!local_file_path.nil?, type: Error) { 'URL shall have a path, check syntax' }
49
84
  local_file_path = File.expand_path(local_file_path.gsub(%r{^/}, '')) if %r{^/(~|.|..)/}.match?(local_file_path)
50
85
  return File.read(local_file_path)
51
- else Aspera.error_unexpected_value(uri.scheme){"scheme for [#{uri_to_read}]"}
86
+ else Aspera.error_unexpected_value(uri.scheme) { "scheme for [#{uri_to_read}]" }
52
87
  end
53
88
  end
54
89
 
55
- # @return [String] path to file with content at URL
90
+ # Return the local file-system path for the content at +url+, downloading to a temp file if needed.
91
+ # For file: URLs the path is extracted directly (no download).
92
+ # For data: and http(s): URLs the content is written to a temporary file and its path is returned.
93
+ # @return [String] local path to a file containing the URL content
56
94
  def read_as_file(url)
57
95
  if url.start_with?(SCHEME_FILE_PFX1)
58
- # for file scheme, return directly the path
59
- # require specific file scheme: the path part is "relative", or absolute if there are 4 slash
96
+ # file: scheme: extract the literal path encoded in the URL (relative or absolute).
60
97
  return file_path(url)
61
98
  elsif url.start_with?('data:')
62
99
  # download to temp file
@@ -68,7 +105,7 @@ module Aspera
68
105
  # download to temp file
69
106
  # auto-delete on exit
70
107
  temp_file = TempFileManager.instance.new_file_path_global(suffix: File.basename(url))
71
- Aspera::Rest.new(base_url: url, redirect_max: 3).call(operation: 'GET', save_to_file: temp_file)
108
+ Aspera::Rest.new(base_url: url, redirect_max: 3).call(operation: 'GET', save_to: temp_file)
72
109
  return temp_file
73
110
  end
74
111
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'aspera/web_server_simple'
4
4
  require 'aspera/assert'
5
+ require 'erb'
5
6
 
6
7
  module Aspera
7
8
  # servlet called on callback: it records the callback request
@@ -15,8 +16,8 @@ module Aspera
15
16
  end
16
17
 
17
18
  def service(request, response)
18
- Log.log.debug{"received request from browser #{request.request_method} #{request.path}"}
19
- Aspera.assert_values(request.request_method, ['GET'], type: WEBrick::HTTPStatus::MethodNotAllowed){'HTTP verb'}
19
+ Log.log.debug { "received request from browser #{request.request_method} #{request.path}" }
20
+ Aspera.assert_values(request.request_method, ['GET'], type: WEBrick::HTTPStatus::MethodNotAllowed) { 'HTTP verb' }
20
21
  additional_info = @web_auth.signal_request(request)
21
22
  response.status = 200
22
23
  response.content_type = 'text/html'
@@ -91,7 +92,7 @@ module Aspera
91
92
  <body>
92
93
  <h1>Thank You!</h1>
93
94
  <p>You can close this window.</p>
94
- <p>#{additional_info}</p>
95
+ <p>#{ERB::Util.html_escape(additional_info) unless additional_info.nil?}</p>
95
96
 
96
97
  <!-- JavaScript to generate IBM logos -->
97
98
  <script>
@@ -182,7 +183,7 @@ module Aspera
182
183
  # last argument (self) is provided to constructor of servlet
183
184
  mount(@expected_path, WebAuthServlet, self)
184
185
  # server runs in thread
185
- Thread.new{start}
186
+ Thread.new { start }
186
187
  end
187
188
 
188
189
  # Called by web server thread on received request
@@ -201,7 +202,7 @@ module Aspera
201
202
  # @return [Hash] the query
202
203
  def received_request
203
204
  # wait for signal from thread
204
- @mutex.synchronize{@cond.wait(@mutex)}
205
+ @mutex.synchronize { @cond.wait(@mutex) }
205
206
  # tell server thread to stop
206
207
  shutdown
207
208
  return @query
@@ -12,7 +12,7 @@ module Aspera
12
12
  DEFAULT_URL = 'http://localhost:8080'
13
13
  GENERIC_ISSUER = '/C=FR/O=Test/OU=Test/CN=Test'
14
14
  ONE_YEAR_SECONDS = 365 * 24 * 60 * 60
15
- PKCS12_EXT = %w[p12 pfx].map{ |i| ".#{i}"}.freeze
15
+ PKCS12_EXT = %w[p12 pfx].map { |i| ".#{i}" }.freeze
16
16
  CLOCK_SKEW_OFFSET_SEC = 5
17
17
 
18
18
  private_constant :GENERIC_ISSUER, :ONE_YEAR_SECONDS, :PKCS12_EXT, :CLOCK_SKEW_OFFSET_SEC
@@ -42,7 +42,7 @@ module Aspera
42
42
 
43
43
  # @return [Array<OpenSSL::X509::Certificate>] list of Certificates from chain file
44
44
  def read_chain_file(chain)
45
- File.read(chain).scan(/-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/m).map{ |i| OpenSSL::X509::Certificate.new(i)}
45
+ File.read(chain).scan(/-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/m).map { |i| OpenSSL::X509::Certificate.new(i) }
46
46
  end
47
47
  end
48
48
 
@@ -75,7 +75,7 @@ module Aspera
75
75
  elsif cert && PKCS12_EXT.include?(File.extname(cert).downcase)
76
76
  # PKCS12
77
77
  Log.log.debug('Using PKCS12 certificate')
78
- Aspera.assert(!key.nil?, type: Error){'PKCS12 requires a key (password)'}
78
+ Aspera.assert(!key.nil?, type: Error) { 'PKCS12 requires a key (password)' }
79
79
  pkcs12 = OpenSSL::PKCS12.new(File.read(cert), key)
80
80
  webrick_options[:SSLCertificate] = pkcs12.certificate
81
81
  webrick_options[:SSLPrivateKey] = pkcs12.key
@@ -93,27 +93,27 @@ module Aspera
93
93
  OpenSSL::X509::Certificate.new(File.read(cert))
94
94
  end
95
95
  webrick_options[:SSLExtraChainCert] = read_chain_file(chain) unless chain.nil?
96
- Aspera.assert(webrick_options[:SSLCertificate].public_key.to_der == webrick_options[:SSLPrivateKey].public_key.to_der, type: Error){'key and cert do not match'}
96
+ Aspera.assert(webrick_options[:SSLCertificate].public_key.to_der == webrick_options[:SSLPrivateKey].public_key.to_der, type: Error) { 'key and cert do not match' }
97
97
  end
98
98
  end
99
99
  # call constructor of parent class, but capture STDERR
100
100
  # self signed certificate generates characters on STDERR
101
101
  # see create_self_signed_cert in webrick/ssl.rb
102
- Log.capture_stderr{super(webrick_options)}
102
+ Log.capture_stderr { super(webrick_options) }
103
103
  end
104
104
 
105
105
  # blocking
106
106
  def start
107
- Log.log.info{"Listening on #{@uri}"}
107
+ Log.log.info { "Listening on #{@uri}" }
108
108
  # kill (-TERM) for graceful shutdown
109
- handler = proc{shutdown}
110
- %i{INT TERM}.each{ |sig| trap(sig, &handler)}
109
+ handler = proc { shutdown }
110
+ %i{INT TERM}.each { |sig| trap(sig, &handler) }
111
111
  super
112
112
  end
113
113
 
114
114
  # log web server access ( option AccessLog )
115
115
  def <<(access_log)
116
- Log.log.debug{"webrick log #{access_log.chomp}"}
116
+ Log.log.debug { "webrick log #{access_log.chomp}" }
117
117
  end
118
118
  end
119
119
  end
data/lib/aspera/yaml.rb CHANGED
@@ -15,7 +15,7 @@ module Aspera
15
15
  return duplicate_keys unless node.respond_to?(:children)
16
16
  if node.is_a?(Psych::Nodes::Mapping)
17
17
  counts = Hash.new(0)
18
- key_nodes = Hash.new{ |h, k| h[k] = []}
18
+ key_nodes = Hash.new { |h, k| h[k] = [] }
19
19
  node.children.each_slice(2) do |key_node, value_node|
20
20
  if key_node&.value
21
21
  counts[key_node.value] += 1
@@ -26,11 +26,11 @@ module Aspera
26
26
  counts.each do |key_str, count|
27
27
  next if count <= 1
28
28
  path = (parent_path + [key_str]).join('.')
29
- occurrences = key_nodes[key_str].map{ |kn| kn.start_line ? kn.start_line + 1 : 'unknown'}.join(', ')
29
+ occurrences = key_nodes[key_str].map { |kn| kn.start_line ? kn.start_line + 1 : 'unknown' }.join(', ')
30
30
  duplicate_keys << "#{path}: #{occurrences}"
31
31
  end
32
32
  else
33
- node.children.to_a.each{ |child| find_duplicate_keys(child, parent_path, duplicate_keys)}
33
+ node.children.to_a.each { |child| find_duplicate_keys(child, parent_path, duplicate_keys) }
34
34
  end
35
35
  duplicate_keys
36
36
  end
@@ -43,7 +43,7 @@ module Aspera
43
43
  # @raise [RuntimeError] If duplicate keys are found
44
44
  def safe_load(yaml)
45
45
  duplicate_keys = find_duplicate_keys(Psych.parse_stream(yaml))
46
- Aspera.assert(duplicate_keys.empty?){"Duplicate keys: #{duplicate_keys.join('; ')}"}
46
+ Aspera.assert(duplicate_keys.empty?) { "Duplicate keys: #{duplicate_keys.join('; ')}" }
47
47
  YAML.safe_load(yaml, permitted_classes: [Time, Date, Symbol])
48
48
  end
49
49
 
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aspera-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.27.0
4
+ version: 4.27.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent Martin
@@ -317,6 +317,7 @@ files:
317
317
  - CHANGELOG.md
318
318
  - CONTRIBUTING.md
319
319
  - README.md
320
+ - TODO.md
320
321
  - bin/ascli
321
322
  - bin/asession
322
323
  - docs/README.md
@@ -357,6 +358,7 @@ files:
357
358
  - lib/aspera/cli/info.rb
358
359
  - lib/aspera/cli/mailer.rb
359
360
  - lib/aspera/cli/mcp_tool.rb
361
+ - lib/aspera/cli/option_declarator.rb
360
362
  - lib/aspera/cli/options.schema.yaml
361
363
  - lib/aspera/cli/parser.rb
362
364
  - lib/aspera/cli/plugins/alee.rb
@@ -368,7 +370,6 @@ files:
368
370
  - lib/aspera/cli/plugins/console.rb
369
371
  - lib/aspera/cli/plugins/cos.rb
370
372
  - lib/aspera/cli/plugins/factory.rb
371
- - lib/aspera/cli/plugins/faspex.rb
372
373
  - lib/aspera/cli/plugins/faspex5.rb
373
374
  - lib/aspera/cli/plugins/faspio.rb
374
375
  - lib/aspera/cli/plugins/httpgw.rb
@@ -420,6 +421,9 @@ files:
420
421
  - lib/aspera/keychain/factory.rb
421
422
  - lib/aspera/keychain/hashicorp_vault.rb
422
423
  - lib/aspera/keychain/macos_security.rb
424
+ - lib/aspera/keychain/one_password_api.rb
425
+ - lib/aspera/keychain/one_password_base.rb
426
+ - lib/aspera/keychain/one_password_cli.rb
423
427
  - lib/aspera/line_logger.rb
424
428
  - lib/aspera/link_header.rb
425
429
  - lib/aspera/log.rb
@@ -455,7 +459,10 @@ files:
455
459
  - lib/aspera/rest_errors_aspera.rb
456
460
  - lib/aspera/rest_list.rb
457
461
  - lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml
462
+ - lib/aspera/schema/IBM Aspera Node API-4.4.6.yaml
463
+ - lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0.yaml
458
464
  - lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml
465
+ - lib/aspera/schema/IBM_Aspera_Shares.yaml
459
466
  - lib/aspera/schema/async_tables.yaml
460
467
  - lib/aspera/schema/documentation.rb
461
468
  - lib/aspera/schema/reader.rb
@@ -476,7 +483,6 @@ files:
476
483
  - lib/aspera/transfer/resumer.rb
477
484
  - lib/aspera/transfer/spec.rb
478
485
  - lib/aspera/transfer/spec.schema.yaml
479
- - lib/aspera/transfer/uri.rb
480
486
  - lib/aspera/uri_reader.rb
481
487
  - lib/aspera/web_auth.rb
482
488
  - lib/aspera/web_server_simple.rb
@@ -508,7 +514,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
508
514
  version: '0'
509
515
  requirements:
510
516
  - Read the manual for any requirement
511
- rubygems_version: 4.0.16
517
+ rubygems_version: 4.0.20
512
518
  specification_version: 4
513
519
  summary: 'Execute actions using command line on IBM Aspera Server products: Aspera
514
520
  on Cloud, Faspex, Shares, Node, Console, Orchestrator, High Speed Transfer Server'
metadata.gz.sig CHANGED
Binary file