aspera-cli 4.24.0 → 4.24.2
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 +19 -1
 - data/README.md +1264 -941
 - data/bin/ascli +20 -1
 - data/bin/asession +23 -27
 - data/lib/aspera/agent/base.rb +10 -21
 - data/lib/aspera/agent/connect.rb +2 -3
 - data/lib/aspera/agent/desktop.rb +2 -2
 - data/lib/aspera/agent/direct.rb +49 -32
 - data/lib/aspera/agent/factory.rb +31 -0
 - data/lib/aspera/api/aoc.rb +79 -49
 - data/lib/aspera/api/faspex.rb +212 -0
 - data/lib/aspera/api/node.rb +99 -84
 - data/lib/aspera/ascp/installation.rb +22 -21
 - data/lib/aspera/ascp/management.rb +119 -23
 - data/lib/aspera/assert.rb +14 -8
 - data/lib/aspera/cli/extended_value.rb +15 -15
 - data/lib/aspera/cli/formatter.rb +7 -5
 - data/lib/aspera/cli/hints.rb +8 -0
 - data/lib/aspera/cli/info.rb +4 -4
 - data/lib/aspera/cli/main.rb +56 -71
 - data/lib/aspera/cli/manager.rb +7 -4
 - data/lib/aspera/cli/plugins/alee.rb +2 -1
 - data/lib/aspera/cli/plugins/aoc.rb +110 -186
 - data/lib/aspera/cli/plugins/ats.rb +4 -4
 - data/lib/aspera/cli/plugins/base.rb +335 -0
 - data/lib/aspera/cli/plugins/basic_auth.rb +45 -0
 - data/lib/aspera/cli/plugins/config.rb +263 -221
 - data/lib/aspera/cli/plugins/console.rb +15 -15
 - data/lib/aspera/cli/plugins/cos.rb +2 -2
 - data/lib/aspera/cli/plugins/factory.rb +78 -0
 - data/lib/aspera/cli/plugins/faspex.rb +17 -20
 - data/lib/aspera/cli/plugins/faspex5.rb +79 -193
 - data/lib/aspera/cli/plugins/faspio.rb +14 -13
 - data/lib/aspera/cli/plugins/httpgw.rb +13 -12
 - data/lib/aspera/cli/plugins/node.rb +34 -32
 - data/lib/aspera/cli/plugins/oauth.rb +48 -0
 - data/lib/aspera/cli/plugins/orchestrator.rb +15 -13
 - data/lib/aspera/cli/plugins/preview.rb +4 -4
 - data/lib/aspera/cli/plugins/server.rb +15 -13
 - data/lib/aspera/cli/plugins/shares.rb +18 -15
 - data/lib/aspera/cli/sync_actions.rb +1 -1
 - data/lib/aspera/cli/transfer_agent.rb +24 -20
 - data/lib/aspera/cli/transfer_progress.rb +6 -6
 - data/lib/aspera/cli/version.rb +3 -3
 - data/lib/aspera/cli/wizard.rb +74 -65
 - data/lib/aspera/colors.rb +6 -0
 - data/lib/aspera/command_line_builder.rb +45 -50
 - data/lib/aspera/command_line_converter.rb +2 -1
 - data/lib/aspera/coverage.rb +1 -1
 - data/lib/aspera/data_repository.rb +1 -1
 - data/lib/aspera/environment.rb +13 -9
 - data/lib/aspera/faspex_gw.rb +6 -4
 - data/lib/aspera/faspex_postproc.rb +1 -1
 - data/lib/aspera/keychain/macos_security.rb +1 -1
 - data/lib/aspera/log.rb +88 -37
 - data/lib/aspera/nagios.rb +1 -1
 - data/lib/aspera/oauth/base.rb +17 -10
 - data/lib/aspera/oauth/factory.rb +8 -8
 - data/lib/aspera/oauth/web.rb +2 -2
 - data/lib/aspera/products/connect.rb +4 -3
 - data/lib/aspera/products/desktop.rb +1 -4
 - data/lib/aspera/products/other.rb +9 -1
 - data/lib/aspera/products/transferd.rb +0 -1
 - data/lib/aspera/rest.rb +126 -83
 - data/lib/aspera/ssh.rb +3 -3
 - data/lib/aspera/sync/args.schema.yaml +46 -3
 - data/lib/aspera/sync/conf.schema.yaml +130 -94
 - data/lib/aspera/sync/operations.rb +71 -74
 - data/lib/aspera/temp_file_manager.rb +17 -5
 - data/lib/aspera/transfer/error.rb +16 -7
 - data/lib/aspera/transfer/parameters.rb +34 -20
 - data/lib/aspera/transfer/resumer.rb +74 -0
 - data/lib/aspera/transfer/spec.rb +4 -3
 - data/lib/aspera/transfer/spec.schema.yaml +132 -51
 - data/lib/aspera/transfer/spec_doc.rb +41 -35
 - data/lib/aspera/uri_reader.rb +1 -1
 - data/lib/aspera/web_auth.rb +6 -6
 - data.tar.gz.sig +0 -0
 - metadata +9 -7
 - metadata.gz.sig +2 -2
 - data/lib/aspera/cli/basic_auth_plugin.rb +0 -43
 - data/lib/aspera/cli/plugin.rb +0 -333
 - data/lib/aspera/cli/plugin_factory.rb +0 -81
 - data/lib/aspera/resumer.rb +0 -77
 - data/lib/aspera/transfer/error_info.rb +0 -91
 
    
        data/lib/aspera/log.rb
    CHANGED
    
    | 
         @@ -15,14 +15,22 @@ $VERBOSE = nil 
     | 
