aspera-cli 4.14.0 → 4.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +54 -3
- data/CONTRIBUTING.md +7 -7
- data/README.md +1457 -880
- data/bin/ascli +18 -9
- data/bin/asession +12 -14
- data/examples/proxy.pac +1 -1
- data/lib/aspera/aoc.rb +198 -127
- data/lib/aspera/ascmd.rb +24 -14
- data/lib/aspera/cli/basic_auth_plugin.rb +9 -6
- data/lib/aspera/cli/error.rb +17 -0
- data/lib/aspera/cli/extended_value.rb +47 -12
- data/lib/aspera/cli/formatter.rb +260 -171
- data/lib/aspera/cli/hints.rb +80 -0
- data/lib/aspera/cli/main.rb +101 -147
- data/lib/aspera/cli/manager.rb +160 -124
- data/lib/aspera/cli/plugin.rb +70 -59
- data/lib/aspera/cli/plugins/alee.rb +0 -1
- data/lib/aspera/cli/plugins/aoc.rb +239 -273
- data/lib/aspera/cli/plugins/ats.rb +8 -5
- data/lib/aspera/cli/plugins/bss.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +516 -375
- data/lib/aspera/cli/plugins/console.rb +40 -0
- data/lib/aspera/cli/plugins/cos.rb +4 -5
- data/lib/aspera/cli/plugins/faspex.rb +99 -84
- data/lib/aspera/cli/plugins/faspex5.rb +179 -148
- data/lib/aspera/cli/plugins/node.rb +219 -153
- data/lib/aspera/cli/plugins/orchestrator.rb +52 -17
- data/lib/aspera/cli/plugins/preview.rb +46 -32
- data/lib/aspera/cli/plugins/server.rb +57 -17
- data/lib/aspera/cli/plugins/shares.rb +34 -12
- data/lib/aspera/cli/sync_actions.rb +68 -0
- data/lib/aspera/cli/transfer_agent.rb +45 -55
- data/lib/aspera/cli/transfer_progress.rb +74 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -1
- data/lib/aspera/command_line_builder.rb +14 -11
- data/lib/aspera/cos_node.rb +3 -2
- data/lib/aspera/environment.rb +17 -6
- data/lib/aspera/fasp/agent_aspera.rb +126 -0
- data/lib/aspera/fasp/agent_base.rb +31 -77
- data/lib/aspera/fasp/agent_connect.rb +21 -22
- data/lib/aspera/fasp/agent_direct.rb +88 -102
- data/lib/aspera/fasp/agent_httpgw.rb +196 -192
- data/lib/aspera/fasp/agent_node.rb +41 -34
- data/lib/aspera/fasp/agent_trsdk.rb +75 -34
- data/lib/aspera/fasp/error_info.rb +2 -2
- data/lib/aspera/fasp/faux_file.rb +52 -0
- data/lib/aspera/fasp/installation.rb +43 -184
- data/lib/aspera/fasp/management.rb +244 -0
- data/lib/aspera/fasp/parameters.rb +59 -26
- data/lib/aspera/fasp/parameters.yaml +75 -8
- data/lib/aspera/fasp/products.rb +162 -0
- data/lib/aspera/fasp/transfer_spec.rb +1 -1
- data/lib/aspera/fasp/uri.rb +4 -4
- data/lib/aspera/faspex_gw.rb +2 -2
- data/lib/aspera/faspex_postproc.rb +2 -2
- data/lib/aspera/hash_ext.rb +2 -2
- data/lib/aspera/json_rpc.rb +49 -0
- data/lib/aspera/line_logger.rb +23 -0
- data/lib/aspera/log.rb +57 -16
- data/lib/aspera/node.rb +97 -14
- data/lib/aspera/oauth.rb +36 -18
- data/lib/aspera/open_application.rb +4 -4
- data/lib/aspera/persistency_folder.rb +2 -2
- data/lib/aspera/preview/file_types.rb +4 -2
- data/lib/aspera/preview/generator.rb +22 -35
- data/lib/aspera/preview/options.rb +2 -0
- data/lib/aspera/preview/terminal.rb +24 -13
- data/lib/aspera/preview/utils.rb +19 -26
- data/lib/aspera/rest.rb +103 -72
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +15 -14
- data/lib/aspera/rest_errors_aspera.rb +37 -34
- data/lib/aspera/secret_hider.rb +14 -16
- data/lib/aspera/ssh.rb +4 -1
- data/lib/aspera/sync.rb +128 -122
- data/lib/aspera/temp_file_manager.rb +10 -3
- data/lib/aspera/web_auth.rb +10 -7
- data/lib/aspera/web_server_simple.rb +9 -4
- data.tar.gz.sig +0 -0
- metadata +33 -15
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/listener/line_dump.rb +0 -19
- data/lib/aspera/cli/listener/logger.rb +0 -22
- data/lib/aspera/cli/listener/progress.rb +0 -50
- data/lib/aspera/cli/listener/progress_multi.rb +0 -84
- data/lib/aspera/cli/plugins/sync.rb +0 -44
- data/lib/aspera/fasp/listener.rb +0 -13
@@ -1,49 +1,51 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# cspell:words Transfersdk
|
4
|
-
|
5
3
|
require 'aspera/fasp/agent_base'
|
6
4
|
require 'aspera/fasp/installation'
|
7
5
|
require 'json'
|
6
|
+
require 'uri'
|
8
7
|
|
9
8
|
module Aspera
|
10
9
|
module Fasp
|
11
10
|
class AgentTrsdk < Aspera::Fasp::AgentBase
|
12
11
|
DEFAULT_OPTIONS = {
|
13
|
-
|
14
|
-
|
12
|
+
url: 'grpc://127.0.0.1:0',
|
13
|
+
external: false,
|
14
|
+
keep: false
|
15
15
|
}.freeze
|
16
16
|
private_constant :DEFAULT_OPTIONS
|
17
17
|
|
18
18
|
# options come from transfer_info
|
19
|
-
def initialize(user_opts)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
options[k] = v
|
26
|
-
end
|
27
|
-
Log.log.debug{"options= #{options}"}
|
28
|
-
super()
|
19
|
+
def initialize(user_opts={})
|
20
|
+
super(user_opts)
|
21
|
+
@options = AgentBase.options(default: DEFAULT_OPTIONS, options: user_opts)
|
22
|
+
daemon_uri = URI.parse(@options[:url])
|
23
|
+
raise Fasp::Error, "invalid url #{@options[:url]}" unless daemon_uri.scheme.eql?('grpc')
|
24
|
+
Log.log.debug{Log.dump(:agent_options, @options)}
|
29
25
|
# load and create SDK stub
|
30
26
|
$LOAD_PATH.unshift(Installation.instance.sdk_ruby_folder)
|
31
27
|
require 'transfer_services_pb'
|
32
|
-
|
28
|
+
# it stays
|
29
|
+
@daemon_pid = nil
|
33
30
|
begin
|
31
|
+
@transfer_client = Transfersdk::TransferService::Stub.new("#{daemon_uri.host}:#{daemon_uri.port}", :this_channel_is_insecure)
|
34
32
|
get_info_response = @transfer_client.get_info(Transfersdk::InstanceInfoRequest.new)
|
35
33
|
Log.log.debug{"daemon info: #{get_info_response}"}
|
34
|
+
Log.log.warn{'attached to existing daemon'} unless @options[:external] || @options[:keep]
|
35
|
+
at_exit{shutdown}
|
36
36
|
rescue GRPC::Unavailable
|
37
|
-
|
37
|
+
raise if @options[:external]
|
38
|
+
raise "daemon started with PID #{@daemon_pid}, but connection failed to #{daemon_uri}}" unless @daemon_pid.nil?
|
39
|
+
Log.log.warn('no daemon present, starting daemon...') if @options[:external]
|
38
40
|
# location of daemon binary
|
39
41
|
bin_folder = File.realpath(File.join(Installation.instance.sdk_ruby_folder, '..'))
|
40
42
|
# config file and logs are created in same folder
|
41
|
-
|
43
|
+
generated_config_file_path = File.join(bin_folder, 'sdk.conf')
|
42
44
|
log_base = File.join(bin_folder, 'transferd')
|
43
45
|
# create a config file for daemon
|
44
46
|
config = {
|
45
|
-
address:
|
46
|
-
port:
|
47
|
+
address: daemon_uri.host,
|
48
|
+
port: daemon_uri.port,
|
47
49
|
fasp_runtime: {
|
48
50
|
use_embedded: false,
|
49
51
|
user_defined: {
|
@@ -52,10 +54,30 @@ module Aspera
|
|
52
54
|
}
|
53
55
|
}
|
54
56
|
}
|
55
|
-
File.write(
|
56
|
-
|
57
|
-
|
58
|
-
|
57
|
+
File.write(generated_config_file_path, config.to_json)
|
58
|
+
@daemon_pid = Process.spawn(Installation.instance.path(:transferd), '--config', generated_config_file_path, out: "#{log_base}.out", err: "#{log_base}.err")
|
59
|
+
begin
|
60
|
+
# wait for process to initialize
|
61
|
+
Timeout.timeout(2.0) do
|
62
|
+
_, status = Process.wait2(@daemon_pid)
|
63
|
+
raise "transfer daemon exited with status #{status.exitstatus}. Check files: #{log_base}.out #{log_base}.err"
|
64
|
+
end
|
65
|
+
rescue Timeout::Error
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
Log.log.debug{"daemon started with pid #{@daemon_pid}"}
|
69
|
+
Process.detach(@daemon_pid) if @options[:keep]
|
70
|
+
if daemon_uri.port.eql?(0)
|
71
|
+
# if port is zero, a dynamic port was created, get it
|
72
|
+
File.open("#{log_base}.out", 'r') do |file|
|
73
|
+
file.each_line do |line|
|
74
|
+
if (m = line.match(/Info: API Server: Listening on ([^:]+):(\d+) /))
|
75
|
+
daemon_uri.port = m[2].to_i
|
76
|
+
# no "break" , need to keep last one
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
59
81
|
retry
|
60
82
|
end
|
61
83
|
end
|
@@ -74,25 +96,34 @@ module Aspera
|
|
74
96
|
end
|
75
97
|
|
76
98
|
def wait_for_transfers_completion
|
77
|
-
|
99
|
+
# set to true when we know the total size of the transfer
|
100
|
+
session_started = false
|
101
|
+
bytes_expected = nil
|
78
102
|
# monitor transfer status
|
79
103
|
@transfer_client.monitor_transfers(Transfersdk::RegistrationRequest.new(transferId: [@transfer_id])) do |response|
|
80
|
-
Log.dump(:response, response.to_h)
|
104
|
+
Log.log.debug{Log.dump(:response, response.to_h)}
|
81
105
|
# Log.log.debug{"#{response.sessionInfo.preTransferBytes} #{response.transferInfo.bytesTransferred}"}
|
82
106
|
case response.status
|
83
107
|
when :RUNNING
|
84
|
-
if !
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
108
|
+
if !session_started
|
109
|
+
notify_progress(session_id: @transfer_id, type: :session_start)
|
110
|
+
session_started = true
|
111
|
+
end
|
112
|
+
if bytes_expected.nil? &&
|
113
|
+
!response.sessionInfo.preTransferBytes.eql?(0)
|
114
|
+
bytes_expected = response.sessionInfo.preTransferBytes
|
115
|
+
notify_progress(type: :session_size, session_id: @transfer_id, info: bytes_expected)
|
89
116
|
end
|
90
|
-
|
91
|
-
|
92
|
-
|
117
|
+
notify_progress(type: :transfer, session_id: @transfer_id, info: response.transferInfo.bytesTransferred)
|
118
|
+
when :COMPLETED
|
119
|
+
notify_progress(type: :transfer, session_id: @transfer_id, info: bytes_expected) if bytes_expected
|
120
|
+
notify_progress(type: :end, session_id: @transfer_id)
|
93
121
|
break
|
122
|
+
when :FAILED, :CANCELED
|
123
|
+
notify_progress(type: :end, session_id: @transfer_id)
|
124
|
+
raise Fasp::Error, JSON.parse(response.message)['Description']
|
94
125
|
when :QUEUED, :UNKNOWN_STATUS, :PAUSED, :ORPHANED
|
95
|
-
|
126
|
+
notify_progress(session_id: nil, type: :pre_start, info: response.status.to_s.downcase)
|
96
127
|
else
|
97
128
|
Log.log.error{"unknown status#{response.status}"}
|
98
129
|
end
|
@@ -100,6 +131,16 @@ module Aspera
|
|
100
131
|
# TODO: return status
|
101
132
|
return []
|
102
133
|
end
|
134
|
+
|
135
|
+
def shutdown
|
136
|
+
if !@options[:keep] && !@daemon_pid.nil?
|
137
|
+
Log.log.debug("stopping daemon #{@daemon_pid}")
|
138
|
+
Process.kill('INT', @daemon_pid)
|
139
|
+
_, status = Process.wait2(@daemon_pid)
|
140
|
+
Log.log.debug("daemon stopped #{status}")
|
141
|
+
@daemon_pid = nil
|
142
|
+
end
|
143
|
+
end
|
103
144
|
end
|
104
145
|
end
|
105
146
|
end
|
@@ -5,11 +5,11 @@
|
|
5
5
|
module Aspera
|
6
6
|
module Fasp
|
7
7
|
# from https://www.google.com/search?q=FASP+error+codes
|
8
|
-
# Note that the fact that an error is
|
8
|
+
# Note that the fact that an error is retry-able is not internally defined by protocol, it's client-side responsibility
|
9
9
|
# rubocop:disable Layout/MultilineHashKeyLineBreaks
|
10
10
|
# rubocop:disable Layout/FirstHashElementLineBreak
|
11
11
|
ERROR_INFO = {
|
12
|
-
# id
|
12
|
+
# id retry-able mnemo message additional info
|
13
13
|
1 => { r: false, c: 'FASP_PROTO', m: 'Generic fasp(tm) protocol error', a: 'fasp(tm) error'},
|
14
14
|
2 => { r: false, c: 'ASCP', m: 'Generic SCP error', a: 'ASCP error'},
|
15
15
|
3 => { r: false, c: 'AMBIGUOUS_TARGET', m: 'Target incorrectly specified', a: 'Ambiguous target'},
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Aspera
|
4
|
+
module Fasp
|
5
|
+
# generates a pseudo file stream
|
6
|
+
class FauxFile
|
7
|
+
# marker for faux file
|
8
|
+
PREFIX = 'faux:///'
|
9
|
+
# size suffix
|
10
|
+
SUFFIX = %w[k m g t p e]
|
11
|
+
class << self
|
12
|
+
def open(name)
|
13
|
+
return nil unless name.start_with?(PREFIX)
|
14
|
+
parts = name[PREFIX.length..-1].split('?')
|
15
|
+
raise 'Format: #{PREFIX}<file path>?<size>' unless parts.length.eql?(2)
|
16
|
+
raise "Format: <integer>[#{SUFFIX.join(',')}]" unless (m = parts[1].downcase.match(/^(\d+)([#{SUFFIX.join('')}])$/))
|
17
|
+
size = m[1].to_i
|
18
|
+
suffix = m[2]
|
19
|
+
SUFFIX.each do |s|
|
20
|
+
size *= 1024
|
21
|
+
break if s.eql?(suffix)
|
22
|
+
end
|
23
|
+
return FauxFile.new(parts[0], size)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
attr_reader :path, :size
|
27
|
+
|
28
|
+
def initialize(path, size)
|
29
|
+
@path = path
|
30
|
+
@size = size
|
31
|
+
@offset = 0
|
32
|
+
# we cache large chunks, anyway most of them will be the same size
|
33
|
+
@chunk_by_size = {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def read(chunk_size)
|
37
|
+
return nil if eof?
|
38
|
+
bytes_to_read = [chunk_size, @size - @offset].min
|
39
|
+
@offset += bytes_to_read
|
40
|
+
@chunk_by_size[bytes_to_read] = "\x00" * bytes_to_read unless @chunk_by_size.key?(bytes_to_read)
|
41
|
+
return @chunk_by_size[bytes_to_read]
|
42
|
+
end
|
43
|
+
|
44
|
+
def close
|
45
|
+
end
|
46
|
+
|
47
|
+
def eof?
|
48
|
+
return @offset >= @size
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require 'singleton'
|
5
|
-
require 'aspera/log'
|
3
|
+
# cspell:ignore protobuf ckpt
|
6
4
|
require 'aspera/environment'
|
7
5
|
require 'aspera/data_repository'
|
6
|
+
require 'aspera/fasp/products'
|
7
|
+
require 'aspera/log'
|
8
|
+
require 'aspera/web_server_simple'
|
9
|
+
require 'English'
|
10
|
+
require 'singleton'
|
8
11
|
require 'xmlsimple'
|
9
12
|
require 'zlib'
|
10
13
|
require 'base64'
|
@@ -13,24 +16,18 @@ require 'openssl'
|
|
13
16
|
|
14
17
|
module Aspera
|
15
18
|
module Fasp
|
16
|
-
# Singleton that tells where to find ascp and other local resources (keys..) , using the "path(
|
19
|
+
# Singleton that tells where to find ascp and other local resources (keys..) , using the "path(:name)" method.
|
17
20
|
# It is used by object : AgentDirect to find necessary resources
|
18
|
-
# By default it takes the first Aspera product found
|
21
|
+
# By default it takes the first Aspera product found
|
19
22
|
# but the user can specify ascp location by calling:
|
20
23
|
# Installation.instance.use_ascp_from_product(product_name)
|
21
24
|
# or
|
22
25
|
# Installation.instance.ascp_path=""
|
23
26
|
class Installation
|
24
27
|
include Singleton
|
25
|
-
# known product names
|
26
|
-
PRODUCT_CONNECT = 'Aspera Connect'
|
27
|
-
PRODUCT_CLI_V1 = 'Aspera CLI'
|
28
|
-
PRODUCT_DRIVE = 'Aspera Drive'
|
29
|
-
PRODUCT_ENTSRV = 'Enterprise Server'
|
30
28
|
# protobuf generated files from sdk
|
31
29
|
EXT_RUBY_PROTOBUF = '_pb.rb'
|
32
30
|
RB_SDK_FOLDER = 'lib'
|
33
|
-
ONE_YEAR_SECONDS = 365 * 24 * 60 * 60
|
34
31
|
DEFAULT_ASPERA_CONF = <<~END_OF_CONFIG_FILE
|
35
32
|
<?xml version='1.0' encoding='UTF-8'?>
|
36
33
|
<CONF version="2">
|
@@ -42,9 +39,9 @@ module Aspera
|
|
42
39
|
</default>
|
43
40
|
</CONF>
|
44
41
|
END_OF_CONFIG_FILE
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
# all ascp files (in SDK)
|
43
|
+
FILES = %i[ascp ascp4 transferd ssh_private_dsa ssh_private_rsa aspera_license aspera_conf fallback_certificate fallback_private_key].freeze
|
44
|
+
private_constant :EXT_RUBY_PROTOBUF, :RB_SDK_FOLDER, :DEFAULT_ASPERA_CONF, :FILES
|
48
45
|
# set ascp executable path
|
49
46
|
def ascp_path=(v)
|
50
47
|
@path_to_ascp = v
|
@@ -56,7 +53,7 @@ module Aspera
|
|
56
53
|
|
57
54
|
def sdk_ruby_folder
|
58
55
|
ruby_pb_folder = File.join(sdk_folder, RB_SDK_FOLDER)
|
59
|
-
FileUtils.mkdir_p(ruby_pb_folder)
|
56
|
+
FileUtils.mkdir_p(ruby_pb_folder)
|
60
57
|
return ruby_pb_folder
|
61
58
|
end
|
62
59
|
|
@@ -73,61 +70,36 @@ module Aspera
|
|
73
70
|
# @return the path to folder where SDK is installed
|
74
71
|
def sdk_folder
|
75
72
|
raise 'SDK path was ot initialized' if @sdk_dir.nil?
|
76
|
-
FileUtils.mkdir_p(@sdk_dir)
|
73
|
+
FileUtils.mkdir_p(@sdk_dir)
|
77
74
|
@sdk_dir
|
78
75
|
end
|
79
76
|
|
80
77
|
# find ascp in named product (use value : FIRST_FOUND='FIRST' to just use first one)
|
81
|
-
# or select one from installed_products()
|
78
|
+
# or select one from Products.installed_products()
|
82
79
|
def use_ascp_from_product(product_name)
|
83
80
|
if product_name.eql?(FIRST_FOUND)
|
84
|
-
pl = installed_products.first
|
81
|
+
pl = Products.installed_products.first
|
85
82
|
raise "no FASP installation found\nPlease check manual on how to install FASP." if pl.nil?
|
86
83
|
else
|
87
|
-
pl = installed_products.find{|i|i[:name].eql?(product_name)}
|
84
|
+
pl = Products.installed_products.find{|i|i[:name].eql?(product_name)}
|
88
85
|
raise "no such product installed: #{product_name}" if pl.nil?
|
89
86
|
end
|
90
87
|
self.ascp_path = pl[:ascp_path]
|
91
88
|
Log.log.debug{"ascp_path=#{@path_to_ascp}"}
|
92
89
|
end
|
93
90
|
|
94
|
-
# @return
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
sub_bin: ''
|
103
|
-
})
|
104
|
-
# search installed products: with ascp
|
105
|
-
@found_products = scan_locations.select! do |item|
|
106
|
-
# skip if not main folder
|
107
|
-
next false unless Dir.exist?(item[:app_root])
|
108
|
-
Log.log.debug{"Found #{item[:app_root]}"}
|
109
|
-
sub_bin = item[:sub_bin] || BIN_SUBFOLDER
|
110
|
-
item[:ascp_path] = File.join(item[:app_root], sub_bin, ascp_filename)
|
111
|
-
# skip if no ascp
|
112
|
-
next false unless File.exist?(item[:ascp_path])
|
113
|
-
# read info from product info file if present
|
114
|
-
product_info_file = "#{item[:app_root]}/#{PRODUCT_INFO}"
|
115
|
-
if File.exist?(product_info_file)
|
116
|
-
res_s = XmlSimple.xml_in(File.read(product_info_file), {'ForceArray' => false})
|
117
|
-
item[:name] = res_s['name']
|
118
|
-
item[:version] = res_s['version']
|
119
|
-
else
|
120
|
-
item[:name] = item[:expected]
|
91
|
+
# @return [Hash] with key = file name (String), and value = path to file
|
92
|
+
def file_paths
|
93
|
+
return FILES.each_with_object({}) do |v, m|
|
94
|
+
m[v.to_s] =
|
95
|
+
begin
|
96
|
+
path(v)
|
97
|
+
rescue => e
|
98
|
+
e.message
|
121
99
|
end
|
122
|
-
true # select this version
|
123
|
-
end
|
124
100
|
end
|
125
|
-
return @found_products
|
126
101
|
end
|
127
102
|
|
128
|
-
# all ascp files (in SDK)
|
129
|
-
FILES = %i[ascp ascp4 ssh_bypass_dsa_privkey ssh_bypass_rsa_privkey aspera_license aspera_conf fallback_certificate fallback_cert_privkey].freeze
|
130
|
-
|
131
103
|
def check_or_create_sdk_file(filename, force: false, &block)
|
132
104
|
return Environment.write_file_restricted(File.join(sdk_folder, filename), force: force, mode: 0o644, &block)
|
133
105
|
end
|
@@ -143,31 +115,28 @@ module Aspera
|
|
143
115
|
file = file.gsub('ascp', 'ascp4') if k.eql?(:ascp4)
|
144
116
|
when :transferd
|
145
117
|
file = transferd_filepath
|
146
|
-
when :
|
147
|
-
|
148
|
-
|
149
|
-
file = check_or_create_sdk_file(
|
118
|
+
when :ssh_private_dsa, :ssh_private_rsa
|
119
|
+
# assume last 3 letters are type
|
120
|
+
type = k.to_s[-3..-1]
|
121
|
+
file = check_or_create_sdk_file("aspera_bypass_#{type}.pem") do
|
122
|
+
# generate PEM from DER
|
123
|
+
OpenSSL::PKey.const_get(type.upcase).new(DataRepository.instance.data(type.eql?('dsa') ? 1 : 2)).to_pem
|
124
|
+
end
|
150
125
|
when :aspera_license
|
151
126
|
file = check_or_create_sdk_file('aspera-license') do
|
152
127
|
Zlib::Inflate.inflate(DataRepository.instance.data(6))
|
153
128
|
end
|
154
129
|
when :aspera_conf
|
155
130
|
file = check_or_create_sdk_file('aspera.conf') {DEFAULT_ASPERA_CONF}
|
156
|
-
when :fallback_certificate, :
|
131
|
+
when :fallback_certificate, :fallback_private_key
|
157
132
|
file_key = File.join(sdk_folder, 'aspera_fallback_cert_private_key.pem')
|
158
133
|
file_cert = File.join(sdk_folder, 'aspera_fallback_cert.pem')
|
159
134
|
if !File.exist?(file_key) || !File.exist?(file_cert)
|
160
135
|
require 'openssl'
|
161
136
|
# create new self signed certificate for http fallback
|
162
|
-
private_key = OpenSSL::PKey::RSA.new(1024)
|
163
137
|
cert = OpenSSL::X509::Certificate.new
|
164
|
-
|
165
|
-
cert
|
166
|
-
cert.not_after = Time.now + ONE_YEAR_SECONDS
|
167
|
-
cert.public_key = private_key.public_key
|
168
|
-
cert.serial = 0x0
|
169
|
-
cert.version = 2
|
170
|
-
cert.sign(private_key, OpenSSL::Digest.new('SHA1'))
|
138
|
+
private_key = OpenSSL::PKey::RSA.new(4096)
|
139
|
+
WebServerSimple.fill_self_signed_cert(cert, private_key)
|
171
140
|
check_or_create_sdk_file('aspera_fallback_cert_private_key.pem', force: true) {private_key.to_pem}
|
172
141
|
check_or_create_sdk_file('aspera_fallback_cert.pem', force: true) {cert.to_pem}
|
173
142
|
end
|
@@ -179,33 +148,13 @@ module Aspera
|
|
179
148
|
return file
|
180
149
|
end
|
181
150
|
|
182
|
-
# @return the file path of local connect where API's URI can be read
|
183
|
-
def connect_uri
|
184
|
-
connect = get_product_folders(PRODUCT_CONNECT)
|
185
|
-
folder = File.join(connect[:run_root], VAR_RUN_SUBFOLDER)
|
186
|
-
['', 's'].each do |ext|
|
187
|
-
uri_file = File.join(folder, "http#{ext}.uri")
|
188
|
-
Log.log.debug{"checking connect port file: #{uri_file}"}
|
189
|
-
if File.exist?(uri_file)
|
190
|
-
return File.open(uri_file, &:gets).strip
|
191
|
-
end
|
192
|
-
end
|
193
|
-
raise "no connect uri file found in #{folder}"
|
194
|
-
end
|
195
|
-
|
196
|
-
# @ return path to configuration file of aspera CLI
|
197
|
-
def cli_conf_file
|
198
|
-
connect = get_product_folders(PRODUCT_CLI_V1)
|
199
|
-
return File.join(connect[:app_root], BIN_SUBFOLDER, '.aspera_cli_conf')
|
200
|
-
end
|
201
|
-
|
202
151
|
# default bypass key phrase
|
203
|
-
def
|
152
|
+
def ssh_cert_uuid
|
204
153
|
return format('%08x-%04x-%04x-%04x-%04x%08x', *DataRepository.instance.data(3).unpack('NnnnnN'))
|
205
154
|
end
|
206
155
|
|
207
|
-
def
|
208
|
-
return %i[
|
156
|
+
def aspera_token_ssh_key_paths
|
157
|
+
return %i[ssh_private_dsa ssh_private_rsa].map{|i|Installation.instance.path(i)}
|
209
158
|
end
|
210
159
|
|
211
160
|
# use in plugin `config`
|
@@ -267,123 +216,33 @@ module Aspera
|
|
267
216
|
# ensure license file are generated so that ascp invocation for version works
|
268
217
|
path(:aspera_license)
|
269
218
|
path(:aspera_conf)
|
270
|
-
|
271
|
-
|
219
|
+
ascp_file = Products.ascp_filename
|
220
|
+
ascp_path = File.join(sdk_folder, ascp_file)
|
221
|
+
raise "No #{ascp_file} found in SDK archive" unless File.exist?(ascp_path)
|
272
222
|
Environment.restrict_file_access(ascp_path, mode: 0o755)
|
273
223
|
Environment.restrict_file_access(ascp_path.gsub('ascp', 'ascp4'), mode: 0o755)
|
274
|
-
ascp_version = get_ascp_version(
|
224
|
+
ascp_version = get_ascp_version(ascp_path)
|
275
225
|
trd_path = transferd_filepath
|
276
226
|
Log.log.warn{"No #{trd_path} in SDK archive"} unless File.exist?(trd_path)
|
277
227
|
Environment.restrict_file_access(trd_path, mode: 0o755) if File.exist?(trd_path)
|
278
228
|
transferd_version = get_exe_version(trd_path, 'version')
|
279
229
|
sdk_version = transferd_version || ascp_version
|
280
|
-
File.write(File.join(sdk_folder,
|
230
|
+
File.write(File.join(sdk_folder, Products::INFO_META_FILE), "<product><name>IBM Aspera SDK</name><version>#{sdk_version}</version></product>")
|
281
231
|
return sdk_version
|
282
232
|
end
|
283
233
|
|
284
234
|
private
|
285
235
|
|
286
|
-
BIN_SUBFOLDER = 'bin'
|
287
|
-
ETC_SUBFOLDER = 'etc'
|
288
|
-
VAR_RUN_SUBFOLDER = File.join('var', 'run')
|
289
|
-
# product information manifest: XML (part of aspera product)
|
290
|
-
PRODUCT_INFO = 'product-info.mf'
|
291
236
|
# policy for product selection
|
292
237
|
FIRST_FOUND = 'FIRST'
|
293
238
|
|
294
|
-
private_constant :BIN_SUBFOLDER, :ETC_SUBFOLDER, :VAR_RUN_SUBFOLDER, :PRODUCT_INFO
|
295
|
-
|
296
239
|
def initialize
|
297
240
|
@path_to_ascp = nil
|
298
241
|
@sdk_dir = nil
|
299
|
-
@found_products = nil
|
300
|
-
end
|
301
|
-
|
302
|
-
# @return folder paths for specified applications
|
303
|
-
# @param name Connect or CLI
|
304
|
-
def get_product_folders(name)
|
305
|
-
found = installed_products.select{|i|i[:expected].eql?(name) || i[:name].eql?(name)}
|
306
|
-
raise "Product: #{name} not found, please install." if found.empty?
|
307
|
-
return found.first
|
308
|
-
end
|
309
|
-
|
310
|
-
# filename for ascp with optional extension (Windows)
|
311
|
-
def ascp_filename
|
312
|
-
return 'ascp' + Environment.exe_extension
|
313
242
|
end
|
314
243
|
|
315
244
|
def transferd_filepath
|
316
|
-
return File.join(sdk_folder, 'asperatransferd' + Environment.exe_extension)
|
317
|
-
end
|
318
|
-
|
319
|
-
# @return product folders depending on OS fields
|
320
|
-
# :expected M app name is taken from the manifest if present, else defaults to this value
|
321
|
-
# :app_root M main folder for the application
|
322
|
-
# :log_root O location of log files (Linux uses syslog)
|
323
|
-
# :run_root O only for Connect Client, location of http port file
|
324
|
-
# :sub_bin O subfolder with executables, default : bin
|
325
|
-
def product_locations
|
326
|
-
case Aspera::Environment.os
|
327
|
-
when Aspera::Environment::OS_WINDOWS; return [{
|
328
|
-
expected: PRODUCT_CONNECT,
|
329
|
-
app_root: File.join(ENV['LOCALAPPDATA'], 'Programs', 'Aspera', 'Aspera Connect'),
|
330
|
-
log_root: File.join(ENV['LOCALAPPDATA'], 'Aspera', 'Aspera Connect', 'var', 'log'),
|
331
|
-
run_root: File.join(ENV['LOCALAPPDATA'], 'Aspera', 'Aspera Connect')
|
332
|
-
}, {
|
333
|
-
expected: PRODUCT_CLI_V1,
|
334
|
-
app_root: File.join('C:', 'Program Files', 'Aspera', 'cli'),
|
335
|
-
log_root: File.join('C:', 'Program Files', 'Aspera', 'cli', 'var', 'log')
|
336
|
-
}, {
|
337
|
-
expected: PRODUCT_ENTSRV,
|
338
|
-
app_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server'),
|
339
|
-
log_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server', 'var', 'log')
|
340
|
-
}]
|
341
|
-
when Aspera::Environment::OS_X; return [{
|
342
|
-
expected: PRODUCT_CONNECT,
|
343
|
-
app_root: File.join(Dir.home, 'Applications', 'Aspera Connect.app'),
|
344
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
345
|
-
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
346
|
-
sub_bin: File.join('Contents', 'Resources')
|
347
|
-
}, {
|
348
|
-
expected: PRODUCT_CONNECT,
|
349
|
-
app_root: File.join('', 'Applications', 'Aspera Connect.app'),
|
350
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
|
351
|
-
run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
|
352
|
-
sub_bin: File.join('Contents', 'Resources')
|
353
|
-
}, {
|
354
|
-
expected: PRODUCT_CLI_V1,
|
355
|
-
app_root: File.join(Dir.home, 'Applications', 'Aspera CLI'),
|
356
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
|
357
|
-
}, {
|
358
|
-
expected: PRODUCT_ENTSRV,
|
359
|
-
app_root: File.join('', 'Library', 'Aspera'),
|
360
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
|
361
|
-
}, {
|
362
|
-
expected: PRODUCT_DRIVE,
|
363
|
-
app_root: File.join('', 'Applications', 'Aspera Drive.app'),
|
364
|
-
log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Drive'),
|
365
|
-
sub_bin: File.join('Contents', 'Resources')
|
366
|
-
}]
|
367
|
-
else; return [{ # other: Linux and Unix family
|
368
|
-
expected: PRODUCT_CONNECT,
|
369
|
-
app_root: File.join(Dir.home, '.aspera', 'connect'),
|
370
|
-
run_root: File.join(Dir.home, '.aspera', 'connect')
|
371
|
-
}, {
|
372
|
-
expected: PRODUCT_CLI_V1,
|
373
|
-
app_root: File.join(Dir.home, '.aspera', 'cli')
|
374
|
-
}, {
|
375
|
-
expected: PRODUCT_ENTSRV,
|
376
|
-
app_root: File.join('', 'opt', 'aspera')
|
377
|
-
}]
|
378
|
-
end
|
379
|
-
end
|
380
|
-
|
381
|
-
# @return a standard bypass key
|
382
|
-
# @param type rsa or dsa
|
383
|
-
# @param id in repository 1 for dsa, 2 for rsa
|
384
|
-
def get_key(type, id)
|
385
|
-
# generate PEM from DER
|
386
|
-
OpenSSL::PKey.const_get(type.upcase).new(DataRepository.instance.data(id)).to_pem
|
245
|
+
return File.join(sdk_folder, 'asperatransferd' + Environment.exe_extension) # cspell:disable-line
|
387
246
|
end
|
388
247
|
end # Installation
|
389
248
|
end
|