aspera-cli 4.24.1 → 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 +15 -2
- data/README.md +745 -436
- 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 +55 -70
- 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 +249 -220
- 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 +65 -53
- 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 +10 -7
- 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 +37 -9
- 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 +16 -16
- 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 +0 -0
- 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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# cspell:ignore initdemo genkey pubkey asperasoft filelists
|
|
4
|
-
require 'aspera/cli/
|
|
4
|
+
require 'aspera/cli/plugins/basic_auth'
|
|
5
|
+
require 'aspera/cli/plugins/factory'
|
|
5
6
|
require 'aspera/cli/extended_value'
|
|
6
7
|
require 'aspera/cli/special_values'
|
|
7
8
|
require 'aspera/cli/version'
|
|
@@ -10,8 +11,8 @@ require 'aspera/cli/info'
|
|
|
10
11
|
require 'aspera/cli/transfer_progress'
|
|
11
12
|
require 'aspera/cli/wizard'
|
|
12
13
|
require 'aspera/ascp/installation'
|
|
14
|
+
require 'aspera/sync/operations'
|
|
13
15
|
require 'aspera/products/transferd'
|
|
14
|
-
require 'aspera/transfer/error_info'
|
|
15
16
|
require 'aspera/transfer/parameters'
|
|
16
17
|
require 'aspera/transfer/spec'
|
|
17
18
|
require 'aspera/transfer/spec_doc'
|
|
@@ -36,93 +37,34 @@ require 'erb'
|
|
|
36
37
|
module Aspera
|
|
37
38
|
module Cli
|
|
38
39
|
module Plugins
|
|
39
|
-
#
|
|
40
|
-
class Config <
|
|
41
|
-
# folder in $HOME for application files (config, cache)
|
|
42
|
-
ASPERA_HOME_FOLDER_NAME = '.aspera'
|
|
43
|
-
# default config file
|
|
44
|
-
DEFAULT_CONFIG_FILENAME = 'config.yaml'
|
|
45
|
-
# reserved preset names
|
|
46
|
-
CONF_PRESET_CONFIG = 'config'
|
|
47
|
-
CONF_PRESET_VERSION = 'version'
|
|
48
|
-
CONF_PRESET_DEFAULTS = 'default'
|
|
49
|
-
CONF_PRESET_GLOBAL = 'global_common_defaults'
|
|
50
|
-
# special name to identify value of default
|
|
51
|
-
GLOBAL_DEFAULT_KEYWORD = 'GLOBAL'
|
|
52
|
-
CONF_GLOBAL_SYM = :config
|
|
53
|
-
# folder containing custom plugins in user's config folder
|
|
54
|
-
ASPERA_PLUGINS_FOLDERNAME = 'plugins'
|
|
55
|
-
PERSISTENCY_FOLDER = 'persist_store'
|
|
56
|
-
ASPERA = 'aspera'
|
|
57
|
-
SERVER_COMMAND = 'server'
|
|
58
|
-
DIR_SDK = 'sdk'
|
|
59
|
-
DEMO_SERVER = 'demo'
|
|
60
|
-
DEMO_PRESET = 'demoserver' # cspell: disable-line
|
|
61
|
-
EMAIL_TEST_TEMPLATE = <<~END_OF_TEMPLATE
|
|
62
|
-
From: <%=from_name%> <<%=from_email%>>
|
|
63
|
-
To: <<%=to%>>
|
|
64
|
-
Subject: #{Info::GEM_NAME} email test
|
|
65
|
-
|
|
66
|
-
This email was sent to test #{Info::CMD_NAME}.
|
|
67
|
-
END_OF_TEMPLATE
|
|
68
|
-
# special extended values
|
|
69
|
-
EXTEND_PRESET = :preset
|
|
70
|
-
EXTEND_VAULT = :vault
|
|
71
|
-
PRESET_DIG_SEPARATOR = '.'
|
|
72
|
-
DEFAULT_CHECK_NEW_VERSION_DAYS = 7
|
|
73
|
-
COFFEE_IMAGE_URL = 'https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg'
|
|
74
|
-
GEM_CHECK_DATE_FMT = '%Y/%m/%d'
|
|
75
|
-
# for testing only
|
|
76
|
-
SELF_SIGNED_CERT = OpenSSL::SSL.const_get(:enon_yfirev.to_s.upcase.reverse) # cspell: disable-line
|
|
77
|
-
CONF_OVERVIEW_KEYS = %w[preset parameter value].freeze
|
|
78
|
-
SMTP_CONF_PARAMS = %i[server tls ssl port domain username password from_name from_email].freeze
|
|
79
|
-
private_constant :DEFAULT_CONFIG_FILENAME,
|
|
80
|
-
:CONF_PRESET_CONFIG,
|
|
81
|
-
:CONF_PRESET_VERSION,
|
|
82
|
-
:CONF_PRESET_DEFAULTS,
|
|
83
|
-
:CONF_PRESET_GLOBAL,
|
|
84
|
-
:ASPERA_PLUGINS_FOLDERNAME,
|
|
85
|
-
:ASPERA,
|
|
86
|
-
:DEMO_SERVER,
|
|
87
|
-
:DEMO_PRESET,
|
|
88
|
-
:EMAIL_TEST_TEMPLATE,
|
|
89
|
-
:EXTEND_PRESET,
|
|
90
|
-
:EXTEND_VAULT,
|
|
91
|
-
:DEFAULT_CHECK_NEW_VERSION_DAYS,
|
|
92
|
-
:SERVER_COMMAND,
|
|
93
|
-
:PRESET_DIG_SEPARATOR,
|
|
94
|
-
:COFFEE_IMAGE_URL,
|
|
95
|
-
:SELF_SIGNED_CERT,
|
|
96
|
-
:PERSISTENCY_FOLDER,
|
|
97
|
-
:CONF_OVERVIEW_KEYS,
|
|
98
|
-
:SMTP_CONF_PARAMS
|
|
99
|
-
|
|
40
|
+
# Manage the CLI config file
|
|
41
|
+
class Config < Base
|
|
100
42
|
class << self
|
|
101
|
-
#
|
|
43
|
+
# Folder containing plugins in the gem's main folder
|
|
102
44
|
def gem_plugins_folder
|
|
103
45
|
File.dirname(File.expand_path(__FILE__))
|
|
104
46
|
end
|
|
105
47
|
|
|
106
48
|
# @return main folder where code is, i.e. .../lib
|
|
107
|
-
#
|
|
49
|
+
# Go up as many times as englobing modules (not counting class, as it is a file)
|
|
108
50
|
def gem_src_root
|
|
109
51
|
# Module.nesting[2] is Cli::Plugins
|
|
110
52
|
File.expand_path(Module.nesting[2].to_s.gsub('::', '/').gsub(%r{[^/]+}, '..'), gem_plugins_folder)
|
|
111
53
|
end
|
|
112
54
|
|
|
113
|
-
#
|
|
55
|
+
# Deep clone hash so that it does not get modified in case of display and secret hide
|
|
114
56
|
def deep_clone(val)
|
|
115
57
|
return Marshal.load(Marshal.dump(val))
|
|
116
58
|
end
|
|
117
59
|
|
|
118
|
-
# return product family folder (~/.aspera)
|
|
60
|
+
# @return product family folder (~/.aspera)
|
|
119
61
|
def module_family_folder
|
|
120
62
|
user_home_folder = Dir.home
|
|
121
63
|
Aspera.assert(Dir.exist?(user_home_folder), type: Cli::Error){"Home folder does not exist: #{user_home_folder}. Check your user environment."}
|
|
122
64
|
return File.join(user_home_folder, ASPERA_HOME_FOLDER_NAME)
|
|
123
65
|
end
|
|
124
66
|
|
|
125
|
-
# return
|
|
67
|
+
# @return [String] Product config folder (~/.aspera/<name>)
|
|
126
68
|
def default_app_main_folder(app_name:)
|
|
127
69
|
Aspera.assert_type(app_name, String)
|
|
128
70
|
Aspera.assert(!app_name.empty?)
|
|
@@ -131,7 +73,7 @@ module Aspera
|
|
|
131
73
|
end
|
|
132
74
|
|
|
133
75
|
def initialize(**_)
|
|
134
|
-
#
|
|
76
|
+
# We need to defer parsing of options until we have the config file, so we can use @extend with @preset
|
|
135
77
|
super
|
|
136
78
|
@use_plugin_defaults = true
|
|
137
79
|
@config_presets = nil
|
|
@@ -147,12 +89,12 @@ module Aspera
|
|
|
147
89
|
@option_cache_tokens = true
|
|
148
90
|
@main_folder = nil
|
|
149
91
|
@option_config_file = nil
|
|
150
|
-
#
|
|
92
|
+
# Store is used for ruby https
|
|
151
93
|
@certificate_store = nil
|
|
152
|
-
#
|
|
94
|
+
# Paths are used for ascp
|
|
153
95
|
@certificate_paths = nil
|
|
154
96
|
@progress_bar = nil
|
|
155
|
-
#
|
|
97
|
+
# Option to set main folder
|
|
156
98
|
options.declare(
|
|
157
99
|
:home, 'Home folder for tool',
|
|
158
100
|
handler: {o: self, m: :main_folder},
|
|
@@ -161,38 +103,38 @@ module Aspera
|
|
|
161
103
|
)
|
|
162
104
|
options.parse_options!
|
|
163
105
|
Log.log.debug{"#{Info::CMD_NAME} folder: #{@main_folder}"}
|
|
164
|
-
#
|
|
106
|
+
# Data persistency manager, created by config plugin, set for global object
|
|
165
107
|
context.persistency = PersistencyFolder.new(File.join(@main_folder, PERSISTENCY_FOLDER))
|
|
166
|
-
#
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
#
|
|
108
|
+
# Set folders for plugin lookup
|
|
109
|
+
Plugins::Factory.instance.add_lookup_folder(self.class.gem_plugins_folder)
|
|
110
|
+
Plugins::Factory.instance.add_lookup_folder(File.join(@main_folder, ASPERA_PLUGINS_FOLDERNAME))
|
|
111
|
+
# Option to set config file
|
|
170
112
|
options.declare(
|
|
171
113
|
:config_file, 'Path to YAML file with preset configuration',
|
|
172
114
|
handler: {o: self, m: :option_config_file},
|
|
173
115
|
default: File.join(@main_folder, DEFAULT_CONFIG_FILENAME)
|
|
174
116
|
)
|
|
175
117
|
options.parse_options!
|
|
176
|
-
#
|
|
118
|
+
# Read config file (set @config_presets)
|
|
177
119
|
read_config_file
|
|
178
|
-
#
|
|
120
|
+
# Add preset handler (needed for smtp)
|
|
179
121
|
ExtendedValue.instance.set_handler(EXTEND_PRESET, lambda{ |v| preset_by_name(v)})
|
|
180
122
|
ExtendedValue.instance.set_handler(EXTEND_VAULT, lambda{ |v| vault_value(v)})
|
|
181
|
-
#
|
|
123
|
+
# Load defaults before it can be overridden
|
|
182
124
|
add_plugin_default_preset(CONF_GLOBAL_SYM)
|
|
183
|
-
#
|
|
125
|
+
# Vault options
|
|
184
126
|
options.declare(:secret, 'Secret for access keys')
|
|
185
127
|
options.declare(:vault, 'Vault for secrets', types: Hash, default: {})
|
|
186
128
|
options.declare(:vault_password, 'Vault password')
|
|
187
129
|
options.parse_options!
|
|
188
|
-
#
|
|
189
|
-
|
|
190
|
-
#
|
|
130
|
+
# Declare generic plugin options only after handlers are declared
|
|
131
|
+
Base.declare_options(options)
|
|
132
|
+
# Configuration options
|
|
191
133
|
options.declare(:no_default, 'Do not load default configuration for plugin', values: :none, short: 'N'){@use_plugin_defaults = false}
|
|
192
134
|
options.declare(:preset, 'Load the named option preset from current config file', short: 'P', handler: {o: self, m: :option_preset})
|
|
193
135
|
options.declare(:version_check_days, 'Period in days to check new version (zero to disable)', coerce: Integer, default: DEFAULT_CHECK_NEW_VERSION_DAYS)
|
|
194
136
|
options.declare(:plugin_folder, 'Folder where to find additional plugins', handler: {o: self, m: :option_plugin_folder})
|
|
195
|
-
#
|
|
137
|
+
# Declare wizard options
|
|
196
138
|
@wizard = Wizard.new(self, @main_folder)
|
|
197
139
|
# Transfer SDK options
|
|
198
140
|
options.declare(:ascp_path, 'Ascp: Path to ascp', handler: {o: Ascp::Installation.instance, m: :ascp_path})
|
|
@@ -201,7 +143,7 @@ module Aspera
|
|
|
201
143
|
options.declare(:locations_url, 'Ascp: URL to get locations of Aspera Transfer Daemon', handler: {o: Ascp::Installation.instance, m: :transferd_urls})
|
|
202
144
|
options.declare(:sdk_folder, 'Ascp: SDK folder path', handler: {o: Products::Transferd, m: :sdk_directory})
|
|
203
145
|
options.declare(:progress_bar, 'Display progress bar', values: :bool, default: Environment.terminal?)
|
|
204
|
-
#
|
|
146
|
+
# Email options
|
|
205
147
|
options.declare(:smtp, 'Email: SMTP configuration', types: Hash)
|
|
206
148
|
options.declare(:notify_to, 'Email: Recipient for notification of transfers')
|
|
207
149
|
options.declare(:notify_template, 'Email: ERB template for notification of transfers')
|
|
@@ -222,21 +164,21 @@ module Aspera
|
|
|
222
164
|
if sdk_dir.nil?
|
|
223
165
|
@sdk_default_location = true
|
|
224
166
|
Log.log.debug('SDK folder is not set, checking default')
|
|
225
|
-
#
|
|
226
|
-
sdk_dir = self.class.default_app_main_folder(app_name:
|
|
227
|
-
Log.log.debug{"
|
|
167
|
+
# New location
|
|
168
|
+
sdk_dir = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME)
|
|
169
|
+
Log.log.debug{"Checking: #{sdk_dir}"}
|
|
228
170
|
if !Dir.exist?(sdk_dir)
|
|
229
|
-
Log.log.debug{"
|
|
230
|
-
#
|
|
231
|
-
former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: Info::CMD_NAME),
|
|
232
|
-
Log.log.debug{"
|
|
171
|
+
Log.log.debug{"No such folder: #{sdk_dir}"}
|
|
172
|
+
# Former location
|
|
173
|
+
former_sdk_folder = File.join(self.class.default_app_main_folder(app_name: Info::CMD_NAME), TRANSFERD_APP_NAME)
|
|
174
|
+
Log.log.debug{"Checking: #{former_sdk_folder}"}
|
|
233
175
|
sdk_dir = former_sdk_folder if Dir.exist?(former_sdk_folder)
|
|
234
176
|
end
|
|
235
|
-
Log.log.debug{"
|
|
177
|
+
Log.log.debug{"Using: #{sdk_dir}"}
|
|
236
178
|
Products::Transferd.sdk_directory = sdk_dir
|
|
237
179
|
end
|
|
238
180
|
pac_script = options.get_option(:fpac)
|
|
239
|
-
#
|
|
181
|
+
# Create PAC executor
|
|
240
182
|
if !pac_script.nil?
|
|
241
183
|
@pac_exec = ProxyAutoConfig.new(pac_script).register_uri_generic
|
|
242
184
|
proxy_user_pass = options.get_option(:proxy_credentials)
|
|
@@ -249,23 +191,54 @@ module Aspera
|
|
|
249
191
|
RestParameters.instance.user_agent = Info::CMD_NAME
|
|
250
192
|
RestParameters.instance.progress_bar = @progress_bar
|
|
251
193
|
RestParameters.instance.session_cb = lambda{ |http_session| update_http_session(http_session)}
|
|
252
|
-
|
|
194
|
+
# Check http options that are global
|
|
195
|
+
keys_to_delete = []
|
|
196
|
+
@option_http_options.each do |k, v|
|
|
253
197
|
method = "#{k}=".to_sym
|
|
254
|
-
RestParameters.instance.
|
|
255
|
-
|
|
198
|
+
if RestParameters.instance.respond_to?(method)
|
|
199
|
+
keys_to_delete.push(k)
|
|
200
|
+
RestParameters.instance.send(method, v)
|
|
201
|
+
elsif k.eql?('ssl_options')
|
|
202
|
+
keys_to_delete.push(k)
|
|
203
|
+
# NOTE: here is a hack that allows setting SSLContext options
|
|
204
|
+
Aspera.assert_type(v, Array){'ssl_options'}
|
|
205
|
+
# Start with default options
|
|
206
|
+
ssl_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
|
|
207
|
+
v.each do |opt|
|
|
208
|
+
case opt
|
|
209
|
+
when Integer
|
|
210
|
+
ssl_options = opt
|
|
211
|
+
when String
|
|
212
|
+
name = "OP_#{opt.start_with?('-') ? opt[1..] : opt}".upcase
|
|
213
|
+
raise Cli::BadArgument, "Unknown ssl_option: #{name}, use one of: #{OpenSSL::SSL.constants.grep(/^OP_/).map{ |c| c.to_s.sub(/^OP_/, '')}.join(', ')}" if !OpenSSL::SSL.const_defined?(name)
|
|
214
|
+
if opt.start_with?('-')
|
|
215
|
+
ssl_options &= ~OpenSSL::SSL.const_get(name)
|
|
216
|
+
else
|
|
217
|
+
ssl_options |= OpenSSL::SSL.const_get(name)
|
|
218
|
+
end
|
|
219
|
+
else
|
|
220
|
+
Aspera.error_unexpected_value(opt.class.name){'Expected String or Integer in ssl_options'}
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] = ssl_options
|
|
224
|
+
elsif OAuth::Factory.instance.parameters.key?(k.to_sym)
|
|
225
|
+
keys_to_delete.push(k)
|
|
226
|
+
OAuth::Factory.instance.parameters[k.to_sym] = v
|
|
227
|
+
end
|
|
256
228
|
end
|
|
229
|
+
keys_to_delete.each{ |k| @option_http_options.delete(k)}
|
|
257
230
|
OAuth::Factory.instance.persist_mgr = persistency if @option_cache_tokens
|
|
258
|
-
OAuth::Web.
|
|
231
|
+
OAuth::Web.additional_info = "#{Info::CMD_NAME} v#{Cli::VERSION}"
|
|
259
232
|
Transfer::Parameters.file_list_folder = File.join(@main_folder, 'filelists')
|
|
260
233
|
RestErrorAnalyzer.instance.log_file = File.join(@main_folder, 'rest_exceptions.log')
|
|
261
|
-
#
|
|
234
|
+
# Register aspera REST call error handlers
|
|
262
235
|
RestErrorsAspera.register_handlers
|
|
263
236
|
end
|
|
264
237
|
|
|
265
238
|
attr_accessor :main_folder, :option_cache_tokens, :option_insecure, :option_warn_insecure_cert, :option_http_options
|
|
266
239
|
attr_reader :option_ignore_cert_host_port, :progress_bar
|
|
267
240
|
|
|
268
|
-
#
|
|
241
|
+
# Add files, folders or default locations to the certificate store
|
|
269
242
|
# @param path_list [Array<String>] list of paths to add
|
|
270
243
|
# @return the list of paths
|
|
271
244
|
def trusted_cert_locations=(path_list)
|
|
@@ -307,14 +280,14 @@ module Aspera
|
|
|
307
280
|
@certificate_paths.uniq!
|
|
308
281
|
end
|
|
309
282
|
|
|
310
|
-
#
|
|
283
|
+
# @return only files
|
|
311
284
|
def trusted_cert_locations
|
|
312
285
|
locations = @certificate_paths
|
|
313
286
|
if locations.nil?
|
|
314
|
-
#
|
|
287
|
+
# Compute default locations
|
|
315
288
|
self.trusted_cert_locations = SpecialValues::DEF
|
|
316
289
|
locations = @certificate_paths
|
|
317
|
-
#
|
|
290
|
+
# Restore defaults
|
|
318
291
|
@certificate_paths = @certificate_store = nil
|
|
319
292
|
end
|
|
320
293
|
return locations
|
|
@@ -357,7 +330,7 @@ module Aspera
|
|
|
357
330
|
return ignore_cert
|
|
358
331
|
end
|
|
359
332
|
|
|
360
|
-
#
|
|
333
|
+
# Called every time a new REST HTTP session is opened to set user-provided options
|
|
361
334
|
# @param http_session [Net::HTTP] the newly created HTTP/S session object
|
|
362
335
|
def update_http_session(http_session)
|
|
363
336
|
http_session.set_debug_output(LineLogger.new(:trace2)) if Log.instance.logger.trace2?
|
|
@@ -367,38 +340,12 @@ module Aspera
|
|
|
367
340
|
Log.log.debug{"Using cert store #{http_session.cert_store} (#{@certificate_store})"} unless http_session.cert_store.nil?
|
|
368
341
|
@option_http_options.each do |k, v|
|
|
369
342
|
method = "#{k}=".to_sym
|
|
370
|
-
#
|
|
343
|
+
# Check if accessor is a method of Net::HTTP
|
|
371
344
|
# continue_timeout= read_timeout= write_timeout=
|
|
372
345
|
if http_session.respond_to?(method)
|
|
373
346
|
http_session.send(method, v)
|
|
374
|
-
elsif k.eql?('ssl_options')
|
|
375
|
-
# NOTE: here is a hack that allows setting SSLContext options
|
|
376
|
-
Aspera.assert_type(v, Array){'ssl_options'}
|
|
377
|
-
# more dynamic method, but more complex:
|
|
378
|
-
# Net::HTTP::SSL_ATTRIBUTES.push(:options) unless Net::HTTP::SSL_ATTRIBUTES.include?(:options)
|
|
379
|
-
# Net::HTTP::SSL_IVNAMES.push(:@options) unless Net::HTTP::SSL_IVNAMES.include?(:@options)
|
|
380
|
-
# Start with default options
|
|
381
|
-
ssl_options = OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options]
|
|
382
|
-
v.each do |opt|
|
|
383
|
-
case opt
|
|
384
|
-
when Integer
|
|
385
|
-
ssl_options = opt
|
|
386
|
-
when String
|
|
387
|
-
name = "OP_#{opt.start_with?('-') ? opt[1..] : opt}".upcase
|
|
388
|
-
raise Cli::BadArgument, "No such ssl_option: #{name}, use one of: #{OpenSSL::SSL.constants.grep(/^OP_/).map{ |c| c.to_s.sub(/^OP_/, '')}.join(', ')}" if !OpenSSL::SSL.const_defined?(name)
|
|
389
|
-
if opt.start_with?('-')
|
|
390
|
-
ssl_options &= ~OpenSSL::SSL.const_get(name)
|
|
391
|
-
else
|
|
392
|
-
ssl_options |= OpenSSL::SSL.const_get(name)
|
|
393
|
-
end
|
|
394
|
-
else
|
|
395
|
-
Aspera.error_unexpected_value(opt.class.name){'Expected String or Integer in ssl_options'}
|
|
396
|
-
end
|
|
397
|
-
end
|
|
398
|
-
# http_session.instance_variable_set(:@options, ssl_options)
|
|
399
|
-
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] = ssl_options
|
|
400
347
|
else
|
|
401
|
-
Log.log.error{"
|
|
348
|
+
Log.log.error{"Unknown HTTP session attribute: #{k}"}
|
|
402
349
|
end
|
|
403
350
|
end
|
|
404
351
|
end
|
|
@@ -426,35 +373,35 @@ module Aspera
|
|
|
426
373
|
end
|
|
427
374
|
|
|
428
375
|
def periodic_check_newer_gem_version
|
|
429
|
-
#
|
|
376
|
+
# Get verification period
|
|
430
377
|
delay_days = options.get_option(:version_check_days, mandatory: true).to_i
|
|
431
|
-
#
|
|
378
|
+
# Check only if not zero day
|
|
432
379
|
return if delay_days.eql?(0)
|
|
433
|
-
#
|
|
380
|
+
# Get last date from persistency
|
|
434
381
|
last_check_array = []
|
|
435
382
|
check_date_persist = PersistencyActionOnce.new(
|
|
436
383
|
manager: persistency,
|
|
437
384
|
data: last_check_array,
|
|
438
385
|
id: 'version_last_check'
|
|
439
386
|
)
|
|
440
|
-
#
|
|
387
|
+
# Get persisted date or nil
|
|
441
388
|
current_date = Date.today
|
|
442
389
|
last_check_days = (current_date - Date.strptime(last_check_array.first, GEM_CHECK_DATE_FMT)) rescue nil
|
|
443
390
|
Log.log.debug{"gem check new version: #{delay_days}, #{last_check_days}, #{current_date}, #{last_check_array}"}
|
|
444
391
|
return if !last_check_days.nil? && last_check_days < delay_days
|
|
445
|
-
#
|
|
392
|
+
# Generate timestamp
|
|
446
393
|
last_check_array[0] = current_date.strftime(GEM_CHECK_DATE_FMT)
|
|
447
394
|
check_date_persist.save
|
|
448
|
-
#
|
|
395
|
+
# Compare this version and the one on internet
|
|
449
396
|
check_data = check_gem_version
|
|
450
397
|
Log.log.warn do
|
|
451
398
|
"A new version is available: #{check_data[:latest]}. You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:name]}"
|
|
452
399
|
end if check_data[:need_update]
|
|
453
400
|
end
|
|
454
401
|
|
|
455
|
-
#
|
|
402
|
+
# Loads default parameters of plugin if no -P parameter
|
|
456
403
|
# and if there is a section defined for the plugin in the "default" section
|
|
457
|
-
#
|
|
404
|
+
# Try to find: conf[conf["default"][plugin_str]]
|
|
458
405
|
# @param plugin_name_sym : symbol for plugin name
|
|
459
406
|
def add_plugin_default_preset(plugin_name_sym)
|
|
460
407
|
default_config_name = get_plugin_default_config_name(plugin_name_sym)
|
|
@@ -463,7 +410,7 @@ module Aspera
|
|
|
463
410
|
return
|
|
464
411
|
end
|
|
465
412
|
|
|
466
|
-
#
|
|
413
|
+
# Get the default global preset, or set default one
|
|
467
414
|
def global_default_preset
|
|
468
415
|
result = get_plugin_default_config_name(CONF_GLOBAL_SYM)
|
|
469
416
|
if result.nil?
|
|
@@ -491,7 +438,7 @@ module Aspera
|
|
|
491
438
|
param_name = param_name.to_s
|
|
492
439
|
selected_preset = @config_presets[preset]
|
|
493
440
|
if selected_preset.nil?
|
|
494
|
-
Log.log.debug{"
|
|
441
|
+
Log.log.debug{"Unknown preset name: #{preset}, initializing"}
|
|
495
442
|
selected_preset = @config_presets[preset] = {}
|
|
496
443
|
end
|
|
497
444
|
Aspera.assert_type(selected_preset, Hash){"#{preset}.#{param_name}"}
|
|
@@ -507,8 +454,8 @@ module Aspera
|
|
|
507
454
|
nil
|
|
508
455
|
end
|
|
509
456
|
|
|
510
|
-
#
|
|
511
|
-
#
|
|
457
|
+
# Set parameter and value in global config
|
|
458
|
+
# Creates one if none already created
|
|
512
459
|
# @return preset name that contains global default
|
|
513
460
|
def set_global_default(key, value)
|
|
514
461
|
set_preset_key(global_default_preset, key, value)
|
|
@@ -523,13 +470,13 @@ module Aspera
|
|
|
523
470
|
# @return copy of the hash from name (also expands possible includes)
|
|
524
471
|
def preset_by_name(config_name, include_path = [])
|
|
525
472
|
raise Cli::Error, 'loop in include' if include_path.include?(config_name)
|
|
526
|
-
include_path = include_path.clone #
|
|
473
|
+
include_path = include_path.clone # Avoid messing up if there are multiple branches
|
|
527
474
|
current = @config_presets
|
|
528
475
|
config_name.split(PRESET_DIG_SEPARATOR).each do |name|
|
|
529
476
|
Aspera.assert_type(current, Hash, type: Cli::Error){"sub key: #{include_path}"}
|
|
530
477
|
include_path.push(name)
|
|
531
478
|
current = current[name]
|
|
532
|
-
raise Cli::Error, "
|
|
479
|
+
raise Cli::Error, "Unknown config preset: #{include_path}" if current.nil?
|
|
533
480
|
end
|
|
534
481
|
current = self.class.deep_clone(current) unless current.is_a?(String)
|
|
535
482
|
return ExtendedValue.instance.evaluate(current)
|
|
@@ -547,11 +494,11 @@ module Aspera
|
|
|
547
494
|
Aspera.assert_values(value.class, [String, Array]){'plugin folder'}
|
|
548
495
|
value = [value] if value.is_a?(String)
|
|
549
496
|
Aspera.assert(value.all?(String)){'plugin folder'}
|
|
550
|
-
value.each{ |f|
|
|
497
|
+
value.each{ |f| Plugins::Factory.instance.add_lookup_folder(f)}
|
|
551
498
|
end
|
|
552
499
|
|
|
553
500
|
def option_plugin_folder
|
|
554
|
-
return
|
|
501
|
+
return Plugins::Factory.instance.lookup_folders
|
|
555
502
|
end
|
|
556
503
|
|
|
557
504
|
def option_preset; 'write-only option'; end
|
|
@@ -571,14 +518,14 @@ module Aspera
|
|
|
571
518
|
JSON.generate(@config_presets).hash
|
|
572
519
|
end
|
|
573
520
|
|
|
574
|
-
#
|
|
521
|
+
# Read config file and validate format
|
|
575
522
|
def read_config_file
|
|
576
523
|
Log.log.debug{"config file is: #{@option_config_file}".red}
|
|
577
|
-
#
|
|
524
|
+
# Files search for configuration, by default the one given by user
|
|
578
525
|
search_files = [@option_config_file]
|
|
579
|
-
#
|
|
526
|
+
# Find first existing file (or nil)
|
|
580
527
|
conf_file_to_load = search_files.find{ |f| File.exist?(f)}
|
|
581
|
-
#
|
|
528
|
+
# If no file found, create default config
|
|
582
529
|
if conf_file_to_load.nil?
|
|
583
530
|
Log.log.warn{"No config file found. New configuration file: #{@option_config_file}"}
|
|
584
531
|
@config_presets = {CONF_PRESET_CONFIG => {CONF_PRESET_VERSION => 'new file'}}
|
|
@@ -591,16 +538,16 @@ module Aspera
|
|
|
591
538
|
files_to_copy = []
|
|
592
539
|
Log.dump(:available_presets, @config_presets, level: :trace1)
|
|
593
540
|
Aspera.assert_type(@config_presets, Hash){'config file YAML'}
|
|
594
|
-
#
|
|
541
|
+
# Check there is at least the config section
|
|
595
542
|
Aspera.assert(@config_presets.key?(CONF_PRESET_CONFIG)){"Cannot find key: #{CONF_PRESET_CONFIG}"}
|
|
596
543
|
version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]
|
|
597
544
|
raise Error, 'No version found in config section.' if version.nil?
|
|
598
545
|
Log.log.debug{"conf version: #{version}"}
|
|
599
546
|
# VVV if there are any conversion needed, those happen here.
|
|
600
|
-
#
|
|
547
|
+
# Fix bug in 4.4 (creating key "true" in "default" preset)
|
|
601
548
|
@config_presets[CONF_PRESET_DEFAULTS].delete(true) if @config_presets[CONF_PRESET_DEFAULTS].is_a?(Hash)
|
|
602
549
|
# ^^^ Place new compatibility code before this line
|
|
603
|
-
#
|
|
550
|
+
# Set version to current
|
|
604
551
|
@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = Cli::VERSION
|
|
605
552
|
unless files_to_copy.empty?
|
|
606
553
|
Log.log.warn('Copying referenced files')
|
|
@@ -615,7 +562,7 @@ module Aspera
|
|
|
615
562
|
rescue StandardError => e
|
|
616
563
|
Log.log.debug{"-> #{e.class.name} : #{e}"}
|
|
617
564
|
if File.exist?(@option_config_file)
|
|
618
|
-
#
|
|
565
|
+
# Then there is a problem with that file.
|
|
619
566
|
new_name = "#{@option_config_file}.pre#{Cli::VERSION}.manual_conversion_needed"
|
|
620
567
|
File.rename(@option_config_file, new_name)
|
|
621
568
|
Log.log.warn{"Renamed config file to #{new_name}."}
|
|
@@ -674,13 +621,13 @@ module Aspera
|
|
|
674
621
|
when :show
|
|
675
622
|
return Main.result_text(Ascp::Installation.instance.path(:ascp))
|
|
676
623
|
when :info
|
|
677
|
-
#
|
|
624
|
+
# Collect info from ascp executable
|
|
678
625
|
data = Ascp::Installation.instance.ascp_info
|
|
679
|
-
#
|
|
626
|
+
# Add command line transfer spec
|
|
680
627
|
data['ts'] = transfer.option_transfer_spec
|
|
681
|
-
#
|
|
628
|
+
# Add keys
|
|
682
629
|
DataRepository::ELEMENTS.each_with_object(data){ |i, h| h[i.to_s] = DataRepository.instance.item(i)}
|
|
683
|
-
#
|
|
630
|
+
# Declare those as secrets
|
|
684
631
|
SecretHider::ADDITIONAL_KEYS_TO_HIDE.concat(DataRepository::ELEMENTS.map(&:to_s))
|
|
685
632
|
return Main.result_single_object(data)
|
|
686
633
|
when :products
|
|
@@ -695,13 +642,13 @@ module Aspera
|
|
|
695
642
|
return Main.result_nothing
|
|
696
643
|
end
|
|
697
644
|
when :install
|
|
698
|
-
#
|
|
699
|
-
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name:
|
|
645
|
+
# Reset to default location, if older default was used
|
|
646
|
+
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME) if @sdk_default_location
|
|
700
647
|
version = options.get_next_argument('transferd version', mandatory: false)
|
|
701
648
|
n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
|
|
702
649
|
return Main.result_status("Installed #{n} version #{v}")
|
|
703
650
|
when :spec
|
|
704
|
-
fields, data = Transfer::SpecDoc.man_table(Formatter)
|
|
651
|
+
fields, data = Transfer::SpecDoc.man_table(Formatter, include_option: true)
|
|
705
652
|
return Main.result_object_list(data, fields: fields.map(&:to_s))
|
|
706
653
|
when :schema
|
|
707
654
|
schema = Transfer::Spec::SCHEMA.merge({'$comment'=>'DO NOT EDIT, this file was generated from the YAML.'})
|
|
@@ -711,7 +658,7 @@ module Aspera
|
|
|
711
658
|
return Main.result_single_object(schema)
|
|
712
659
|
when :errors
|
|
713
660
|
error_data = []
|
|
714
|
-
|
|
661
|
+
Ascp::Management::ERRORS.each_pair do |code, prop|
|
|
715
662
|
error_data.push(code: code, mnemonic: prop[:c], retry: prop[:r], info: prop[:a])
|
|
716
663
|
end
|
|
717
664
|
return Main.result_object_list(error_data)
|
|
@@ -724,8 +671,8 @@ module Aspera
|
|
|
724
671
|
command = options.get_next_command(%i[list install])
|
|
725
672
|
case command
|
|
726
673
|
when :install
|
|
727
|
-
#
|
|
728
|
-
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name:
|
|
674
|
+
# Reset to default location, if older default was used
|
|
675
|
+
Products::Transferd.sdk_directory = self.class.default_app_main_folder(app_name: TRANSFERD_APP_NAME) if @sdk_default_location
|
|
729
676
|
version = options.get_next_argument('transferd version', mandatory: false)
|
|
730
677
|
n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
|
|
731
678
|
return Main.result_status("Installed #{n} version #{v}")
|
|
@@ -740,9 +687,9 @@ module Aspera
|
|
|
740
687
|
Aspera.error_unreachable_line
|
|
741
688
|
end
|
|
742
689
|
|
|
743
|
-
#
|
|
690
|
+
# Legacy actions available globally
|
|
744
691
|
PRESET_GBL_ACTIONS = %i[list overview lookup secure].freeze
|
|
745
|
-
#
|
|
692
|
+
# Operations requiring that preset exists
|
|
746
693
|
PRESET_EXIST_ACTIONS = %i[show delete get unset].freeze
|
|
747
694
|
# require id
|
|
748
695
|
PRESET_INSTANCE_ACTIONS = %i[initialize update ask set].concat(PRESET_EXIST_ACTIONS).freeze
|
|
@@ -752,13 +699,13 @@ module Aspera
|
|
|
752
699
|
action = options.get_next_command(PRESET_ALL_ACTIONS) if action.nil?
|
|
753
700
|
name = instance_identifier if name.nil? && PRESET_INSTANCE_ACTIONS.include?(action)
|
|
754
701
|
name = global_default_preset if name.eql?(GLOBAL_DEFAULT_KEYWORD)
|
|
755
|
-
#
|
|
702
|
+
# Those operations require existing option
|
|
756
703
|
raise "no such preset: #{name}" if PRESET_EXIST_ACTIONS.include?(action) && !@config_presets.key?(name)
|
|
757
704
|
case action
|
|
758
705
|
when :list
|
|
759
706
|
return Main.result_value_list(@config_presets.keys, name: 'name')
|
|
760
707
|
when :overview
|
|
761
|
-
#
|
|
708
|
+
# Display process modifies the value (hide secrets): we do not want to save removed secrets
|
|
762
709
|
data = self.class.deep_clone(@config_presets)
|
|
763
710
|
formatter.hide_secrets(data)
|
|
764
711
|
result = []
|
|
@@ -812,7 +759,7 @@ module Aspera
|
|
|
812
759
|
end
|
|
813
760
|
return Main.result_status("Updated: #{name}")
|
|
814
761
|
when :lookup
|
|
815
|
-
|
|
762
|
+
BasicAuth.declare_options(options)
|
|
816
763
|
url = options.get_option(:url, mandatory: true)
|
|
817
764
|
user = options.get_option(:username, mandatory: true)
|
|
818
765
|
result = lookup_preset(url: url, username: user)
|
|
@@ -863,6 +810,7 @@ module Aspera
|
|
|
863
810
|
coffee
|
|
864
811
|
image
|
|
865
812
|
ascp
|
|
813
|
+
sync
|
|
866
814
|
transferd
|
|
867
815
|
email_test
|
|
868
816
|
smtp_settings
|
|
@@ -880,7 +828,7 @@ module Aspera
|
|
|
880
828
|
def execute_action
|
|
881
829
|
action = options.get_next_command(ACTIONS)
|
|
882
830
|
case action
|
|
883
|
-
when :preset #
|
|
831
|
+
when :preset # Newer syntax
|
|
884
832
|
return execute_preset
|
|
885
833
|
when :open
|
|
886
834
|
Environment.instance.open_editor(@option_config_file.to_s)
|
|
@@ -890,12 +838,12 @@ module Aspera
|
|
|
890
838
|
section = "##{section}" unless section.nil?
|
|
891
839
|
Environment.instance.open_uri("#{Info::DOC_URL}#{section}")
|
|
892
840
|
return Main.result_nothing
|
|
893
|
-
when :genkey #
|
|
841
|
+
when :genkey # Generate new rsa key
|
|
894
842
|
private_key_path = options.get_next_argument('private key file path')
|
|
895
843
|
private_key_length = options.get_next_argument('size in bits', mandatory: false, validation: Integer, default: OAuth::Jwt::DEFAULT_PRIV_KEY_LENGTH)
|
|
896
844
|
OAuth::Jwt.generate_rsa_private_key(path: private_key_path, length: private_key_length)
|
|
897
845
|
return Main.result_status("Generated #{private_key_length} bit RSA key: #{private_key_path}")
|
|
898
|
-
when :pubkey #
|
|
846
|
+
when :pubkey # Get pub key
|
|
899
847
|
private_key_pem = options.get_next_argument('private key PEM value')
|
|
900
848
|
return Main.result_text(OpenSSL::PKey::RSA.new(private_key_pem).public_key.to_s)
|
|
901
849
|
when :remote_certificate
|
|
@@ -911,7 +859,7 @@ module Aspera
|
|
|
911
859
|
when :name
|
|
912
860
|
return Main.result_text(remote_chain.first.subject.to_a.find{ |name, _, _| name == 'CN'}[1])
|
|
913
861
|
end
|
|
914
|
-
when :echo #
|
|
862
|
+
when :echo # Display the content of a value given on command line
|
|
915
863
|
return Main.result_auto(options.get_next_argument('value', validation: nil))
|
|
916
864
|
when :download
|
|
917
865
|
file_url = options.get_next_argument('source URL').chomp
|
|
@@ -929,20 +877,20 @@ module Aspera
|
|
|
929
877
|
return Main.result_object_list(OAuth::Factory.instance.persisted_tokens)
|
|
930
878
|
when :show
|
|
931
879
|
data = OAuth::Factory.instance.get_token_info(instance_identifier)
|
|
932
|
-
raise Cli::Error, '
|
|
880
|
+
raise Cli::Error, 'Unknown identifier' if data.nil?
|
|
933
881
|
return Main.result_single_object(data)
|
|
934
882
|
end
|
|
935
883
|
when :plugins
|
|
936
884
|
case options.get_next_command(%i[list create])
|
|
937
885
|
when :list
|
|
938
886
|
result = []
|
|
939
|
-
|
|
940
|
-
plugin_class =
|
|
887
|
+
Plugins::Factory.instance.plugin_list.each do |name|
|
|
888
|
+
plugin_class = Plugins::Factory.instance.plugin_class(name)
|
|
941
889
|
result.push({
|
|
942
890
|
plugin: name,
|
|
943
891
|
detect: Formatter.tick(plugin_class.respond_to?(:detect)),
|
|
944
|
-
wizard: Formatter.tick(plugin_class.
|
|
945
|
-
path:
|
|
892
|
+
wizard: Formatter.tick(plugin_class.instance_methods.include?(:wizard)),
|
|
893
|
+
path: Plugins::Factory.instance.plugin_source(name)
|
|
946
894
|
})
|
|
947
895
|
end
|
|
948
896
|
return Main.result_object_list(result, fields: %w[plugin detect wizard path])
|
|
@@ -951,25 +899,27 @@ module Aspera
|
|
|
951
899
|
destination_folder = options.get_next_argument('folder', mandatory: false) || File.join(@main_folder, ASPERA_PLUGINS_FOLDERNAME)
|
|
952
900
|
plugin_file = File.join(destination_folder, "#{plugin_name}.rb")
|
|
953
901
|
content = <<~END_OF_PLUGIN_CODE
|
|
954
|
-
require 'aspera/cli/
|
|
902
|
+
require 'aspera/cli/plugins/base'
|
|
955
903
|
module Aspera
|
|
956
904
|
module Cli
|
|
957
905
|
module Plugins
|
|
958
|
-
class #{plugin_name.
|
|
906
|
+
class #{plugin_name.snake_to_capital} < Base
|
|
959
907
|
ACTIONS=[]
|
|
960
|
-
def execute_action
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
908
|
+
def execute_action
|
|
909
|
+
return Main.result_status('You called plugin #{plugin_name}')
|
|
910
|
+
end
|
|
911
|
+
end
|
|
912
|
+
end
|
|
913
|
+
end
|
|
914
|
+
end
|
|
965
915
|
END_OF_PLUGIN_CODE
|
|
966
916
|
File.write(plugin_file, content)
|
|
967
917
|
return Main.result_status("Created #{plugin_file}")
|
|
968
918
|
end
|
|
969
919
|
when :detect, :wizard
|
|
970
|
-
#
|
|
920
|
+
# Interactive mode
|
|
971
921
|
options.ask_missing_mandatory = true
|
|
972
|
-
#
|
|
922
|
+
# Detect plugins by url and optional query
|
|
973
923
|
apps = @wizard.identify_plugins_for_url.freeze
|
|
974
924
|
return Main.result_object_list(apps) if action.eql?(:detect)
|
|
975
925
|
return @wizard.find(apps)
|
|
@@ -979,6 +929,13 @@ module Aspera
|
|
|
979
929
|
return Main.result_image(options.get_next_argument('image URI or blob'))
|
|
980
930
|
when :ascp
|
|
981
931
|
execute_action_ascp
|
|
932
|
+
when :sync
|
|
933
|
+
case options.get_next_command(%i[spec])
|
|
934
|
+
when :spec
|
|
935
|
+
fields, data = Transfer::SpecDoc.man_table(Formatter, include_option: true, agent_columns: false, schema: Sync::Operations::CONF_SCHEMA)
|
|
936
|
+
return Main.result_object_list(data, fields: fields.map(&:to_s))
|
|
937
|
+
else Aspera.error_unreachable_line
|
|
938
|
+
end
|
|
982
939
|
when :transferd
|
|
983
940
|
execute_action_transferd
|
|
984
941
|
when :gem
|
|
@@ -986,6 +943,7 @@ module Aspera
|
|
|
986
943
|
when :path then return Main.result_text(self.class.gem_src_root)
|
|
987
944
|
when :version then return Main.result_text(Cli::VERSION)
|
|
988
945
|
when :name then return Main.result_text(Info::GEM_NAME)
|
|
946
|
+
else Aspera.error_unreachable_line
|
|
989
947
|
end
|
|
990
948
|
when :folder
|
|
991
949
|
return Main.result_text(@main_folder)
|
|
@@ -997,7 +955,7 @@ module Aspera
|
|
|
997
955
|
when :smtp_settings
|
|
998
956
|
return Main.result_single_object(email_settings)
|
|
999
957
|
when :proxy_check
|
|
1000
|
-
#
|
|
958
|
+
# Ensure fpac was provided
|
|
1001
959
|
options.get_option(:fpac, mandatory: true)
|
|
1002
960
|
server_url = options.get_next_argument('server url')
|
|
1003
961
|
return Main.result_text(@pac_exec.get_proxies(server_url))
|
|
@@ -1035,11 +993,11 @@ module Aspera
|
|
|
1035
993
|
# @return [Hash] email server setting with defaults if not defined
|
|
1036
994
|
def email_settings
|
|
1037
995
|
smtp = options.get_option(:smtp, mandatory: true)
|
|
1038
|
-
#
|
|
996
|
+
# Change keys from string into symbol
|
|
1039
997
|
smtp = smtp.symbolize_keys
|
|
1040
998
|
unsupported = smtp.keys - SMTP_CONF_PARAMS
|
|
1041
999
|
raise Cli::Error, "Unsupported SMTP parameter: #{unsupported.join(', ')}, use: #{SMTP_CONF_PARAMS.join(', ')}" unless unsupported.empty?
|
|
1042
|
-
#
|
|
1000
|
+
# Defaults
|
|
1043
1001
|
# smtp[:ssl] = nil (false)
|
|
1044
1002
|
smtp[:tls] = !smtp[:ssl] unless smtp.key?(:tls)
|
|
1045
1003
|
smtp[:port] ||= if smtp[:tls]
|
|
@@ -1052,7 +1010,7 @@ module Aspera
|
|
|
1052
1010
|
smtp[:from_email] ||= smtp[:username] if smtp.key?(:username)
|
|
1053
1011
|
smtp[:from_name] ||= smtp[:from_email].sub(/@.*$/, '').gsub(/[^a-zA-Z]/, ' ').capitalize if smtp.key?(:username)
|
|
1054
1012
|
smtp[:domain] ||= smtp[:from_email].sub(/^.*@/, '') if smtp.key?(:from_email)
|
|
1055
|
-
#
|
|
1013
|
+
# Check minimum required
|
|
1056
1014
|
%i[server port domain].each do |n|
|
|
1057
1015
|
Aspera.assert(smtp.key?(n)){"Missing mandatory smtp parameter: #{n}"}
|
|
1058
1016
|
end
|
|
@@ -1060,8 +1018,8 @@ module Aspera
|
|
|
1060
1018
|
return smtp
|
|
1061
1019
|
end
|
|
1062
1020
|
|
|
1063
|
-
#
|
|
1064
|
-
# @param email_template_default [String] default template, can be
|
|
1021
|
+
# Send email using ERB template
|
|
1022
|
+
# @param email_template_default [String] default template, can be overridden by option
|
|
1065
1023
|
# @param values [Hash] values to be used in template, keys with default: to, from_name, from_email
|
|
1066
1024
|
def send_email_template(email_template_default: nil, values: {})
|
|
1067
1025
|
values[:to] ||= options.get_option(:notify_to, mandatory: true)
|
|
@@ -1074,14 +1032,14 @@ module Aspera
|
|
|
1074
1032
|
end
|
|
1075
1033
|
start_options = [mail_conf[:domain]]
|
|
1076
1034
|
start_options.push(mail_conf[:username], mail_conf[:password], :login) if mail_conf.key?(:username) && mail_conf.key?(:password)
|
|
1077
|
-
#
|
|
1035
|
+
# Create a binding with only variables defined in values
|
|
1078
1036
|
template_binding = Environment.empty_binding
|
|
1079
|
-
#
|
|
1037
|
+
# Add variables to binding
|
|
1080
1038
|
values.each do |k, v|
|
|
1081
1039
|
Aspera.assert_type(k, Symbol)
|
|
1082
1040
|
template_binding.local_variable_set(k, v)
|
|
1083
1041
|
end
|
|
1084
|
-
#
|
|
1042
|
+
# Execute template
|
|
1085
1043
|
msg_with_headers = ERB.new(notify_template).result(template_binding)
|
|
1086
1044
|
Log.dump(:msg_with_headers, msg_with_headers)
|
|
1087
1045
|
require 'net/smtp'
|
|
@@ -1095,7 +1053,7 @@ module Aspera
|
|
|
1095
1053
|
end
|
|
1096
1054
|
|
|
1097
1055
|
# Save current configuration to config file
|
|
1098
|
-
# return true if file was saved
|
|
1056
|
+
# @return true if file was saved
|
|
1099
1057
|
def save_config_file_if_needed
|
|
1100
1058
|
raise Error, 'no configuration loaded' if @config_presets.nil?
|
|
1101
1059
|
current_checksum = config_checksum
|
|
@@ -1109,29 +1067,35 @@ module Aspera
|
|
|
1109
1067
|
return true
|
|
1110
1068
|
end
|
|
1111
1069
|
|
|
1112
|
-
#
|
|
1113
|
-
#
|
|
1070
|
+
# @return [String] name if config_presets has default
|
|
1071
|
+
# @return nil if there is no config or bypass default params
|
|
1114
1072
|
def get_plugin_default_config_name(plugin_name_sym)
|
|
1115
1073
|
Aspera.assert(!@config_presets.nil?){'config_presets shall be defined'}
|
|
1116
1074
|
if !@use_plugin_defaults
|
|
1117
1075
|
Log.log.debug('skip default config')
|
|
1118
1076
|
return
|
|
1119
1077
|
end
|
|
1120
|
-
if
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1078
|
+
if !@config_presets.key?(CONF_PRESET_DEFAULTS)
|
|
1079
|
+
Log.log.debug('No default section')
|
|
1080
|
+
return
|
|
1081
|
+
end
|
|
1082
|
+
Aspera.assert_type(@config_presets[CONF_PRESET_DEFAULTS], Hash){'default section'}
|
|
1083
|
+
if !@config_presets[CONF_PRESET_DEFAULTS].key?(plugin_name_sym.to_s)
|
|
1084
|
+
Log.log.debug("No default for #{plugin_name_sym}")
|
|
1085
|
+
return
|
|
1086
|
+
end
|
|
1087
|
+
default_config_name = @config_presets[CONF_PRESET_DEFAULTS][plugin_name_sym.to_s]
|
|
1088
|
+
if !@config_presets.key?(default_config_name)
|
|
1089
|
+
Log.log.error do
|
|
1090
|
+
"Default config name [#{default_config_name}] specified for plugin [#{plugin_name_sym}], but it does not exist in config file.\n" \
|
|
1091
|
+
"Please fix the issue: either create preset with one parameter:\n" \
|
|
1092
|
+
"#{Info::CMD_NAME} config id #{default_config_name} init @json:'{}'\n" \
|
|
1093
|
+
"or remove default:\n#{Info::CMD_NAME} config id default remove #{plugin_name_sym}"
|
|
1130
1094
|
end
|
|
1131
|
-
raise Cli::Error, "
|
|
1132
|
-
return default_config_name
|
|
1095
|
+
raise Cli::Error, "No such preset: #{default_config_name}"
|
|
1133
1096
|
end
|
|
1134
|
-
|
|
1097
|
+
Aspera.assert_type(@config_presets[default_config_name], Hash, type: Cli::Error){'preset type'}
|
|
1098
|
+
return default_config_name
|
|
1135
1099
|
end
|
|
1136
1100
|
|
|
1137
1101
|
# @return [Hash] result of execution of vault command
|
|
@@ -1163,7 +1127,7 @@ module Aspera
|
|
|
1163
1127
|
def vault_value(name)
|
|
1164
1128
|
m = name.split('.')
|
|
1165
1129
|
raise BadArgument, 'vault name shall match <name>.<param>' unless m.length.eql?(2)
|
|
1166
|
-
#
|
|
1130
|
+
# This raise exception if label not found:
|
|
1167
1131
|
info = vault.get(label: m[0])
|
|
1168
1132
|
value = info[m[1].to_sym]
|
|
1169
1133
|
raise "no such entry value: #{m[1]}" if value.nil?
|
|
@@ -1184,12 +1148,12 @@ module Aspera
|
|
|
1184
1148
|
)
|
|
1185
1149
|
end
|
|
1186
1150
|
|
|
1187
|
-
#
|
|
1151
|
+
# Artificially raise an exception for tests
|
|
1188
1152
|
def execute_test
|
|
1189
1153
|
case options.get_next_command(%i[throw web])
|
|
1190
1154
|
when :throw
|
|
1191
1155
|
# :type [String]
|
|
1192
|
-
#
|
|
1156
|
+
# Options
|
|
1193
1157
|
exception_class_name = options.get_next_argument('exception class name', mandatory: true)
|
|
1194
1158
|
exception_text = options.get_next_argument('exception text', mandatory: true)
|
|
1195
1159
|
type = Object.const_get(exception_class_name)
|
|
@@ -1199,7 +1163,7 @@ module Aspera
|
|
|
1199
1163
|
end
|
|
1200
1164
|
end
|
|
1201
1165
|
|
|
1202
|
-
#
|
|
1166
|
+
# Version of URL without trailing "/" and removing default port
|
|
1203
1167
|
def canonical_url(url)
|
|
1204
1168
|
url.chomp('/').sub(%r{^(https://[^/]+):443$}, '\1')
|
|
1205
1169
|
end
|
|
@@ -1207,7 +1171,7 @@ module Aspera
|
|
|
1207
1171
|
# Look for a preset that has the corresponding URL and username
|
|
1208
1172
|
# @return the first one matching
|
|
1209
1173
|
def lookup_preset(url:, username:)
|
|
1210
|
-
#
|
|
1174
|
+
# Remove extra info to maximize match
|
|
1211
1175
|
url = canonical_url(url)
|
|
1212
1176
|
Log.log.debug{"Lookup preset for #{username}@#{url}"}
|
|
1213
1177
|
@config_presets.each_value do |v|
|
|
@@ -1232,6 +1196,71 @@ module Aspera
|
|
|
1232
1196
|
end
|
|
1233
1197
|
return secret
|
|
1234
1198
|
end
|
|
1199
|
+
# Private
|
|
1200
|
+
# Folder in $HOME for application files (config, cache)
|
|
1201
|
+
ASPERA_HOME_FOLDER_NAME = '.aspera'
|
|
1202
|
+
# Default config file
|
|
1203
|
+
DEFAULT_CONFIG_FILENAME = 'config.yaml'
|
|
1204
|
+
# Reserved preset names
|
|
1205
|
+
CONF_PRESET_CONFIG = 'config'
|
|
1206
|
+
CONF_PRESET_VERSION = 'version'
|
|
1207
|
+
CONF_PRESET_DEFAULTS = 'default'
|
|
1208
|
+
CONF_PRESET_GLOBAL = 'global_common_defaults'
|
|
1209
|
+
# Special name to identify value of default
|
|
1210
|
+
GLOBAL_DEFAULT_KEYWORD = 'GLOBAL'
|
|
1211
|
+
CONF_GLOBAL_SYM = :config
|
|
1212
|
+
# Folder containing custom plugins in user's config folder
|
|
1213
|
+
ASPERA_PLUGINS_FOLDERNAME = 'plugins'
|
|
1214
|
+
PERSISTENCY_FOLDER = 'persist_store'
|
|
1215
|
+
ASPERA = 'aspera'
|
|
1216
|
+
SERVER_COMMAND = 'server'
|
|
1217
|
+
TRANSFERD_APP_NAME = 'sdk'
|
|
1218
|
+
DEMO_SERVER = 'demo'
|
|
1219
|
+
DEMO_PRESET = 'demoserver' # cspell: disable-line
|
|
1220
|
+
EMAIL_TEST_TEMPLATE = <<~END_OF_TEMPLATE
|
|
1221
|
+
From: <%=from_name%> <<%=from_email%>>
|
|
1222
|
+
To: <<%=to%>>
|
|
1223
|
+
Subject: #{Info::GEM_NAME} email test
|
|
1224
|
+
|
|
1225
|
+
This email was sent to test #{Info::CMD_NAME}.
|
|
1226
|
+
END_OF_TEMPLATE
|
|
1227
|
+
# Special extended values
|
|
1228
|
+
EXTEND_PRESET = :preset
|
|
1229
|
+
EXTEND_VAULT = :vault
|
|
1230
|
+
PRESET_DIG_SEPARATOR = '.'
|
|
1231
|
+
DEFAULT_CHECK_NEW_VERSION_DAYS = 7
|
|
1232
|
+
COFFEE_IMAGE_URL = 'https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg'
|
|
1233
|
+
GEM_CHECK_DATE_FMT = '%Y/%m/%d'
|
|
1234
|
+
# For testing only
|
|
1235
|
+
SELF_SIGNED_CERT = OpenSSL::SSL.const_get(:enon_yfirev.to_s.upcase.reverse) # cspell: disable-line
|
|
1236
|
+
CONF_OVERVIEW_KEYS = %w[preset parameter value].freeze
|
|
1237
|
+
SMTP_CONF_PARAMS = %i[server tls ssl port domain username password from_name from_email].freeze
|
|
1238
|
+
|
|
1239
|
+
private_constant :ASPERA_HOME_FOLDER_NAME,
|
|
1240
|
+
:DEFAULT_CONFIG_FILENAME,
|
|
1241
|
+
:CONF_PRESET_CONFIG,
|
|
1242
|
+
:CONF_PRESET_VERSION,
|
|
1243
|
+
:CONF_PRESET_DEFAULTS,
|
|
1244
|
+
:CONF_PRESET_GLOBAL,
|
|
1245
|
+
:ASPERA_PLUGINS_FOLDERNAME,
|
|
1246
|
+
:ASPERA,
|
|
1247
|
+
:DEMO_SERVER,
|
|
1248
|
+
:DEMO_PRESET,
|
|
1249
|
+
:EMAIL_TEST_TEMPLATE,
|
|
1250
|
+
:EXTEND_PRESET,
|
|
1251
|
+
:EXTEND_VAULT,
|
|
1252
|
+
:DEFAULT_CHECK_NEW_VERSION_DAYS,
|
|
1253
|
+
:SERVER_COMMAND,
|
|
1254
|
+
:PRESET_DIG_SEPARATOR,
|
|
1255
|
+
:COFFEE_IMAGE_URL,
|
|
1256
|
+
:SELF_SIGNED_CERT,
|
|
1257
|
+
:PERSISTENCY_FOLDER,
|
|
1258
|
+
:CONF_OVERVIEW_KEYS,
|
|
1259
|
+
:SMTP_CONF_PARAMS,
|
|
1260
|
+
:TRANSFERD_APP_NAME,
|
|
1261
|
+
:GLOBAL_DEFAULT_KEYWORD,
|
|
1262
|
+
:CONF_GLOBAL_SYM,
|
|
1263
|
+
:GEM_CHECK_DATE_FMT
|
|
1235
1264
|
end
|
|
1236
1265
|
end
|
|
1237
1266
|
end
|