|
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
            # Extend Ruby logger with trace levels
         
     | 
| 
       17 
17 
     | 
    
         
             
            class Logger
         
     | 
| 
       18 
     | 
    
         
            -
              # Two  
     | 
| 
      
 18 
     | 
    
         
            +
              # Two additional trace levels
         
     | 
| 
       19 
19 
     | 
    
         
             
              TRACE_MAX = 2
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
       20 
21 
     | 
    
         
             
              # Add custom level to logger severity, below debug level
         
     | 
| 
       21 
22 
     | 
    
         
             
              module Severity
         
     | 
| 
       22 
23 
     | 
    
         
             
                1.upto(TRACE_MAX).each{ |level| const_set(:"TRACE#{level}", - level)}
         
     | 
| 
       23 
24 
     | 
    
         
             
              end
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              # Hash
         
     | 
| 
      
 27 
     | 
    
         
            +
              # key   [Integer] Log level (e.g. 0 for DEBUG)
         
     | 
| 
      
 28 
     | 
    
         
            +
              # value [Symbol]  Uppercase log level label (e.g. :DEBUG)
         
     | 
| 
       25 
29 
     | 
    
         
             
              SEVERITY_LABEL = Severity.constants.each_with_object({}){ |name, hash| hash[Severity.const_get(name)] = name}
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              # Override
         
     | 
| 
      
 32 
     | 
    
         
            +
              # @param severity [Integer] Log severity as int
         
     | 
| 
      
 33 
     | 
    
         
            +
              # @return [String] Log severity upper case label
         
     | 
| 
       26 
34 
     | 
    
         
             
              def format_severity(severity)
         
     | 
| 
       27 
35 
     | 
    
         
             
                SEVERITY_LABEL[severity] || 'ANY'
         
     | 
| 
       28 
36 
     | 
    
         
             
              end
         
     | 
| 
         @@ -51,34 +59,23 @@ module Aspera 
     | 
|
| 
       51 
59 
     | 
    
         | 
| 
       52 
60 
     | 
    
         
             
                # Where logs are sent to
         
     | 
| 
       53 
61 
     | 
    
         
             
                LOG_TYPES = %i[stderr stdout syslog].freeze
         
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                 
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
                }.freeze
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                # Levels are :trace2,:trace1,:debug,:info,:warn,:error,fatal,:unknown
         
     | 
| 
      
 64 
     | 
    
         
            +
                LEVELS = Logger::Severity.constants.sort{ |a, b| Logger::Severity.const_get(a) <=> Logger::Severity.const_get(b)}.map{ |c| c.downcase.to_sym}.freeze
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
       59 
66 
     | 
    
         
             
                # Class methods
         
     | 
| 
       60 
67 
     | 
    
         
             
                class << self
         
     | 
| 
       61 
     | 
    
         
            -
                   
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
                     
     | 
| 
       66 
     | 
    
         
            -
                    when :INFO  then 'INF'.green
         
     | 
| 
       67 
     | 
    
         
            -
                    when :WARN  then 'WRN'.bg_brown.black
         
     | 
| 
       68 
     | 
    
         
            -
                    when :ERROR then 'ERR'.bg_red.blink
         
     | 
| 
       69 
     | 
    
         
            -
                    when :FATAL then 'FTL'.magenta
         
     | 
| 
       70 
     | 
    
         
            -
                    when :UNKNOWN then 'UKN'.blink
         
     | 
| 
       71 
     | 
    
         
            -
                    else Aspera.error_unexpected_value(level){'log level'}
         
     | 
| 
       72 
     | 
    
         
            -
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  # Applies the provided list of string decoration (colors) to the value.
         
     | 
| 
      
 69 
     | 
    
         
            +
                  # @param value [String]         Value to enhance.
         
     | 
| 
      
 70 
     | 
    
         
            +
                  # @param colors [Array(Symbol)] List of decorations
         
     | 
| 
      
 71 
     | 
    
         
            +
                  def apply_colors(value, colors)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    colors.inject(value){ |s, c| s.send(c)}
         
     | 
| 
       73 
73 
     | 
    
         
             
                  end
         
     | 
| 
       74 
74 
     | 
    
         | 
| 
       75 
     | 
    
         
            -
                  #  
     | 
| 
       76 
     | 
    
         
            -
                  def levels; Logger::Severity.constants.sort{ |a, b| Logger::Severity.const_get(a) <=> Logger::Severity.const_get(b)}.map{ |c| c.downcase.to_sym}; end
         
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
                  # get the logger object of singleton
         
     | 
| 
      
 75 
     | 
    
         
            +
                  # Get the logger object of singleton
         
     | 
| 
       79 
76 
     | 
    
         
             
                  def log; instance.logger; end
         
     | 
| 
       80 
77 
     | 
    
         | 
| 
       81 
     | 
    
         
            -
                  # Dump object (`Hash`) using specified level
         
     | 
| 
      
 78 
     | 
    
         
            +
                  # Dump object (`Hash`) to log using specified level
         
     | 
| 
       82 
79 
     | 
    
         
             
                  #
         
     | 
| 
       83 
80 
     | 
    
         
             
                  # @param name   [String, Symbol]  Name of object dumped
         
     | 
| 
       84 
81 
     | 
    
         
             
                  # @param object [Hash, nil]       Data to dump
         
     | 
| 
         @@ -90,14 +87,16 @@ module Aspera 
     | 
|
| 
       90 
87 
     | 
    
         
             
                    instance.logger.send(level, obj_dump(name, object))
         
     | 
| 
       91 
88 
     | 
    
         
             
                  end
         
     | 
| 
       92 
89 
     | 
    
         | 
| 
      
 90 
     | 
    
         
            +
                  # @return [String] Dump of object
         
     | 
| 
       93 
91 
     | 
    
         
             
                  def obj_dump(name, object)
         
     | 
| 
       94 
     | 
    
         
            -
                    dump_text = 
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
                       
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
                       
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
      
 92 
     | 
    
         
            +
                    dump_text =
         
     | 
| 
      
 93 
     | 
    
         
            +
                      case instance.dump_format
         
     | 
| 
      
 94 
     | 
    
         
            +
                      when :json
         
     | 
| 
      
 95 
     | 
    
         
            +
                        JSON.pretty_generate(object) rescue PP.pp(object, +'')
         
     | 
| 
      
 96 
     | 
    
         
            +
                      when :ruby
         
     | 
| 
      
 97 
     | 
    
         
            +
                        PP.pp(object, +'')
         
     | 
| 
      
 98 
     | 
    
         
            +
                      else error_unexpected_value(instance.dump_format){'dump format'}
         
     | 
| 
      
 99 
     | 
    
         
            +
                      end
         
     | 
| 
       101 
100 
     | 
    
         
             
                    "#{name.to_s.green} (#{instance.dump_format})=\n#{dump_text}"
         
     | 
| 
       102 
101 
     | 
    
         
             
                  end
         
     | 
| 
       103 
102 
     | 
    
         | 
| 
         @@ -110,6 +109,31 @@ module Aspera 
     | 
|
| 
       110 
109 
     | 
    
         
             
                  ensure
         
     | 
| 
       111 
110 
     | 
    
         
             
                    $stderr = real_stderr
         
     | 
| 
       112 
111 
     | 
    
         
             
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  # Returns the last 2 containers (module/class) and method caller
         
     | 
| 
      
 114 
     | 
    
         
            +
                  def caller_method
         
     | 
| 
      
 115 
     | 
    
         
            +
                    stack = caller
         
     | 
| 
      
 116 
     | 
    
         
            +
                    i = stack.rindex{ |line| line.include?('Logger')}
         
     | 
| 
      
 117 
     | 
    
         
            +
                    frame = stack[i + 1] if i && stack[i + 1]
         
     | 
| 
      
 118 
     | 
    
         
            +
                    return '???' unless frame
         
     | 
| 
      
 119 
     | 
    
         
            +
                    # Extract the "Class::Module::Method" or "Class#method" part
         
     | 
| 
      
 120 
     | 
    
         
            +
                    full = frame[/'([^']+)'/, 1]
         
     | 
| 
      
 121 
     | 
    
         
            +
                    return '???' unless full
         
     | 
| 
      
 122 
     | 
    
         
            +
                    # Split into class/module and method parts
         
     | 
| 
      
 123 
     | 
    
         
            +
                    parts = full.split(/(::|#)/)
         
     | 
| 
      
 124 
     | 
    
         
            +
                    # Reconstruct keeping only last two class/module names + separator + method
         
     | 
| 
      
 125 
     | 
    
         
            +
                    if parts.include?('#')
         
     | 
| 
      
 126 
     | 
    
         
            +
                      sep_index = parts.index('#')
         
     | 
| 
      
 127 
     | 
    
         
            +
                      classes = parts[0...sep_index].join
         
     | 
| 
      
 128 
     | 
    
         
            +
                      method = parts[sep_index + 1]
         
     | 
| 
      
 129 
     | 
    
         
            +
                    else
         
     | 
| 
      
 130 
     | 
    
         
            +
                      classes = parts[0..-2].join
         
     | 
| 
      
 131 
     | 
    
         
            +
                      method = parts.last
         
     | 
| 
      
 132 
     | 
    
         
            +
                    end
         
     | 
| 
      
 133 
     | 
    
         
            +
                    class_parts = classes.split('::')
         
     | 
| 
      
 134 
     | 
    
         
            +
                    selected_classes = class_parts.last(2).join('::')
         
     | 
| 
      
 135 
     | 
    
         
            +
                    "#{selected_classes}.#{method}"
         
     | 
| 
      
 136 
     | 
    
         
            +
                  end
         
     | 
| 
       113 
137 
     | 
    
         
             
                end
         
     | 
| 
       114 
138 
     | 
    
         | 
| 
       115 
139 
     | 
    
         
             
                attr_reader :logger_type, :logger
         
     | 
| 
         @@ -121,7 +145,9 @@ module Aspera 
     | 
|
| 
       121 
145 
     | 
    
         
             
                end
         
     | 
| 
       122 
146 
     | 
    
         | 
| 
       123 
147 
     | 
    
         
             
                # Set log level of underlying logger given symbol level
         
     | 
| 
      
 148 
     | 
    
         
            +
                # @param new_level [Symbol] One of LEVELS
         
     | 
| 
       124 
149 
     | 
    
         
             
                def level=(new_level)
         
     | 
| 
      
 150 
     | 
    
         
            +
                  Aspera.assert_values(new_level, LEVELS)
         
     | 
| 
       125 
151 
     | 
    
         
             
                  @logger.level = Logger::Severity.const_get(new_level.to_sym.upcase)
         
     | 
| 
       126 
152 
     | 
    
         
             
                end
         
     | 
| 
       127 
153 
     | 
    
         | 
| 
         @@ -141,11 +167,10 @@ module Aspera 
     | 
|
| 
       141 
167 
     | 
    
         
             
                end
         
     | 
| 
       142 
168 
     | 
    
         | 
| 
       143 
169 
     | 
    
         
             
                # Get symbol of debug level of underlying logger
         
     | 
| 
      
 170 
     | 
    
         
            +
                # @return [Symbol] One of LEVELS
         
     | 
| 
       144 
171 
     | 
    
         
             
                def level
         
     | 
| 
       145 
     | 
    
         
            -
                  Logger:: 
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
                  end
         
     | 
| 
       148 
     | 
    
         
            -
                  Aspera.error_unexpected_value(@logger.level){'log level'}
         
     | 
| 
      
 172 
     | 
    
         
            +
                  Aspera.assert(Logger::SEVERITY_LABEL.key?(@logger.level))
         
     | 
| 
      
 173 
     | 
    
         
            +
                  Logger::SEVERITY_LABEL[@logger.level].downcase
         
     | 
| 
       149 
174 
     | 
    
         
             
                end
         
     | 
| 
       150 
175 
     | 
    
         | 
| 
       151 
176 
     | 
    
         
             
                # Change underlying logger, but keep log level
         
     | 
| 
         @@ -160,8 +185,8 @@ module Aspera 
     | 
|
| 
       160 
185 
     | 
    
         
             
                    @logger = Logger.new($stdout, progname: @program_name, formatter: DEFAULT_FORMATTER)
         
     | 
| 
       161 
186 
     | 
    
         
             
                  when :syslog
         
     | 
| 
       162 
187 
     | 
    
         
             
                    require 'syslog/logger'
         
     | 
| 
       163 
     | 
    
         
            -
                    #  
     | 
| 
       164 
     | 
    
         
            -
                    #  
     | 
| 
      
 188 
     | 
    
         
            +
                    # The syslog class automatically creates methods from the severity names.
         
     | 
| 
      
 189 
     | 
    
         
            +
                    # We just need to add the mapping (but syslog lowest is DEBUG)
         
     | 
| 
       165 
190 
     | 
    
         
             
                    1.upto(Logger::TRACE_MAX).each do |level|
         
     | 
| 
       166 
191 
     | 
    
         
             
                      Syslog::Logger.const_get(:LEVEL_MAP)[Logger.const_get("TRACE#{level}")] = Syslog::LOG_DEBUG
         
     | 
| 
       167 
192 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -188,5 +213,31 @@ module Aspera 
     | 
|
| 
       188 
213 
     | 
    
         
             
                  # This sets @logger and @logger_type (self needed to call method instead of local var)
         
     | 
| 
       189 
214 
     | 
    
         
             
                  self.logger_type = @logger_type
         
     | 
| 
       190 
215 
     | 
    
         
             
                end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                # Define decoration of levels
         
     | 
| 
      
 218 
     | 
    
         
            +
                LVL_DECO = {
         
     | 
| 
      
 219 
     | 
    
         
            +
                  TRACE2:  %i{dim},
         
     | 
| 
      
 220 
     | 
    
         
            +
                  TRACE1:  %i{blue},
         
     | 
| 
      
 221 
     | 
    
         
            +
                  DEBUG:   %i{cyan},
         
     | 
| 
      
 222 
     | 
    
         
            +
                  INFO:    %i{green},
         
     | 
| 
      
 223 
     | 
    
         
            +
                  WARN:    %i{bg_brown black},
         
     | 
| 
      
 224 
     | 
    
         
            +
                  ERROR:   %i{bg_red blink},
         
     | 
| 
      
 225 
     | 
    
         
            +
                  FATAL:   %i{magenta},
         
     | 
| 
      
 226 
     | 
    
         
            +
                  UNKNOWN: %i{blink}
         
     | 
| 
      
 227 
     | 
    
         
            +
                }.freeze
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
                # Short levels with color
         
     | 
| 
      
 230 
     | 
    
         
            +
                LVL_COLOR = LVL_DECO.map{ |k, v| [k, apply_colors("#{k[..2]}#{k[-1]}", v)]}.to_h.freeze
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
                DEFAULT_FORMATTER = ->(s, _d, _p, m){"#{LVL_COLOR[s]} #{m}\n"}
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                # pre-defined formatters
         
     | 
| 
      
 235 
     | 
    
         
            +
                FORMATTERS = {
         
     | 
| 
      
 236 
     | 
    
         
            +
                  standard: Logger::Formatter.new,
         
     | 
| 
      
 237 
     | 
    
         
            +
                  default:  DEFAULT_FORMATTER,
         
     | 
| 
      
 238 
     | 
    
         
            +
                  caller:   ->(s, _d, _p, m){"#{LVL_COLOR[s]} #{Log.caller_method}\n#{m}\n"}
         
     | 
| 
      
 239 
     | 
    
         
            +
                }.freeze
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
                private_constant :LVL_DECO, :LVL_COLOR, :DEFAULT_FORMATTER, :FORMATTERS
         
     | 
| 
       191 
242 
     | 
    
         
             
              end
         
     | 
| 
       192 
243 
     | 
    
         
             
            end
         
     | 
    
        data/lib/aspera/nagios.rb
    CHANGED
    
    | 
         @@ -57,7 +57,7 @@ module Aspera 
     | 
|
| 
       57 
57 
     | 
    
         
             
                # compare remote time with local time
         
     | 
| 
       58 
58 
     | 
    
         
             
                def check_time_offset(remote_date, component)
         
     | 
| 
       59 
59 
     | 
    
         
             
                  # check date if specified : 2015-10-13T07:32:01Z
         
     | 
| 
       60 
     | 
    
         
            -
                  remote_time = Time. 
     | 
| 
      
 60 
     | 
    
         
            +
                  remote_time = Time.parse(remote_date)
         
     | 
| 
       61 
61 
     | 
    
         
             
                  diff_time = (remote_time - Time.now).abs
         
     | 
| 
       62 
62 
     | 
    
         
             
                  diff_rounded = diff_time.round(-2)
         
     | 
| 
       63 
63 
     | 
    
         
             
                  Log.log.debug{"DATE: #{remote_date} #{remote_time} diff=#{diff_rounded}"}
         
     | 
    
        data/lib/aspera/oauth/base.rb
    CHANGED
    
    | 
         @@ -13,6 +13,7 @@ module Aspera 
     | 
|
| 
       13 
13 
     | 
    
         
             
                # OAuth 2.0 Authorization Framework: https://tools.ietf.org/html/rfc6749
         
     | 
| 
       14 
14 
     | 
    
         
             
                # Bearer Token Usage: https://tools.ietf.org/html/rfc6750
         
     | 
| 
       15 
15 
     | 
    
         
             
                class Base
         
     | 
| 
      
 16 
     | 
    
         
            +
                  Aspera.require_method!(:create_token)
         
     | 
| 
       16 
17 
     | 
    
         
             
                  # @param **             Parameters for REST
         
     | 
| 
       17 
18 
     | 
    
         
             
                  # @param client_id      [String, nil]
         
     | 
| 
       18 
19 
     | 
    
         
             
                  # @param client_secret  [String, nil]
         
     | 
| 
         @@ -31,8 +32,7 @@ module Aspera 
     | 
|
| 
       31 
32 
     | 
    
         
             
                    cache_ids: nil,
         
     | 
| 
       32 
33 
     | 
    
         
             
                    **rest_params
         
     | 
| 
       33 
34 
     | 
    
         
             
                  )
         
     | 
| 
       34 
     | 
    
         
            -
                     
     | 
| 
       35 
     | 
    
         
            -
                    # this is the OAuth API
         
     | 
| 
      
 35 
     | 
    
         
            +
                    # This is the OAuth API
         
     | 
| 
       36 
36 
     | 
    
         
             
                    @api = Rest.new(**rest_params)
         
     | 
| 
       37 
37 
     | 
    
         
             
                    @scope = nil
         
     | 
| 
       38 
38 
     | 
    
         
             
                    @token_cache_id = nil
         
     | 
| 
         @@ -43,6 +43,7 @@ module Aspera 
     | 
|
| 
       43 
43 
     | 
    
         
             
                    @use_query = use_query
         
     | 
| 
       44 
44 
     | 
    
         
             
                    @base_cache_ids = cache_ids.nil? ? [] : cache_ids.clone
         
     | 
| 
       45 
45 
     | 
    
         
             
                    Aspera.assert_type(@base_cache_ids, Array)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    # TODO: this shall be done in class, using cache_ids
         
     | 
| 
       46 
47 
     | 
    
         
             
                    @base_cache_ids.push(@api.auth_params[:username]) if @api.auth_params.key?(:username)
         
     | 
| 
       47 
48 
     | 
    
         
             
                    @base_cache_ids.compact!
         
     | 
| 
       48 
49 
     | 
    
         
             
                    @base_cache_ids.freeze
         
     | 
| 
         @@ -56,16 +57,20 @@ module Aspera 
     | 
|
| 
       56 
57 
     | 
    
         
             
                    @token_cache_id = Factory.cache_id(@api.base_url, self.class, @base_cache_ids, @scope)
         
     | 
| 
       57 
58 
     | 
    
         
             
                  end
         
     | 
| 
       58 
59 
     | 
    
         | 
| 
       59 
     | 
    
         
            -
                  attr_reader :scope, :api, :path_token
         
     | 
| 
      
 60 
     | 
    
         
            +
                  attr_reader :scope, :api, :path_token, :client_id
         
     | 
| 
       60 
61 
     | 
    
         | 
| 
       61 
62 
     | 
    
         
             
                  # helper method to create token as per RFC
         
     | 
| 
       62 
63 
     | 
    
         
             
                  def create_token_call(creation_params)
         
     | 
| 
       63 
64 
     | 
    
         
             
                    Log.log.debug{'Generating a new token'.bg_green}
         
     | 
| 
       64 
     | 
    
         
            -
                    payload =  
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
      
 65 
     | 
    
         
            +
                    payload = if @use_query
         
     | 
| 
      
 66 
     | 
    
         
            +
                      {
         
     | 
| 
      
 67 
     | 
    
         
            +
                        query: creation_params
         
     | 
| 
      
 68 
     | 
    
         
            +
                      }
         
     | 
| 
       67 
69 
     | 
    
         
             
                    else
         
     | 
| 
       68 
     | 
    
         
            -
                       
     | 
| 
      
 70 
     | 
    
         
            +
                      {
         
     | 
| 
      
 71 
     | 
    
         
            +
                        content_type: Rest::MIME_WWW,
         
     | 
| 
      
 72 
     | 
    
         
            +
                        body:         creation_params
         
     | 
| 
      
 73 
     | 
    
         
            +
                      }
         
     | 
| 
       69 
74 
     | 
    
         
             
                    end
         
     | 
| 
       70 
75 
     | 
    
         
             
                    return @api.call(
         
     | 
| 
       71 
76 
     | 
    
         
             
                      operation: 'POST',
         
     | 
| 
         @@ -75,12 +80,13 @@ module Aspera 
     | 
|
| 
       75 
80 
     | 
    
         
             
                    )
         
     | 
| 
       76 
81 
     | 
    
         
             
                  end
         
     | 
| 
       77 
82 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
                  # @ 
     | 
| 
      
 83 
     | 
    
         
            +
                  # @param add_secret [Boolean] Add secret in default call parameters
         
     | 
| 
      
 84 
     | 
    
         
            +
                  # @return [Hash] Optional general parameters
         
     | 
| 
       79 
85 
     | 
    
         
             
                  def optional_scope_client_id(add_secret: false)
         
     | 
| 
       80 
86 
     | 
    
         
             
                    call_params = {}
         
     | 
| 
       81 
87 
     | 
    
         
             
                    call_params[:scope] = @scope unless @scope.nil?
         
     | 
| 
       82 
88 
     | 
    
         
             
                    call_params[:client_id] = @client_id unless @client_id.nil?
         
     | 
| 
       83 
     | 
    
         
            -
                    call_params[:client_secret] = @client_secret  
     | 
| 
      
 89 
     | 
    
         
            +
                    call_params[:client_secret] = @client_secret unless !add_secret || @client_id.nil? || @client_secret.nil?
         
     | 
| 
       84 
90 
     | 
    
         
             
                    return call_params
         
     | 
| 
       85 
91 
     | 
    
         
             
                  end
         
     | 
| 
       86 
92 
     | 
    
         | 
| 
         @@ -106,6 +112,7 @@ module Aspera 
     | 
|
| 
       106 
112 
     | 
    
         
             
                      # `direct` agent is equipped with refresh code
         
     | 
| 
       107 
113 
     | 
    
         
             
                      # an API was already called, but failed, we need to regenerate or refresh
         
     | 
| 
       108 
114 
     | 
    
         
             
                      if refresh || token_info[:expired]
         
     | 
| 
      
 115 
     | 
    
         
            +
                        Log.log.trace1{"refresh: #{refresh} expired: #{token_info[:expired]}"}
         
     | 
| 
       109 
116 
     | 
    
         
             
                        refresh_token = nil
         
     | 
| 
       110 
117 
     | 
    
         
             
                        if token_data.key?('refresh_token') && !token_data['refresh_token'].eql?('not_supported')
         
     | 
| 
       111 
118 
     | 
    
         
             
                          # save possible refresh token, before deleting the cache
         
     | 
| 
         @@ -118,7 +125,7 @@ module Aspera 
     | 
|
| 
       118 
125 
     | 
    
         
             
                        if !refresh_token.nil?
         
     | 
| 
       119 
126 
     | 
    
         
             
                          Log.log.info{"refresh=[#{refresh_token}]".bg_green}
         
     | 
| 
       120 
127 
     | 
    
         
             
                          # NOTE: AoC admin token has no refresh, and lives by default 1800secs
         
     | 
| 
       121 
     | 
    
         
            -
                          resp = create_token_call(optional_scope_client_id.merge(grant_type: 'refresh_token', refresh_token: refresh_token))
         
     | 
| 
      
 128 
     | 
    
         
            +
                          resp = create_token_call(optional_scope_client_id(add_secret: true).merge(grant_type: 'refresh_token', refresh_token: refresh_token))
         
     | 
| 
       122 
129 
     | 
    
         
             
                          if resp[:http].code.start_with?('2')
         
     | 
| 
       123 
130 
     | 
    
         
             
                            # save only if success
         
     | 
| 
       124 
131 
     | 
    
         
             
                            json_data = resp[:http].body
         
     | 
    
        data/lib/aspera/oauth/factory.rb
    CHANGED
    
    | 
         @@ -63,10 +63,10 @@ module Aspera 
     | 
|
| 
       63 
63 
     | 
    
         
             
                    @decoders = []
         
     | 
| 
       64 
64 
     | 
    
         
             
                    # default parameters, others can be added by handlers
         
     | 
| 
       65 
65 
     | 
    
         
             
                    @parameters = {
         
     | 
| 
       66 
     | 
    
         
            -
                      # tokens older than  
     | 
| 
       67 
     | 
    
         
            -
                       
     | 
| 
       68 
     | 
    
         
            -
                      # tokens valid for less than this duration will be regenerated
         
     | 
| 
       69 
     | 
    
         
            -
                       
     | 
| 
      
 66 
     | 
    
         
            +
                      # tokens older than this duration in sec. will be discarded from cache
         
     | 
| 
      
 67 
     | 
    
         
            +
                      token_cache_max_age:     1800,
         
     | 
| 
      
 68 
     | 
    
         
            +
                      # tokens valid for less than this duration in sec. will be regenerated
         
     | 
| 
      
 69 
     | 
    
         
            +
                      token_refresh_threshold: 120
         
     | 
| 
       70 
70 
     | 
    
         
             
                    }
         
     | 
| 
       71 
71 
     | 
    
         
             
                  end
         
     | 
| 
       72 
72 
     | 
    
         | 
| 
         @@ -77,7 +77,7 @@ module Aspera 
     | 
|
| 
       77 
77 
     | 
    
         
             
                  def persist_mgr=(manager)
         
     | 
| 
       78 
78 
     | 
    
         
             
                    @persist = manager
         
     | 
| 
       79 
79 
     | 
    
         
             
                    # cleanup expired tokens
         
     | 
| 
       80 
     | 
    
         
            -
                    @persist.garbage_collect(PERSIST_CATEGORY_TOKEN, @parameters[: 
     | 
| 
      
 80 
     | 
    
         
            +
                    @persist.garbage_collect(PERSIST_CATEGORY_TOKEN, @parameters[:token_cache_max_age])
         
     | 
| 
       81 
81 
     | 
    
         
             
                  end
         
     | 
| 
       82 
82 
     | 
    
         | 
| 
       83 
83 
     | 
    
         
             
                  def persist_mgr
         
     | 
| 
         @@ -108,7 +108,7 @@ module Aspera 
     | 
|
| 
       108 
108 
     | 
    
         
             
                    end
         
     | 
| 
       109 
109 
     | 
    
         
             
                  end
         
     | 
| 
       110 
110 
     | 
    
         | 
| 
       111 
     | 
    
         
            -
                  #  
     | 
| 
      
 111 
     | 
    
         
            +
                  # Get token information from cache
         
     | 
| 
       112 
112 
     | 
    
         
             
                  # @param id [String] identifier of token
         
     | 
| 
       113 
113 
     | 
    
         
             
                  # @return [Hash] token internal information , including Date object for `expiration_date`
         
     | 
| 
       114 
114 
     | 
    
         
             
                  def get_token_info(id)
         
     | 
| 
         @@ -118,7 +118,6 @@ module Aspera 
     | 
|
| 
       118 
118 
     | 
    
         
             
                    Aspera.assert_type(token_data, Hash)
         
     | 
| 
       119 
119 
     | 
    
         
             
                    decoded_token = decode_token(token_data[TOKEN_FIELD])
         
     | 
| 
       120 
120 
     | 
    
         
             
                    info = {data: token_data}
         
     | 
| 
       121 
     | 
    
         
            -
                    Log.dump(:decoded_token, decoded_token)
         
     | 
| 
       122 
121 
     | 
    
         
             
                    if decoded_token.is_a?(Hash)
         
     | 
| 
       123 
122 
     | 
    
         
             
                      info[:decoded] = decoded_token
         
     | 
| 
       124 
123 
     | 
    
         
             
                      # TODO: move date decoding to token decoder ?
         
     | 
| 
         @@ -129,9 +128,10 @@ module Aspera 
     | 
|
| 
       129 
128 
     | 
    
         
             
                      unless expiration_date.nil?
         
     | 
| 
       130 
129 
     | 
    
         
             
                        info[:expiration] = expiration_date
         
     | 
| 
       131 
130 
     | 
    
         
             
                        info[:ttl_sec] = expiration_date - Time.now
         
     | 
| 
       132 
     | 
    
         
            -
                        info[:expired] = info[:ttl_sec] < @parameters[: 
     | 
| 
      
 131 
     | 
    
         
            +
                        info[:expired] = info[:ttl_sec] < @parameters[:token_refresh_threshold]
         
     | 
| 
       133 
132 
     | 
    
         
             
                      end
         
     | 
| 
       134 
133 
     | 
    
         
             
                    end
         
     | 
| 
      
 134 
     | 
    
         
            +
                    Log.dump(:token_info, info)
         
     | 
| 
       135 
135 
     | 
    
         
             
                    return info
         
     | 
| 
       136 
136 
     | 
    
         
             
                  end
         
     | 
| 
       137 
137 
     | 
    
         | 
    
        data/lib/aspera/oauth/web.rb
    CHANGED
    
    | 
         @@ -9,7 +9,7 @@ module Aspera 
     | 
|
| 
       9 
9 
     | 
    
         
             
                # Authentication using Web browser
         
     | 
| 
       10 
10 
     | 
    
         
             
                class Web < Base
         
     | 
| 
       11 
11 
     | 
    
         
             
                  class << self
         
     | 
| 
       12 
     | 
    
         
            -
                    attr_accessor : 
     | 
| 
      
 12 
     | 
    
         
            +
                    attr_accessor :additional_info
         
     | 
| 
       13 
13 
     | 
    
         
             
                  end
         
     | 
| 
       14 
14 
     | 
    
         
             
                  # @param redirect_uri    url to receive the code after auth (to be exchanged for token)
         
     | 
| 
       15 
15 
     | 
    
         
             
                  # @param path_authorize  path to login page on web app
         
     | 
| 
         @@ -37,7 +37,7 @@ module Aspera 
     | 
|
| 
       37 
37 
     | 
    
         
             
                    # here, we need a human to authorize on a web page
         
     | 
| 
       38 
38 
     | 
    
         
             
                    Log.log.info{"login_page_url=#{login_page_url}".bg_red.gray}
         
     | 
| 
       39 
39 
     | 
    
         
             
                    # start a web server to receive request code
         
     | 
| 
       40 
     | 
    
         
            -
                    web_server = WebAuth.new(@redirect_uri, self.class. 
     | 
| 
      
 40 
     | 
    
         
            +
                    web_server = WebAuth.new(@redirect_uri, self.class.additional_info)
         
     | 
| 
       41 
41 
     | 
    
         
             
                    # start browser on login page
         
     | 
| 
       42 
42 
     | 
    
         
             
                    Environment.instance.open_uri(login_page_url)
         
     | 
| 
       43 
43 
     | 
    
         
             
                    # wait for code in request
         
     | 
| 
         @@ -48,11 +48,12 @@ module Aspera 
     | 
|
| 
       48 
48 
     | 
    
         
             
                    end
         
     | 
| 
       49 
49 
     | 
    
         
             
                  end
         
     | 
| 
       50 
50 
     | 
    
         | 
| 
      
 51 
     | 
    
         
            +
                  # Base URL for CDN of Connect
         
     | 
| 
       51 
52 
     | 
    
         
             
                  def cdn_api
         
     | 
| 
       52 
53 
     | 
    
         
             
                    Rest.new(base_url: CDN_BASE_URL)
         
     | 
| 
       53 
54 
     | 
    
         
             
                  end
         
     | 
| 
       54 
55 
     | 
    
         | 
| 
       55 
     | 
    
         
            -
                  #  
     | 
| 
      
 56 
     | 
    
         
            +
                  # Retrieve structure from cloud (CDN) with all versions available
         
     | 
| 
       56 
57 
     | 
    
         
             
                  def versions
         
     | 
| 
       57 
58 
     | 
    
         
             
                    if @connect_versions.nil?
         
     | 
| 
       58 
59 
     | 
    
         
             
                      javascript = cdn_api.call(operation: 'GET', subpath: VERSION_INFO_FILE)
         
     | 
| 
         @@ -74,10 +75,10 @@ module Aspera 
     | 
|
| 
       74 
75 
     | 
    
         
             
                    @connect_versions = nil
         
     | 
| 
       75 
76 
     | 
    
         
             
                  end
         
     | 
| 
       76 
77 
     | 
    
         | 
| 
       77 
     | 
    
         
            -
                  VERSION_INFO_FILE = 'connectversions.js' # cspell: disable-line
         
     | 
| 
       78 
78 
     | 
    
         
             
                  CDN_BASE_URL = 'https://d3gcli72yxqn2z.cloudfront.net/connect'
         
     | 
| 
      
 79 
     | 
    
         
            +
                  VERSION_INFO_FILE = 'connectversions.js' # cspell: disable-line
         
     | 
| 
       79 
80 
     | 
    
         | 
| 
       80 
     | 
    
         
            -
                  private_constant : 
     | 
| 
      
 81 
     | 
    
         
            +
                  private_constant :CDN_BASE_URL, :VERSION_INFO_FILE
         
     | 
| 
       81 
82 
     | 
    
         
             
                end
         
     | 
| 
       82 
83 
     | 
    
         
             
              end
         
     | 
| 
       83 
84 
     | 
    
         
             
            end
         
     | 
| 
         @@ -8,6 +8,7 @@ module Aspera 
     | 
|
| 
       8 
8 
     | 
    
         
             
                class Desktop
         
     | 
| 
       9 
9 
     | 
    
         
             
                  APP_NAME = 'IBM Aspera for Desktop'
         
     | 
| 
       10 
10 
     | 
    
         
             
                  APP_IDENTIFIER = 'com.ibm.software.aspera.desktop'
         
     | 
| 
      
 11 
     | 
    
         
            +
                  LOG_FILENAME = 'ibm-aspera-desktop.log'
         
     | 
| 
       11 
12 
     | 
    
         
             
                  class << self
         
     | 
| 
       12 
13 
     | 
    
         
             
                    # standard folder locations
         
     | 
| 
       13 
14 
     | 
    
         
             
                    def locations
         
     | 
| 
         @@ -20,10 +21,6 @@ module Aspera 
     | 
|
| 
       20 
21 
     | 
    
         
             
                      else []
         
     | 
| 
       21 
22 
     | 
    
         
             
                      end.map{ |i| i.merge({expected: APP_NAME})}
         
     | 
| 
       22 
23 
     | 
    
         
             
                    end
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                    def log_file
         
     | 
| 
       25 
     | 
    
         
            -
                      File.join(Dir.home, 'Library', 'Logs', APP_IDENTIFIER, 'ibm-aspera-desktop.log')
         
     | 
| 
       26 
     | 
    
         
            -
                    end
         
     | 
| 
       27 
24 
     | 
    
         
             
                  end
         
     | 
| 
       28 
25 
     | 
    
         
             
                end
         
     | 
| 
       29 
26 
     | 
    
         
             
              end
         
     | 
| 
         @@ -54,8 +54,14 @@ module Aspera 
     | 
|
| 
       54 
54 
     | 
    
         
             
                  }]
         
     | 
| 
       55 
55 
     | 
    
         
             
                  end
         
     | 
| 
       56 
56 
     | 
    
         
             
                  class << self
         
     | 
| 
      
 57 
     | 
    
         
            +
                    # Find installed products and provide paths for it.
         
     | 
| 
      
 58 
     | 
    
         
            +
                    # @param scan_locations [Array] Array of Hash with keys: expected, app_root, sub_bin, ascp_path, name, version
         
     | 
| 
      
 59 
     | 
    
         
            +
                    # @return [Array] of products found, with filled missing fields
         
     | 
| 
      
 60 
     | 
    
         
            +
                    # @raise Exception if no installed product found
         
     | 
| 
       57 
61 
     | 
    
         
             
                    def find(scan_locations)
         
     | 
| 
       58 
     | 
    
         
            -
                       
     | 
| 
      
 62 
     | 
    
         
            +
                      product_names = []
         
     | 
| 
      
 63 
     | 
    
         
            +
                      found = scan_locations.select do |item|
         
     | 
| 
      
 64 
     | 
    
         
            +
                        product_names.push(item[:expected]) unless product_names.include?(item[:expected])
         
     | 
| 
       59 
65 
     | 
    
         
             
                        # skip if not main folder
         
     | 
| 
       60 
66 
     | 
    
         
             
                        Log.log.trace1{"Checking #{item[:app_root]}"}
         
     | 
| 
       61 
67 
     | 
    
         
             
                        next false unless Dir.exist?(item[:app_root])
         
     | 
| 
         @@ -75,6 +81,8 @@ module Aspera 
     | 
|
| 
       75 
81 
     | 
    
         
             
                        end
         
     | 
| 
       76 
82 
     | 
    
         
             
                        true # select this version
         
     | 
| 
       77 
83 
     | 
    
         
             
                      end
         
     | 
| 
      
 84 
     | 
    
         
            +
                      raise "Product: #{product_names.join(', ')} not found, please install." if found.empty?
         
     | 
| 
      
 85 
     | 
    
         
            +
                      found
         
     | 
| 
       78 
86 
     | 
    
         
             
                    end
         
     | 
| 
       79 
87 
     | 
    
         
             
                  end
         
     | 
| 
       80 
88 
     | 
    
         
             
                end
         
     |