aspera-cli 4.5.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +1 -0
- data/README.md +1894 -1574
- data/bin/ascli +21 -1
- data/bin/asession +38 -34
- data/docs/test_env.conf +14 -3
- data/examples/aoc.rb +17 -15
- data/examples/dascli +26 -0
- data/examples/faspex4.rb +42 -35
- data/examples/proxy.pac +1 -1
- data/examples/transfer.rb +38 -37
- data/lib/aspera/aoc.rb +245 -205
- data/lib/aspera/ascmd.rb +111 -90
- data/lib/aspera/ats_api.rb +16 -14
- data/lib/aspera/cli/basic_auth_plugin.rb +19 -18
- data/lib/aspera/cli/extended_value.rb +50 -39
- data/lib/aspera/cli/formater.rb +161 -135
- data/lib/aspera/cli/info.rb +18 -0
- data/lib/aspera/cli/listener/line_dump.rb +4 -2
- data/lib/aspera/cli/listener/logger.rb +3 -1
- data/lib/aspera/cli/listener/progress.rb +20 -21
- data/lib/aspera/cli/listener/progress_multi.rb +29 -31
- data/lib/aspera/cli/main.rb +194 -183
- data/lib/aspera/cli/manager.rb +213 -206
- data/lib/aspera/cli/plugin.rb +71 -49
- data/lib/aspera/cli/plugins/alee.rb +8 -7
- data/lib/aspera/cli/plugins/aoc.rb +675 -558
- data/lib/aspera/cli/plugins/ats.rb +116 -109
- data/lib/aspera/cli/plugins/bss.rb +35 -34
- data/lib/aspera/cli/plugins/config.rb +722 -542
- data/lib/aspera/cli/plugins/console.rb +28 -22
- data/lib/aspera/cli/plugins/cos.rb +28 -37
- data/lib/aspera/cli/plugins/faspex.rb +281 -227
- data/lib/aspera/cli/plugins/faspex5.rb +129 -84
- data/lib/aspera/cli/plugins/node.rb +426 -232
- data/lib/aspera/cli/plugins/orchestrator.rb +106 -98
- data/lib/aspera/cli/plugins/preview.rb +196 -191
- data/lib/aspera/cli/plugins/server.rb +131 -126
- data/lib/aspera/cli/plugins/shares.rb +49 -36
- data/lib/aspera/cli/plugins/sync.rb +27 -28
- data/lib/aspera/cli/transfer_agent.rb +84 -79
- data/lib/aspera/cli/version.rb +3 -1
- data/lib/aspera/colors.rb +37 -28
- data/lib/aspera/command_line_builder.rb +84 -63
- data/lib/aspera/cos_node.rb +68 -34
- data/lib/aspera/data_repository.rb +4 -2
- data/lib/aspera/environment.rb +61 -46
- data/lib/aspera/fasp/agent_base.rb +36 -31
- data/lib/aspera/fasp/agent_connect.rb +44 -37
- data/lib/aspera/fasp/agent_direct.rb +101 -104
- data/lib/aspera/fasp/agent_httpgw.rb +91 -90
- data/lib/aspera/fasp/agent_node.rb +36 -33
- data/lib/aspera/fasp/agent_trsdk.rb +28 -31
- data/lib/aspera/fasp/error.rb +3 -1
- data/lib/aspera/fasp/error_info.rb +81 -54
- data/lib/aspera/fasp/installation.rb +171 -151
- data/lib/aspera/fasp/listener.rb +2 -0
- data/lib/aspera/fasp/parameters.rb +105 -111
- data/lib/aspera/fasp/parameters.yaml +305 -249
- data/lib/aspera/fasp/resume_policy.rb +20 -20
- data/lib/aspera/fasp/transfer_spec.rb +27 -0
- data/lib/aspera/fasp/uri.rb +31 -29
- data/lib/aspera/faspex_gw.rb +95 -118
- data/lib/aspera/hash_ext.rb +12 -13
- data/lib/aspera/id_generator.rb +11 -9
- data/lib/aspera/keychain/encrypted_hash.rb +73 -57
- data/lib/aspera/keychain/macos_security.rb +27 -29
- data/lib/aspera/log.rb +40 -39
- data/lib/aspera/nagios.rb +24 -22
- data/lib/aspera/node.rb +38 -30
- data/lib/aspera/oauth.rb +217 -248
- data/lib/aspera/open_application.rb +9 -7
- data/lib/aspera/persistency_action_once.rb +15 -14
- data/lib/aspera/persistency_folder.rb +15 -18
- data/lib/aspera/preview/file_types.rb +266 -270
- data/lib/aspera/preview/generator.rb +94 -92
- data/lib/aspera/preview/image_error.png +0 -0
- data/lib/aspera/preview/options.rb +20 -17
- data/lib/aspera/preview/utils.rb +99 -102
- data/lib/aspera/preview/video_error.png +0 -0
- data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
- data/lib/aspera/proxy_auto_config.rb +114 -21
- data/lib/aspera/rest.rb +144 -142
- data/lib/aspera/rest_call_error.rb +3 -2
- data/lib/aspera/rest_error_analyzer.rb +31 -31
- data/lib/aspera/rest_errors_aspera.rb +18 -16
- data/lib/aspera/secret_hider.rb +68 -0
- data/lib/aspera/ssh.rb +20 -16
- data/lib/aspera/sync.rb +57 -54
- data/lib/aspera/temp_file_manager.rb +20 -14
- data/lib/aspera/timer_limiter.rb +10 -8
- data/lib/aspera/uri_reader.rb +14 -15
- data/lib/aspera/web_auth.rb +85 -80
- data.tar.gz.sig +0 -0
- metadata +169 -40
- metadata.gz.sig +2 -0
- data/bin/dascli +0 -13
- data/docs/Makefile +0 -63
- data/docs/README.erb.md +0 -4221
- data/docs/README.md +0 -13
- data/docs/diagrams.txt +0 -49
- data/docs/doc_tools.rb +0 -58
- data/lib/aspera/cli/plugins/shares2.rb +0 -114
- data/lib/aspera/fasp/default.rb +0 -17
@@ -1,16 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'aspera/cli/basic_auth_plugin'
|
2
4
|
require 'aspera/cli/extended_value'
|
5
|
+
require 'aspera/cli/version'
|
6
|
+
require 'aspera/cli/formater'
|
3
7
|
require 'aspera/fasp/installation'
|
4
8
|
require 'aspera/fasp/parameters'
|
5
|
-
require 'aspera/
|
6
|
-
require 'aspera/
|
9
|
+
require 'aspera/fasp/transfer_spec'
|
10
|
+
require 'aspera/fasp/error_info'
|
7
11
|
require 'aspera/proxy_auto_config'
|
8
|
-
require 'aspera/
|
9
|
-
require 'aspera/rest'
|
12
|
+
require 'aspera/open_application'
|
10
13
|
require 'aspera/persistency_action_once'
|
11
14
|
require 'aspera/id_generator'
|
12
15
|
require 'aspera/keychain/encrypted_hash'
|
13
16
|
require 'aspera/keychain/macos_security'
|
17
|
+
require 'aspera/aoc'
|
18
|
+
require 'aspera/rest'
|
14
19
|
require 'xmlsimple'
|
15
20
|
require 'base64'
|
16
21
|
require 'net/smtp'
|
@@ -24,185 +29,207 @@ module Aspera
|
|
24
29
|
# manage the CLI config file
|
25
30
|
class Config < Plugin
|
26
31
|
# folder in $HOME for application files (config, cache)
|
27
|
-
ASPERA_HOME_FOLDER_NAME='.aspera'
|
32
|
+
ASPERA_HOME_FOLDER_NAME = '.aspera'
|
28
33
|
# default config file
|
29
34
|
DEFAULT_CONFIG_FILENAME = 'config.yaml'
|
30
35
|
# reserved preset names
|
31
|
-
CONF_PRESET_CONFIG='config'
|
32
|
-
CONF_PRESET_VERSION='version'
|
33
|
-
CONF_PRESET_DEFAULT='default'
|
34
|
-
CONF_PRESET_GLOBAL='global_common_defaults'
|
35
|
-
CONF_PRESET_SECRETS='default_secrets'
|
36
|
+
CONF_PRESET_CONFIG = 'config'
|
37
|
+
CONF_PRESET_VERSION = 'version'
|
38
|
+
CONF_PRESET_DEFAULT = 'default'
|
39
|
+
CONF_PRESET_GLOBAL = 'global_common_defaults'
|
40
|
+
CONF_PRESET_SECRETS = 'default_secrets' # pragma: allowlist secret
|
36
41
|
CONF_PLUGIN_SYM = :config # Plugins::Config.name.split('::').last.downcase.to_sym
|
37
42
|
CONF_GLOBAL_SYM = :config
|
38
43
|
# old tool name
|
39
44
|
PROGRAM_NAME_V1 = 'aslmcli'
|
40
45
|
PROGRAM_NAME_V2 = 'mlia'
|
41
46
|
# default redirect for AoC web auth
|
42
|
-
DEFAULT_REDIRECT='http://localhost:12345'
|
47
|
+
DEFAULT_REDIRECT = 'http://localhost:12345'
|
43
48
|
# folder containing custom plugins in user's config folder
|
44
|
-
ASPERA_PLUGINS_FOLDERNAME='plugins'
|
45
|
-
RUBY_FILE_EXT='.rb'
|
46
|
-
AOC_COMMAND_V1='files'
|
47
|
-
AOC_COMMAND_V2='aspera'
|
48
|
-
AOC_COMMAND_V3='aoc'
|
49
|
-
AOC_COMMAND_CURRENT=AOC_COMMAND_V3
|
50
|
-
SERVER_COMMAND='server'
|
49
|
+
ASPERA_PLUGINS_FOLDERNAME = 'plugins'
|
50
|
+
RUBY_FILE_EXT = '.rb'
|
51
|
+
AOC_COMMAND_V1 = 'files'
|
52
|
+
AOC_COMMAND_V2 = 'aspera'
|
53
|
+
AOC_COMMAND_V3 = 'aoc'
|
54
|
+
AOC_COMMAND_CURRENT = AOC_COMMAND_V3
|
55
|
+
SERVER_COMMAND = 'server'
|
51
56
|
CONNECT_WEB_URL = 'https://d3gcli72yxqn2z.cloudfront.net/connect'
|
52
57
|
CONNECT_VERSIONS = 'connectversions.js'
|
53
58
|
TRANSFER_SDK_ARCHIVE_URL = 'https://ibm.biz/aspera_transfer_sdk'
|
54
|
-
DEMO='demo'
|
55
|
-
DEMO_SERVER_PRESET='demoserver'
|
56
|
-
AOC_PATH_API_CLIENTS='admin/api-clients'
|
57
|
-
EMAIL_TEST_TEMPLATE
|
58
|
-
From: <%=from_name%> <<%=from_email%>>
|
59
|
-
To: <<%=to%>>
|
60
|
-
Subject: Amelia email test
|
59
|
+
DEMO = 'demo'
|
60
|
+
DEMO_SERVER_PRESET = 'demoserver'
|
61
|
+
AOC_PATH_API_CLIENTS = 'admin/api-clients'
|
62
|
+
EMAIL_TEST_TEMPLATE = <<~END_OF_TEMPLATE
|
63
|
+
From: <%=from_name%> <<%=from_email%>>
|
64
|
+
To: <<%=to%>>
|
65
|
+
Subject: Amelia email test
|
61
66
|
|
62
|
-
It worked !
|
63
|
-
END_OF_TEMPLATE
|
67
|
+
It worked !
|
68
|
+
END_OF_TEMPLATE
|
64
69
|
# special extended values
|
65
|
-
EXTV_INCLUDE_PRESETS=
|
66
|
-
EXTV_PRESET=
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
+
EXTV_INCLUDE_PRESETS = :incps
|
71
|
+
EXTV_PRESET = :preset
|
72
|
+
PRESET_DIG_SEPARATOR = '.'
|
73
|
+
DEFAULT_CHECK_NEW_VERSION_DAYS = 7
|
74
|
+
DEFAULT_PRIV_KEY_FILENAME = 'aspera_aoc_key' # pragma: allowlist secret
|
75
|
+
DEFAULT_PRIVKEY_LENGTH = 4096
|
70
76
|
private_constant :DEFAULT_CONFIG_FILENAME,:CONF_PRESET_CONFIG,:CONF_PRESET_VERSION,:CONF_PRESET_DEFAULT,
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
when String
|
80
|
-
self.options.add_option_preset(preset_by_name(value))
|
81
|
-
when Hash
|
82
|
-
self.options.add_option_preset(value)
|
83
|
-
else
|
84
|
-
raise "Preset definition must be a String for name, or Hash for value"
|
85
|
-
end
|
86
|
-
nil
|
87
|
-
end
|
88
|
-
|
89
|
-
def initialize(env,tool_name,help_url,version,main_folder)
|
77
|
+
:CONF_PRESET_GLOBAL,:PROGRAM_NAME_V1,:PROGRAM_NAME_V2,:DEFAULT_REDIRECT,:ASPERA_PLUGINS_FOLDERNAME,
|
78
|
+
:RUBY_FILE_EXT,:AOC_COMMAND_V1,:AOC_COMMAND_V2,:AOC_COMMAND_V3,:AOC_COMMAND_CURRENT,:DEMO,
|
79
|
+
:TRANSFER_SDK_ARCHIVE_URL,:AOC_PATH_API_CLIENTS,:DEMO_SERVER_PRESET,:EMAIL_TEST_TEMPLATE,:EXTV_INCLUDE_PRESETS,
|
80
|
+
:EXTV_PRESET,:DEFAULT_CHECK_NEW_VERSION_DAYS,:DEFAULT_PRIV_KEY_FILENAME,:SERVER_COMMAND,:CONF_PRESET_SECRETS,
|
81
|
+
:PRESET_DIG_SEPARATOR
|
82
|
+
def initialize(env,params)
|
83
|
+
raise 'env and params must be Hash' unless env.is_a?(Hash) && params.is_a?(Hash)
|
84
|
+
raise 'missing param' unless %i[name help version gem].sort.eql?(params.keys.sort)
|
90
85
|
super(env)
|
91
|
-
@
|
92
|
-
@
|
93
|
-
@
|
94
|
-
@
|
95
|
-
@
|
96
|
-
@
|
97
|
-
@
|
98
|
-
@
|
99
|
-
@
|
100
|
-
@
|
101
|
-
@
|
102
|
-
@
|
103
|
-
Log.log.debug("#{tool_name} folder: #{@main_folder}")
|
86
|
+
@info = params
|
87
|
+
@main_folder = default_app_main_folder
|
88
|
+
@plugins = {}
|
89
|
+
@plugin_lookup_folders = []
|
90
|
+
@use_plugin_defaults = true
|
91
|
+
@config_presets = nil
|
92
|
+
@connect_versions = nil
|
93
|
+
@vault = nil
|
94
|
+
@conf_file_default = File.join(@main_folder,DEFAULT_CONFIG_FILENAME)
|
95
|
+
@option_config_file = @conf_file_default
|
96
|
+
@pac_exec = nil
|
97
|
+
Log.log.debug("#{@info[:name]} folder: #{@main_folder}")
|
104
98
|
# set folder for FASP SDK
|
105
|
-
add_plugin_lookup_folder(File.join(@main_folder,ASPERA_PLUGINS_FOLDERNAME))
|
106
99
|
add_plugin_lookup_folder(self.class.gem_plugins_folder)
|
100
|
+
add_plugin_lookup_folder(File.join(@main_folder,ASPERA_PLUGINS_FOLDERNAME))
|
107
101
|
# do file parameter first
|
108
|
-
|
109
|
-
|
110
|
-
|
102
|
+
options.set_obj_attr(:config_file,self,:option_config_file)
|
103
|
+
options.add_opt_simple(:config_file,"read parameters from file in YAML format, current=#{@option_config_file}")
|
104
|
+
options.parse_options!
|
111
105
|
# read correct file
|
112
106
|
read_config_file
|
113
107
|
# add preset handler (needed for smtp)
|
114
108
|
ExtendedValue.instance.set_handler(EXTV_PRESET,:reader,lambda{|v|preset_by_name(v)})
|
115
109
|
ExtendedValue.instance.set_handler(EXTV_INCLUDE_PRESETS,:decoder,lambda{|v|expanded_with_preset_includes(v)})
|
116
110
|
# load defaults before it can be overriden
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
111
|
+
add_plugin_default_preset(CONF_GLOBAL_SYM)
|
112
|
+
options.parse_options!
|
113
|
+
options.set_obj_attr(:ascp_path,Fasp::Installation.instance,:ascp_path)
|
114
|
+
options.set_obj_attr(:sdk_folder,Fasp::Installation.instance,:sdk_folder)
|
115
|
+
options.set_obj_attr(:use_product,self,:option_use_product)
|
116
|
+
options.set_obj_attr(:preset,self,:option_preset)
|
117
|
+
options.set_obj_attr(:plugin_folder,self,:option_plugin_folder)
|
118
|
+
options.add_opt_switch(:no_default,'-N','do not load default configuration for plugin') { @use_plugin_defaults = false }
|
119
|
+
options.add_opt_boolean(:override,'Wizard: override existing value')
|
120
|
+
options.add_opt_boolean(:use_generic_client,'Wizard: AoC: use global or org specific jwt client id')
|
121
|
+
options.add_opt_boolean(:default,'Wizard: set as default configuration for specified plugin (also: update)')
|
122
|
+
options.add_opt_boolean(:test_mode,'Wizard: skip private key check step')
|
123
|
+
options.add_opt_simple(:preset,'-PVALUE','load the named option preset from current config file')
|
124
|
+
options.add_opt_simple(:pkeypath,'Wizard: path to private key for JWT')
|
125
|
+
options.add_opt_simple(:ascp_path,'path to ascp')
|
126
|
+
options.add_opt_simple(:use_product,'use ascp from specified product')
|
127
|
+
options.add_opt_simple(:smtp,'smtp configuration (extended value: hash)')
|
128
|
+
options.add_opt_simple(:fpac,'proxy auto configuration script')
|
129
|
+
options.add_opt_simple(:secret,'default secret')
|
130
|
+
options.add_opt_simple(:secrets,'secret vault')
|
131
|
+
options.add_opt_simple(:sdk_url,'URL to get SDK')
|
132
|
+
options.add_opt_simple(:sdk_folder,'SDK folder path')
|
133
|
+
options.add_opt_simple(:notif_to,'email recipient for notification of transfers')
|
134
|
+
options.add_opt_simple(:notif_template,'email ERB template for notification of transfers')
|
135
|
+
options.add_opt_simple(:version_check_days,Integer,'period in days to check new version (zero to disable)')
|
136
|
+
options.add_opt_simple(:plugin_folder,'folder where to find additional plugins')
|
137
|
+
options.set_option(:use_generic_client,true)
|
138
|
+
options.set_option(:test_mode,false)
|
139
|
+
options.set_option(:default,true)
|
140
|
+
options.set_option(:version_check_days,DEFAULT_CHECK_NEW_VERSION_DAYS)
|
141
|
+
options.set_option(:sdk_url,TRANSFER_SDK_ARCHIVE_URL)
|
142
|
+
options.set_option(:sdk_folder,File.join(@main_folder,'sdk'))
|
143
|
+
options.set_option(:override,:no)
|
144
|
+
options.parse_options!
|
145
|
+
pac_script = options.get_option(:fpac)
|
146
|
+
# create PAC executor
|
147
|
+
@pac_exec = Aspera::ProxyAutoConfig.new(pac_script).register_uri_generic unless pac_script.nil?
|
148
|
+
end
|
149
|
+
|
150
|
+
# env var name to override the app's main folder
|
151
|
+
# default main folder is $HOME/<vendor main app folder>/<program name>
|
152
|
+
def conf_dir_env_var
|
153
|
+
return "#{@info[:name]}_home".upcase
|
154
|
+
end
|
155
|
+
|
156
|
+
def default_app_main_folder
|
157
|
+
# find out application main folder
|
158
|
+
app_folder = ENV[conf_dir_env_var]
|
159
|
+
# if env var undefined or empty
|
160
|
+
if app_folder.nil? || app_folder.empty?
|
161
|
+
user_home_folder = Dir.home
|
162
|
+
raise CliError,"Home folder does not exist: #{user_home_folder}. Check your user environment or use #{conf_dir_env_var}." unless Dir.exist?(user_home_folder)
|
163
|
+
app_folder = File.join(user_home_folder,ASPERA_HOME_FOLDER_NAME,@info[:name])
|
164
|
+
end
|
165
|
+
return app_folder
|
149
166
|
end
|
150
167
|
|
151
168
|
def check_gem_version
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
169
|
+
latest_version =
|
170
|
+
begin
|
171
|
+
Rest.new(base_url: 'https://rubygems.org/api/v1').read("versions/#{@info[:gem]}/latest.json")[:data]['version']
|
172
|
+
rescue StandardError
|
173
|
+
Log.log.warn('Could not retrieve latest gem version on rubygems.')
|
174
|
+
'0'
|
175
|
+
end
|
176
|
+
if Gem::Version.new(Environment.ruby_version) < Gem::Version.new(RUBY_FUTURE_MINIMUM_VERSION)
|
177
|
+
Log.log.warn("Note that a future version will require Ruby version #{RUBY_FUTURE_MINIMUM_VERSION} at minimum, "\
|
178
|
+
"you are using #{Environment.ruby_version}")
|
158
179
|
end
|
159
|
-
return {
|
180
|
+
return {
|
181
|
+
name: @info[:gem],
|
182
|
+
current: Aspera::Cli::VERSION,
|
183
|
+
latest: latest_version,
|
184
|
+
need_update: Gem::Version.new(Aspera::Cli::VERSION) < Gem::Version.new(latest_version)
|
185
|
+
}
|
160
186
|
end
|
161
187
|
|
162
188
|
def periodic_check_newer_gem_version
|
163
189
|
# get verification period
|
164
|
-
delay_days=options.get_option(:version_check_days
|
190
|
+
delay_days = options.get_option(:version_check_days,is_type: :mandatory)
|
165
191
|
Log.log.info("check days: #{delay_days}")
|
166
192
|
# check only if not zero day
|
167
|
-
if
|
168
|
-
|
169
|
-
|
170
|
-
|
193
|
+
return if delay_days.eql?(0)
|
194
|
+
# get last date from persistency
|
195
|
+
last_check_array = []
|
196
|
+
check_date_persist = PersistencyActionOnce.new(
|
171
197
|
manager: persistency,
|
172
198
|
data: last_check_array,
|
173
199
|
id: 'version_last_check')
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
200
|
+
# get persisted date or nil
|
201
|
+
current_date = Date.today
|
202
|
+
last_check_days =
|
203
|
+
begin
|
204
|
+
current_date - Date.strptime(last_check_array.first, '%Y/%m/%d')
|
205
|
+
rescue StandardError
|
206
|
+
# negative value will force check
|
207
|
+
-1
|
179
208
|
end
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
end
|
190
|
-
end
|
209
|
+
Log.log.debug("days elapsed: #{last_check_days}")
|
210
|
+
return if last_check_days < delay_days
|
211
|
+
# generate timestamp
|
212
|
+
last_check_array[0] = current_date.strftime('%Y/%m/%d')
|
213
|
+
check_date_persist.save
|
214
|
+
# compare this version and the one on internet
|
215
|
+
check_data = check_gem_version
|
216
|
+
Log.log.warn("A new version is available: #{check_data[:latest]}. "\
|
217
|
+
"You have #{check_data[:current]}. Upgrade with: gem update #{check_data[:name]}") if check_data[:need_update]
|
191
218
|
end
|
192
219
|
|
193
220
|
# retrieve structure from cloud (CDN) with all versions available
|
194
221
|
def connect_versions
|
195
222
|
if @connect_versions.nil?
|
196
|
-
api_connect_cdn=Rest.new({base_url: CONNECT_WEB_URL})
|
197
|
-
javascript=api_connect_cdn.call({operation: 'GET',subpath: CONNECT_VERSIONS})
|
223
|
+
api_connect_cdn = Rest.new({base_url: CONNECT_WEB_URL})
|
224
|
+
javascript = api_connect_cdn.call({operation: 'GET',subpath: CONNECT_VERSIONS})
|
198
225
|
# get result on one line
|
199
|
-
connect_versions_javascript=javascript[:http].body.gsub(/\r?\n\s*/,'')
|
226
|
+
connect_versions_javascript = javascript[:http].body.gsub(/\r?\n\s*/,'')
|
200
227
|
Log.log.debug("javascript=[\n#{connect_versions_javascript}\n]")
|
201
228
|
# get javascript object only
|
202
|
-
found=connect_versions_javascript.match(/^.*? = (.*);/)
|
229
|
+
found = connect_versions_javascript.match(/^.*? = (.*);/)
|
203
230
|
raise CliError,'Problen when getting connect versions from internet' if found.nil?
|
204
|
-
alldata=JSON.parse(found[1])
|
205
|
-
@connect_versions=alldata['entries']
|
231
|
+
alldata = JSON.parse(found[1])
|
232
|
+
@connect_versions = alldata['entries']
|
206
233
|
end
|
207
234
|
return @connect_versions
|
208
235
|
end
|
@@ -212,47 +239,46 @@ END_OF_TEMPLATE
|
|
212
239
|
# try to find: conffile[conffile["default"][plugin_str]]
|
213
240
|
# @param plugin_name_sym : symbol for plugin name
|
214
241
|
def add_plugin_default_preset(plugin_name_sym)
|
215
|
-
default_config_name=get_plugin_default_config_name(plugin_name_sym)
|
242
|
+
default_config_name = get_plugin_default_config_name(plugin_name_sym)
|
216
243
|
Log.log.debug("add_plugin_default_preset:#{plugin_name_sym}:#{default_config_name}")
|
217
|
-
|
244
|
+
options.add_option_preset(preset_by_name(default_config_name),op: :unshift) unless default_config_name.nil?
|
218
245
|
return nil
|
219
246
|
end
|
247
|
+
|
220
248
|
private
|
221
249
|
|
222
250
|
def generate_rsa_private_key(private_key_path,length)
|
223
251
|
require 'openssl'
|
224
252
|
priv_key = OpenSSL::PKey::RSA.new(length)
|
225
253
|
File.write(private_key_path,priv_key.to_s)
|
226
|
-
File.write(private_key_path+'.pub',priv_key.public_key.to_s)
|
254
|
+
File.write(private_key_path + '.pub',priv_key.public_key.to_s)
|
227
255
|
nil
|
228
256
|
end
|
229
257
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
258
|
+
class << self
|
259
|
+
# folder containing plugins in the gem's main folder
|
260
|
+
def gem_plugins_folder
|
261
|
+
File.dirname(File.expand_path(__FILE__))
|
262
|
+
end
|
234
263
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
264
|
+
# name of englobin module
|
265
|
+
# @return "Aspera::Cli::Plugins"
|
266
|
+
def module_full_name
|
267
|
+
return Module.nesting[2].to_s
|
268
|
+
end
|
240
269
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
end
|
270
|
+
# @return main folder where code is, i.e. .../lib
|
271
|
+
# go up as many times as englobing modules (not counting class, as it is a file)
|
272
|
+
def gem_src_root
|
273
|
+
File.expand_path(module_full_name.gsub('::','/').gsub(%r{[^/]+},'..'),gem_plugins_folder)
|
274
|
+
end
|
247
275
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
end
|
276
|
+
# instanciate a plugin
|
277
|
+
# plugins must be Capitalized
|
278
|
+
def plugin_class(plugin_name_sym)
|
279
|
+
# Module.nesting[2] is Aspera::Cli::Plugins
|
280
|
+
return Object.const_get("#{module_full_name}::#{plugin_name_sym.to_s.capitalize}")
|
254
281
|
end
|
255
|
-
return r
|
256
282
|
end
|
257
283
|
|
258
284
|
# set parameter and value in global config
|
@@ -260,14 +286,14 @@ END_OF_TEMPLATE
|
|
260
286
|
# @return preset name that contains global default
|
261
287
|
def set_global_default(key,value)
|
262
288
|
# get default preset if it exists
|
263
|
-
global_default_preset_name=get_plugin_default_config_name(CONF_GLOBAL_SYM)
|
289
|
+
global_default_preset_name = get_plugin_default_config_name(CONF_GLOBAL_SYM)
|
264
290
|
if global_default_preset_name.nil?
|
265
|
-
global_default_preset_name=CONF_PRESET_GLOBAL
|
266
|
-
@config_presets[CONF_PRESET_DEFAULT]||={}
|
267
|
-
@config_presets[CONF_PRESET_DEFAULT][CONF_GLOBAL_SYM.to_s]=global_default_preset_name
|
291
|
+
global_default_preset_name = CONF_PRESET_GLOBAL
|
292
|
+
@config_presets[CONF_PRESET_DEFAULT] ||= {}
|
293
|
+
@config_presets[CONF_PRESET_DEFAULT][CONF_GLOBAL_SYM.to_s] = global_default_preset_name
|
268
294
|
end
|
269
|
-
@config_presets[global_default_preset_name]||={}
|
270
|
-
@config_presets[global_default_preset_name][key.to_s]=value
|
295
|
+
@config_presets[global_default_preset_name] ||= {}
|
296
|
+
@config_presets[global_default_preset_name][key.to_s] = value
|
271
297
|
self.format.display_status("Updated: #{global_default_preset_name}: #{key} <- #{value}")
|
272
298
|
save_presets_to_config_file
|
273
299
|
return global_default_preset_name
|
@@ -277,27 +303,41 @@ END_OF_TEMPLATE
|
|
277
303
|
|
278
304
|
# $HOME/.aspera/`program_name`
|
279
305
|
attr_reader :main_folder
|
280
|
-
attr_reader :gem_url
|
281
|
-
attr_reader :plugins
|
306
|
+
attr_reader :gem_url, :plugins
|
282
307
|
attr_accessor :option_config_file
|
283
308
|
|
284
309
|
# @return the hash from name (also expands possible includes)
|
310
|
+
# @param config_name name of the preset in config file
|
311
|
+
# @param include_path used to detect and avoid include loops
|
285
312
|
def preset_by_name(config_name, include_path=[])
|
286
|
-
raise CliError,"no such config preset: #{config_name}" unless @config_presets.has_key?(config_name)
|
287
313
|
raise CliError,'loop in include' if include_path.include?(config_name)
|
288
|
-
|
314
|
+
include_path = include_path.clone # avoid messing up if there are multiple branches
|
315
|
+
current = @config_presets
|
316
|
+
config_name.split(PRESET_DIG_SEPARATOR).each do |name|
|
317
|
+
raise CliError,"not a Hash: #{include_path} (#{current.class})" unless current.is_a?(Hash)
|
318
|
+
include_path.push(name)
|
319
|
+
current = current[name]
|
320
|
+
raise CliError,"no such config preset: #{include_path}" if nil?
|
321
|
+
end
|
322
|
+
case current
|
323
|
+
when Hash then return expanded_with_preset_includes(current,include_path)
|
324
|
+
when String then return ExtendedValue.instance.evaluate(current)
|
325
|
+
else return current
|
326
|
+
end
|
289
327
|
end
|
290
328
|
|
329
|
+
# @return the hash value with 'incps' keys expanced to include other presets
|
291
330
|
# @param hash_val
|
331
|
+
# @param include_path to avoid inclusion loop
|
292
332
|
def expanded_with_preset_includes(hash_val, include_path=[])
|
293
|
-
raise CliError,"#{EXTV_INCLUDE_PRESETS} requires a Hash" unless hash_val.is_a?(Hash)
|
333
|
+
raise CliError,"#{EXTV_INCLUDE_PRESETS} requires a Hash, have #{hash_val.class}" unless hash_val.is_a?(Hash)
|
294
334
|
if hash_val.has_key?(EXTV_INCLUDE_PRESETS)
|
295
|
-
memory=hash_val.clone
|
296
|
-
includes=memory[EXTV_INCLUDE_PRESETS]
|
335
|
+
memory = hash_val.clone
|
336
|
+
includes = memory[EXTV_INCLUDE_PRESETS]
|
297
337
|
memory.delete(EXTV_INCLUDE_PRESETS)
|
298
|
-
hash_val={}
|
338
|
+
hash_val = {}
|
299
339
|
raise "#{EXTV_INCLUDE_PRESETS} must be an Array" unless includes.is_a?(Array)
|
300
|
-
raise "#{EXTV_INCLUDE_PRESETS} must contain names" unless includes.map
|
340
|
+
raise "#{EXTV_INCLUDE_PRESETS} must contain names" unless includes.map(&:class).uniq.eql?([String])
|
301
341
|
includes.each do |preset_name|
|
302
342
|
hash_val.merge!(preset_by_name(preset_name,include_path))
|
303
343
|
end
|
@@ -306,31 +346,48 @@ END_OF_TEMPLATE
|
|
306
346
|
return hash_val
|
307
347
|
end
|
308
348
|
|
309
|
-
def
|
310
|
-
Fasp::Installation.instance.
|
349
|
+
def option_use_product=(value)
|
350
|
+
Fasp::Installation.instance.use_ascp_from_product(value)
|
311
351
|
end
|
312
352
|
|
313
|
-
def
|
314
|
-
|
353
|
+
def option_use_product
|
354
|
+
'write-only option, see value of ascp_path'
|
315
355
|
end
|
316
356
|
|
317
|
-
def
|
318
|
-
|
357
|
+
def option_plugin_folder=(value)
|
358
|
+
case value
|
359
|
+
when String then add_plugin_lookup_folder(value)
|
360
|
+
when Array then value.each{|f|add_plugin_lookup_folder(f)}
|
361
|
+
else raise "folder shall be Array or String, not #{value.class}"
|
362
|
+
end
|
319
363
|
end
|
320
364
|
|
321
|
-
def
|
322
|
-
|
365
|
+
def option_plugin_folder
|
366
|
+
return @plugin_lookup_folders
|
367
|
+
end
|
368
|
+
|
369
|
+
def option_preset; 'write-only option'; end
|
370
|
+
|
371
|
+
def option_preset=(value)
|
372
|
+
case value
|
373
|
+
when String
|
374
|
+
options.add_option_preset(preset_by_name(value))
|
375
|
+
when Hash
|
376
|
+
options.add_option_preset(value)
|
377
|
+
else
|
378
|
+
raise 'Preset definition must be a String for name, or Hash for value'
|
379
|
+
end
|
323
380
|
end
|
324
381
|
|
325
382
|
def convert_preset_path(old_name,new_name,files_to_copy)
|
326
|
-
old_subpath=File.join('',ASPERA_HOME_FOLDER_NAME,old_name,'')
|
327
|
-
new_subpath=File.join('',ASPERA_HOME_FOLDER_NAME,new_name,'')
|
383
|
+
old_subpath = File.join('',ASPERA_HOME_FOLDER_NAME,old_name,'')
|
384
|
+
new_subpath = File.join('',ASPERA_HOME_FOLDER_NAME,new_name,'')
|
328
385
|
# convert possible keys located in config folder
|
329
386
|
@config_presets.values.select{|p|p.is_a?(Hash)}.each do |preset|
|
330
|
-
preset.values.select{|v|v.is_a?(String)
|
331
|
-
old_val=value.clone
|
332
|
-
included_path=File.expand_path(old_val.gsub(/^@file:/,''))
|
333
|
-
files_to_copy.push(included_path) unless files_to_copy.include?(included_path)
|
387
|
+
preset.values.select{|v|v.is_a?(String) && v.include?(old_subpath)}.each do |value|
|
388
|
+
old_val = value.clone
|
389
|
+
included_path = File.expand_path(old_val.gsub(/^@file:/,''))
|
390
|
+
files_to_copy.push(included_path) unless files_to_copy.include?(included_path) || !File.exist?(included_path)
|
334
391
|
value.gsub!(old_subpath,new_subpath)
|
335
392
|
Log.log.warn("Converted config value: #{old_val} -> #{value}")
|
336
393
|
end
|
@@ -338,11 +395,11 @@ END_OF_TEMPLATE
|
|
338
395
|
end
|
339
396
|
|
340
397
|
def convert_preset_plugin_name(old_name,new_name)
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
398
|
+
default_preset = @config_presets[CONF_PRESET_DEFAULT]
|
399
|
+
return unless default_preset.is_a?(Hash) && default_preset.has_key?(old_name)
|
400
|
+
default_preset[new_name] = default_preset[old_name]
|
401
|
+
default_preset.delete(old_name)
|
402
|
+
Log.log.warn("Converted plugin default: #{old_name} -> #{new_name}")
|
346
403
|
end
|
347
404
|
|
348
405
|
# read config file and validate format
|
@@ -350,64 +407,65 @@ END_OF_TEMPLATE
|
|
350
407
|
def read_config_file
|
351
408
|
begin
|
352
409
|
Log.log.debug("config file is: #{@option_config_file}".red)
|
353
|
-
conf_file_v1=File.join(Dir.home,ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME_V1,DEFAULT_CONFIG_FILENAME)
|
354
|
-
conf_file_v2=File.join(Dir.home,ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME_V2,DEFAULT_CONFIG_FILENAME)
|
410
|
+
conf_file_v1 = File.join(Dir.home,ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME_V1,DEFAULT_CONFIG_FILENAME)
|
411
|
+
conf_file_v2 = File.join(Dir.home,ASPERA_HOME_FOLDER_NAME,PROGRAM_NAME_V2,DEFAULT_CONFIG_FILENAME)
|
355
412
|
# files search for configuration, by default the one given by user
|
356
|
-
search_files=[@option_config_file]
|
413
|
+
search_files = [@option_config_file]
|
357
414
|
# if default file, then also look for older versions
|
358
415
|
search_files.push(conf_file_v2,conf_file_v1) if @option_config_file.eql?(@conf_file_default)
|
359
416
|
# find first existing file (or nil)
|
360
|
-
conf_file_to_load=search_files.
|
417
|
+
conf_file_to_load = search_files.find{|f| File.exist?(f)}
|
361
418
|
# require save if old version of file
|
362
|
-
save_required
|
419
|
+
save_required = !@option_config_file.eql?(conf_file_to_load)
|
363
420
|
# if no file found, create default config
|
364
421
|
if conf_file_to_load.nil?
|
365
422
|
Log.log.warn("No config file found. Creating empty configuration file: #{@option_config_file}")
|
366
|
-
@config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION
|
423
|
+
@config_presets = {CONF_PRESET_CONFIG => {CONF_PRESET_VERSION => @info[:version]}}
|
367
424
|
else
|
368
425
|
Log.log.debug("loading #{@option_config_file}")
|
369
|
-
@config_presets=YAML.load_file(conf_file_to_load)
|
426
|
+
@config_presets = YAML.load_file(conf_file_to_load)
|
370
427
|
end
|
371
|
-
files_to_copy=[]
|
428
|
+
files_to_copy = []
|
372
429
|
Log.log.debug("Available_presets: #{@config_presets}")
|
373
430
|
raise 'Expecting YAML Hash' unless @config_presets.is_a?(Hash)
|
374
431
|
# check there is at least the config section
|
375
432
|
if !@config_presets.has_key?(CONF_PRESET_CONFIG)
|
376
433
|
raise "Cannot find key: #{CONF_PRESET_CONFIG}"
|
377
434
|
end
|
378
|
-
version
|
435
|
+
version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]
|
379
436
|
if version.nil?
|
380
437
|
raise 'No version found in config section.'
|
381
438
|
end
|
382
439
|
# oldest compatible conf file format, update to latest version when an incompatible change is made
|
383
440
|
# check compatibility of version of conf file
|
384
|
-
config_tested_version='0.4.5'
|
441
|
+
config_tested_version = '0.4.5'
|
385
442
|
if Gem::Version.new(version) < Gem::Version.new(config_tested_version)
|
386
443
|
raise "Unsupported config file version #{version}. Expecting min version #{config_tested_version}"
|
387
444
|
end
|
388
|
-
config_tested_version='0.6.15'
|
445
|
+
config_tested_version = '0.6.15'
|
389
446
|
if Gem::Version.new(version) < Gem::Version.new(config_tested_version)
|
390
447
|
convert_preset_plugin_name(AOC_COMMAND_V1,AOC_COMMAND_V2)
|
391
|
-
version
|
392
|
-
save_required=true
|
448
|
+
version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = config_tested_version
|
449
|
+
save_required = true
|
393
450
|
end
|
394
|
-
config_tested_version='0.8.10'
|
451
|
+
config_tested_version = '0.8.10'
|
395
452
|
if Gem::Version.new(version) <= Gem::Version.new(config_tested_version)
|
396
453
|
convert_preset_path(PROGRAM_NAME_V1,PROGRAM_NAME_V2,files_to_copy)
|
397
|
-
version
|
398
|
-
save_required=true
|
454
|
+
version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = config_tested_version
|
455
|
+
save_required = true
|
399
456
|
end
|
400
|
-
config_tested_version='1.0'
|
457
|
+
config_tested_version = '1.0'
|
401
458
|
if Gem::Version.new(version) <= Gem::Version.new(config_tested_version)
|
402
459
|
convert_preset_plugin_name(AOC_COMMAND_V2,AOC_COMMAND_V3)
|
403
|
-
convert_preset_path(PROGRAM_NAME_V2,@
|
404
|
-
version
|
405
|
-
save_required=true
|
460
|
+
convert_preset_path(PROGRAM_NAME_V2,@info[:name],files_to_copy)
|
461
|
+
version = @config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = config_tested_version
|
462
|
+
save_required = true
|
406
463
|
end
|
464
|
+
Log.log.debug("conf version: #{version}")
|
407
465
|
# Place new compatibility code here
|
408
466
|
if save_required
|
409
467
|
Log.log.warn('Saving automatic conversion.')
|
410
|
-
@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION]
|
468
|
+
@config_presets[CONF_PRESET_CONFIG][CONF_PRESET_VERSION] = @info[:version]
|
411
469
|
save_presets_to_config_file
|
412
470
|
Log.log.warn('Copying referenced files')
|
413
471
|
files_to_copy.each do |file|
|
@@ -418,9 +476,9 @@ END_OF_TEMPLATE
|
|
418
476
|
rescue Psych::SyntaxError => e
|
419
477
|
Log.log.error('YAML error in config file')
|
420
478
|
raise e
|
421
|
-
rescue => e
|
479
|
+
rescue StandardError => e
|
422
480
|
Log.log.debug("-> #{e}")
|
423
|
-
new_name="#{@option_config_file}.pre#{@
|
481
|
+
new_name = "#{@option_config_file}.pre#{@info[:version]}.manual_conversion_needed"
|
424
482
|
File.rename(@option_config_file,new_name)
|
425
483
|
Log.log.warn("Renamed config file to #{new_name}.")
|
426
484
|
Log.log.warn('Manual Conversion is required. Next time, a new empty file will be created.')
|
@@ -431,178 +489,197 @@ END_OF_TEMPLATE
|
|
431
489
|
# find plugins in defined paths
|
432
490
|
def add_plugins_from_lookup_folders
|
433
491
|
@plugin_lookup_folders.each do |folder|
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
end
|
492
|
+
next unless File.directory?(folder)
|
493
|
+
#TODO: add gem root to load path ? and require short folder ?
|
494
|
+
#$LOAD_PATH.push(folder) if i[:add_path]
|
495
|
+
Dir.entries(folder).select{|file|file.end_with?(RUBY_FILE_EXT)}.each do |source|
|
496
|
+
add_plugin_info(File.join(folder,source))
|
440
497
|
end
|
441
498
|
end
|
442
499
|
end
|
443
500
|
|
444
501
|
def add_plugin_lookup_folder(folder)
|
445
|
-
@plugin_lookup_folders.
|
502
|
+
@plugin_lookup_folders.unshift(folder)
|
446
503
|
end
|
447
504
|
|
448
505
|
def add_plugin_info(path)
|
449
506
|
raise "ERROR: plugin path must end with #{RUBY_FILE_EXT}" if !path.end_with?(RUBY_FILE_EXT)
|
450
|
-
plugin_symbol=File.basename(path,RUBY_FILE_EXT).to_sym
|
451
|
-
req=path.gsub(/#{RUBY_FILE_EXT}
|
507
|
+
plugin_symbol = File.basename(path,RUBY_FILE_EXT).to_sym
|
508
|
+
req = path.gsub(/#{RUBY_FILE_EXT}$/o,'')
|
452
509
|
if @plugins.has_key?(plugin_symbol)
|
453
510
|
Log.log.warn("skipping plugin already registered: #{plugin_symbol}")
|
454
511
|
return
|
455
512
|
end
|
456
|
-
@plugins[plugin_symbol]={source: path,require_stanza: req}
|
513
|
+
@plugins[plugin_symbol] = {source: path,require_stanza: req}
|
457
514
|
end
|
458
515
|
|
459
516
|
def identify_plugin_for_url(url)
|
460
517
|
plugins.each do |plugin_name_sym,plugin_info|
|
518
|
+
# no detection for internal plugin
|
461
519
|
next if plugin_name_sym.eql?(CONF_PLUGIN_SYM)
|
520
|
+
# load plugin class
|
462
521
|
require plugin_info[:require_stanza]
|
463
|
-
c=self.class.plugin_class(plugin_name_sym)
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
522
|
+
c = self.class.plugin_class(plugin_name_sym)
|
523
|
+
next unless c.respond_to?(:detect)
|
524
|
+
current_url = url
|
525
|
+
detection_info = nil
|
526
|
+
# first try : direct
|
527
|
+
begin
|
528
|
+
detection_info = c.detect(current_url)
|
529
|
+
rescue OpenSSL::SSL::SSLError => e
|
530
|
+
Log.log.warn(e.message)
|
531
|
+
Log.log.warn('Use option --insecure=yes to ignore certificate') if e.message.include?('cert')
|
532
|
+
rescue StandardError => e
|
533
|
+
Log.log.debug("Cannot detect #{plugin_name_sym} : #{e.class}/#{e.message}")
|
534
|
+
end
|
535
|
+
# second try : is there a redirect ?
|
536
|
+
if detection_info.nil?
|
471
537
|
begin
|
472
|
-
#
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
res=c.send(:detect,current_url)
|
478
|
-
return res.merge(product: plugin_name_sym, url: current_url) unless res.nil?
|
538
|
+
# TODO: check if redirect ?
|
539
|
+
new_url = Rest.new(base_url: url).call(operation: 'GET',subpath: '',redirect_max: 1)[:http].uri.to_s
|
540
|
+
unless url.eql?(new_url)
|
541
|
+
detection_info = c.detect(new_url)
|
542
|
+
current_url = new_url
|
479
543
|
end
|
480
|
-
rescue
|
544
|
+
rescue StandardError => e
|
545
|
+
Log.log.debug("Cannot detect #{plugin_name_sym} : #{e.message}")
|
481
546
|
end
|
482
547
|
end
|
483
|
-
|
548
|
+
return detection_info.merge(product: plugin_name_sym, url: current_url) unless detection_info.nil?
|
549
|
+
end # loop
|
484
550
|
raise "No known application found at #{url}"
|
485
551
|
end
|
486
552
|
|
487
553
|
def execute_connect_action
|
488
|
-
command=
|
554
|
+
command = options.get_next_command(%i[list info version])
|
555
|
+
if %i[info version].include?(command)
|
556
|
+
connect_id = options.get_next_argument('id or title')
|
557
|
+
one_res = connect_versions.find{|i|i['id'].eql?(connect_id) || i['title'].eql?(connect_id)}
|
558
|
+
raise CliNoSuchId.new(:connect,connect_id) if one_res.nil?
|
559
|
+
end
|
489
560
|
case command
|
490
561
|
when :list
|
491
|
-
return {type: :object_list, data: connect_versions, fields: [
|
492
|
-
when :
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
562
|
+
return {type: :object_list, data: connect_versions, fields: %w[id title version]}
|
563
|
+
when :info # shows files used
|
564
|
+
one_res.delete('links')
|
565
|
+
return {type: :single_object, data: one_res}
|
566
|
+
when :version # shows files used
|
567
|
+
all_links = one_res['links']
|
568
|
+
command = options.get_next_command(%i[list download open])
|
569
|
+
if %i[download open].include?(command)
|
570
|
+
link_title = options.get_next_argument('title or rel')
|
571
|
+
one_link = all_links.find {|i| i['title'].eql?(link_title) || i['rel'].eql?(link_title)}
|
572
|
+
raise 'no such value' if one_link.nil?
|
573
|
+
end
|
497
574
|
case command
|
498
|
-
when :
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
case command
|
512
|
-
when :download #
|
513
|
-
folder_dest=self.transfer.destination_folder('receive')
|
514
|
-
#folder_dest=self.options.get_next_argument('destination folder')
|
515
|
-
api_connect_cdn=Rest.new({base_url: CONNECT_WEB_URL})
|
516
|
-
fileurl = one_link['href']
|
517
|
-
filename=fileurl.gsub(%r{.*/},'')
|
518
|
-
api_connect_cdn.call({operation: 'GET',subpath: fileurl,save_to_file: File.join(folder_dest,filename)})
|
519
|
-
return Main.result_status("Downloaded: #{filename}")
|
520
|
-
when :open #
|
521
|
-
OpenApplication.instance.uri(one_link['href'])
|
522
|
-
return Main.result_status("Opened: #{one_link['href']}")
|
523
|
-
end
|
524
|
-
end
|
575
|
+
when :list # shows files used
|
576
|
+
return {type: :object_list, data: all_links}
|
577
|
+
when :download
|
578
|
+
folder_dest = transfer.destination_folder(Fasp::TransferSpec::DIRECTION_RECEIVE)
|
579
|
+
#folder_dest=self.options.get_next_argument('destination folder')
|
580
|
+
api_connect_cdn = Rest.new({base_url: CONNECT_WEB_URL})
|
581
|
+
fileurl = one_link['href']
|
582
|
+
filename = fileurl.gsub(%r{.*/},'')
|
583
|
+
api_connect_cdn.call({operation: 'GET',subpath: fileurl,save_to_file: File.join(folder_dest,filename)})
|
584
|
+
return Main.result_status("Downloaded: #{filename}")
|
585
|
+
when :open
|
586
|
+
OpenApplication.instance.uri(one_link['href'])
|
587
|
+
return Main.result_status("Opened: #{one_link['href']}")
|
525
588
|
end
|
526
589
|
end
|
527
590
|
end
|
528
591
|
|
529
592
|
def execute_action_ascp
|
530
|
-
command=
|
593
|
+
command = options.get_next_command(%i[connect use show products info install spec errors])
|
531
594
|
case command
|
532
595
|
when :connect
|
533
596
|
return execute_connect_action
|
534
597
|
when :use
|
535
|
-
ascp_path=
|
536
|
-
ascp_version=Fasp::Installation.instance.get_ascp_version(ascp_path)
|
598
|
+
ascp_path = options.get_next_argument('path to ascp')
|
599
|
+
ascp_version = Fasp::Installation.instance.get_ascp_version(ascp_path)
|
537
600
|
self.format.display_status("ascp version: #{ascp_version}")
|
538
|
-
preset_name=set_global_default(:ascp_path,ascp_path)
|
601
|
+
preset_name = set_global_default(:ascp_path,ascp_path)
|
539
602
|
return Main.result_status("Saved to default global preset #{preset_name}")
|
540
603
|
when :show # shows files used
|
541
604
|
return {type: :status, data: Fasp::Installation.instance.path(:ascp)}
|
542
605
|
when :info # shows files used
|
543
|
-
data=Fasp::Installation::FILES.
|
544
|
-
m[v.to_s]=
|
545
|
-
|
606
|
+
data = Fasp::Installation::FILES.each_with_object({}) do |v,m|
|
607
|
+
m[v.to_s] =
|
608
|
+
begin
|
609
|
+
Fasp::Installation.instance.path(v)
|
610
|
+
rescue => e
|
611
|
+
e.message
|
612
|
+
end
|
546
613
|
end
|
547
614
|
# read PATHs from ascp directly, and pvcl modules as well
|
548
|
-
Open3.popen3(Fasp::Installation.instance.path(:ascp),'-DDL-') do |
|
549
|
-
last_line=''
|
550
|
-
while line=stderr.gets
|
615
|
+
Open3.popen3(Fasp::Installation.instance.path(:ascp),'-DDL-') do |_stdin, _stdout, stderr, thread|
|
616
|
+
last_line = ''
|
617
|
+
while (line = stderr.gets)
|
551
618
|
line.chomp!
|
552
|
-
last_line=line
|
619
|
+
last_line = line
|
553
620
|
case line
|
554
|
-
when %r{^DBG Path ([^ ]+) (dir|file) +: (.*)$}
|
555
|
-
when %r{^DBG Added module group:"([^"]+)" name:"([^"]+)", version:"([^"]+)" interface:"([^"]+)"$}
|
556
|
-
when %r{^DBG License result \(/license/(\S+)\): (.+)$}
|
557
|
-
when %r{^LOG (.+) version ([0-9.]+)$}
|
558
|
-
when %r{^LOG Initializing FASP version ([^,]+),}
|
621
|
+
when %r{^DBG Path ([^ ]+) (dir|file) +: (.*)$} then data[Regexp.last_match(1)] = Regexp.last_match(3)
|
622
|
+
when %r{^DBG Added module group:"([^"]+)" name:"([^"]+)", version:"([^"]+)" interface:"([^"]+)"$} then data[Regexp.last_match(2)] = Regexp.last_match(4)
|
623
|
+
when %r{^DBG License result \(/license/(\S+)\): (.+)$} then data[Regexp.last_match(1)] = Regexp.last_match(2)
|
624
|
+
when %r{^LOG (.+) version ([0-9.]+)$} then data['product_name'] = Regexp.last_match(1);data['product_version'] = Regexp.last_match(2)
|
625
|
+
when %r{^LOG Initializing FASP version ([^,]+),} then data['ascp_version'] = Regexp.last_match(1)
|
559
626
|
end
|
560
627
|
end
|
561
|
-
if !thread.value.exitstatus.eql?(1)
|
628
|
+
if !thread.value.exitstatus.eql?(1) && !data.has_key?('root')
|
562
629
|
raise last_line
|
563
630
|
end
|
564
631
|
end
|
565
|
-
data['keypass']=Fasp::Installation.instance.bypass_pass
|
632
|
+
data['keypass'] = Fasp::Installation.instance.bypass_pass
|
566
633
|
return {type: :single_object, data: data}
|
567
634
|
when :products
|
568
|
-
command=
|
635
|
+
command = options.get_next_command(%i[list use])
|
569
636
|
case command
|
570
637
|
when :list
|
571
|
-
return {type: :object_list, data: Fasp::Installation.instance.installed_products, fields: [
|
638
|
+
return {type: :object_list, data: Fasp::Installation.instance.installed_products, fields: %w[name app_root]}
|
572
639
|
when :use
|
573
|
-
default_product=
|
640
|
+
default_product = options.get_next_argument('product name')
|
574
641
|
Fasp::Installation.instance.use_ascp_from_product(default_product)
|
575
|
-
preset_name=set_global_default(:ascp_path,Fasp::Installation.instance.path(:ascp))
|
642
|
+
preset_name = set_global_default(:ascp_path,Fasp::Installation.instance.path(:ascp))
|
576
643
|
return Main.result_status("Saved to default global preset #{preset_name}")
|
577
644
|
end
|
578
645
|
when :install
|
579
|
-
v=Fasp::Installation.instance.install_sdk(
|
646
|
+
v = Fasp::Installation.instance.install_sdk(options.get_option(:sdk_url,is_type: :mandatory))
|
580
647
|
return Main.result_status("Installed version #{v}")
|
581
648
|
when :spec
|
582
|
-
return {
|
649
|
+
return {
|
650
|
+
type: :object_list,
|
651
|
+
data: Fasp::Parameters.man_table,
|
652
|
+
fields: ['name','type',Fasp::Parameters::SUPPORTED_AGENTS_SHORT.map(&:to_s),'description'].flatten
|
653
|
+
}
|
654
|
+
when :errors
|
655
|
+
error_data = []
|
656
|
+
Fasp::ERROR_INFO.each_pair do |code,prop|
|
657
|
+
error_data.push(code: code, mnemonic: prop[:c], retry: prop[:r], info: prop[:a])
|
658
|
+
end
|
659
|
+
return {type: :object_list, data: error_data}
|
583
660
|
end
|
584
661
|
raise "unexpected case: #{command}"
|
585
662
|
end
|
586
663
|
|
587
664
|
# legacy actions available globally
|
588
|
-
PRESET_GBL_ACTIONS=[
|
665
|
+
PRESET_GBL_ACTIONS = %i[list overview].freeze
|
589
666
|
# require existing preset
|
590
|
-
PRESET_EXST_ACTIONS=[
|
667
|
+
PRESET_EXST_ACTIONS = %i[show delete get unset].freeze
|
591
668
|
# require id
|
592
|
-
PRESET_INSTANCE_ACTIONS=[PRESET_EXST_ACTIONS
|
593
|
-
PRESET_ALL_ACTIONS=[PRESET_GBL_ACTIONS,PRESET_INSTANCE_ACTIONS].flatten.freeze
|
669
|
+
PRESET_INSTANCE_ACTIONS = [PRESET_EXST_ACTIONS,%i[initialize update ask set]].flatten.freeze
|
670
|
+
PRESET_ALL_ACTIONS = [PRESET_GBL_ACTIONS,PRESET_INSTANCE_ACTIONS].flatten.freeze
|
594
671
|
|
595
672
|
def execute_file_action(action,config_name)
|
596
|
-
action=
|
597
|
-
config_name=instance_identifier
|
673
|
+
action = options.get_next_command(PRESET_ALL_ACTIONS) if action.nil?
|
674
|
+
config_name = instance_identifier if config_name.nil? && PRESET_INSTANCE_ACTIONS.include?(action)
|
598
675
|
# those operations require existing option
|
599
|
-
raise "no such preset: #{config_name}" if PRESET_EXST_ACTIONS.include?(action)
|
600
|
-
selected_preset
|
676
|
+
raise "no such preset: #{config_name}" if PRESET_EXST_ACTIONS.include?(action) && !@config_presets.has_key?(config_name)
|
677
|
+
selected_preset = @config_presets[config_name]
|
601
678
|
case action
|
602
679
|
when :list
|
603
680
|
return {type: :value_list, data: @config_presets.keys, name: 'name'}
|
604
681
|
when :overview
|
605
|
-
return {type: :object_list, data:
|
682
|
+
return {type: :object_list, data: Formater.flatten_config_overview(@config_presets)}
|
606
683
|
when :show
|
607
684
|
raise "no such config: #{config_name}" if selected_preset.nil?
|
608
685
|
return {type: :single_object, data: selected_preset}
|
@@ -611,249 +688,177 @@ END_OF_TEMPLATE
|
|
611
688
|
save_presets_to_config_file
|
612
689
|
return Main.result_status("Deleted: #{config_name}")
|
613
690
|
when :get
|
614
|
-
param_name=
|
615
|
-
value=selected_preset[param_name]
|
691
|
+
param_name = options.get_next_argument('parameter name')
|
692
|
+
value = selected_preset[param_name]
|
616
693
|
raise "no such option in preset #{config_name} : #{param_name}" if value.nil?
|
617
694
|
case value
|
618
|
-
when Numeric,String
|
695
|
+
when Numeric,String then return {type: :text, data: ExtendedValue.instance.evaluate(value.to_s)}
|
619
696
|
end
|
620
697
|
return {type: :single_object, data: value}
|
621
698
|
when :unset
|
622
|
-
param_name=
|
699
|
+
param_name = options.get_next_argument('parameter name')
|
623
700
|
selected_preset.delete(param_name)
|
624
701
|
save_presets_to_config_file
|
625
702
|
return Main.result_status("Removed: #{config_name}: #{param_name}")
|
626
703
|
when :set
|
627
|
-
param_name=
|
628
|
-
param_value=
|
704
|
+
param_name = options.get_next_argument('parameter name')
|
705
|
+
param_value = options.get_next_argument('parameter value')
|
629
706
|
if !@config_presets.has_key?(config_name)
|
630
707
|
Log.log.debug("no such config name: #{config_name}, initializing")
|
631
|
-
selected_preset
|
708
|
+
selected_preset = @config_presets[config_name] = {}
|
632
709
|
end
|
633
710
|
if selected_preset.has_key?(param_name)
|
634
711
|
Log.log.warn("overwriting value: #{selected_preset[param_name]}")
|
635
712
|
end
|
636
|
-
selected_preset[param_name]=param_value
|
713
|
+
selected_preset[param_name] = param_value
|
637
714
|
save_presets_to_config_file
|
638
715
|
return Main.result_status("Updated: #{config_name}: #{param_name} <- #{param_value}")
|
639
716
|
when :initialize
|
640
|
-
config_value=
|
717
|
+
config_value = options.get_next_argument('extended value (Hash)')
|
641
718
|
if @config_presets.has_key?(config_name)
|
642
719
|
Log.log.warn("configuration already exists: #{config_name}, overwriting")
|
643
720
|
end
|
644
|
-
@config_presets[config_name]=config_value
|
721
|
+
@config_presets[config_name] = config_value
|
645
722
|
save_presets_to_config_file
|
646
723
|
return Main.result_status("Modified: #{@option_config_file}")
|
647
724
|
when :update
|
648
725
|
# get unprocessed options
|
649
|
-
theopts=
|
726
|
+
theopts = options.get_options_table
|
650
727
|
Log.log.debug("opts=#{theopts}")
|
651
|
-
@config_presets[config_name]||={}
|
728
|
+
@config_presets[config_name] ||= {}
|
652
729
|
@config_presets[config_name].merge!(theopts)
|
653
730
|
# fix bug in 4.4 (creating key "true" in "default" preset)
|
654
731
|
@config_presets[CONF_PRESET_DEFAULT].delete(true) if @config_presets[CONF_PRESET_DEFAULT].is_a?(Hash)
|
655
732
|
save_presets_to_config_file
|
656
733
|
return Main.result_status("Updated: #{config_name}")
|
657
734
|
when :ask
|
658
|
-
|
659
|
-
@config_presets[config_name]||={}
|
660
|
-
|
661
|
-
option_value=
|
662
|
-
@config_presets[config_name][optionname]=option_value
|
735
|
+
options.ask_missing_mandatory = :yes
|
736
|
+
@config_presets[config_name] ||= {}
|
737
|
+
options.get_next_argument('option names',expected: :multiple).each do |optionname|
|
738
|
+
option_value = options.get_interactive(:option,optionname)
|
739
|
+
@config_presets[config_name][optionname] = option_value
|
663
740
|
end
|
664
741
|
save_presets_to_config_file
|
665
742
|
return Main.result_status("Updated: #{config_name}")
|
666
743
|
end
|
667
744
|
end
|
668
745
|
|
669
|
-
ACTIONS=[PRESET_GBL_ACTIONS
|
746
|
+
ACTIONS = [PRESET_GBL_ACTIONS,%i[id preset open documentation genkey gem plugin flush_tokens echo wizard export_to_cli detect coffee
|
747
|
+
ascp email_test smtp_settings proxy_check folder file check_update initdemo vault]].flatten.freeze
|
670
748
|
|
671
749
|
# "config" plugin
|
672
750
|
def execute_action
|
673
|
-
action=
|
751
|
+
action = options.get_next_command(ACTIONS)
|
674
752
|
case action
|
675
753
|
when *PRESET_GBL_ACTIONS # older syntax
|
676
754
|
return execute_file_action(action,nil)
|
677
755
|
when :id # older syntax
|
678
|
-
return execute_file_action(nil,
|
756
|
+
return execute_file_action(nil,options.get_next_argument('config name'))
|
679
757
|
when :preset # newer syntax
|
680
758
|
return execute_file_action(nil,nil)
|
681
759
|
when :open
|
682
|
-
OpenApplication.instance.uri(
|
760
|
+
OpenApplication.instance.uri(@option_config_file.to_s) #file://
|
683
761
|
return Main.result_nothing
|
684
762
|
when :documentation
|
685
|
-
section=options.get_next_argument('private key file path'
|
686
|
-
section='#'+section unless section.nil?
|
687
|
-
OpenApplication.instance.uri("#{@
|
763
|
+
section = options.get_next_argument('private key file path',mandatory: false)
|
764
|
+
section = '#' + section unless section.nil?
|
765
|
+
OpenApplication.instance.uri("#{@info[:help]}#{section}")
|
688
766
|
return Main.result_nothing
|
689
767
|
when :genkey # generate new rsa key
|
690
|
-
private_key_path=
|
691
|
-
|
692
|
-
|
768
|
+
private_key_path = options.get_next_argument('private key file path')
|
769
|
+
private_key_length = options.get_next_argument('size in bits',mandatory: false) || DEFAULT_PRIVKEY_LENGTH
|
770
|
+
generate_rsa_private_key(private_key_path,private_key_length)
|
771
|
+
return Main.result_status('Generated key: ' + private_key_path)
|
693
772
|
when :echo # display the content of a value given on command line
|
694
|
-
result={type: :other_struct, data:
|
773
|
+
result = {type: :other_struct, data: options.get_next_argument('value')}
|
695
774
|
# special for csv
|
696
|
-
result[:type]
|
775
|
+
result[:type] = :object_list if result[:data].is_a?(Array) && result[:data].first.is_a?(Hash)
|
697
776
|
return result
|
698
777
|
when :flush_tokens
|
699
|
-
deleted_files=Oauth.flush_tokens
|
778
|
+
deleted_files = Oauth.flush_tokens
|
700
779
|
return {type: :value_list, data: deleted_files, name: 'file'}
|
701
|
-
when :
|
702
|
-
|
780
|
+
when :plugin
|
781
|
+
case options.get_next_command(%i[list create])
|
782
|
+
when :list
|
783
|
+
return {type: :object_list, data: @plugins.keys.map { |i| { 'plugin' => i.to_s, 'path' => @plugins[i][:source] } }, fields: %w[plugin path]}
|
784
|
+
when :create
|
785
|
+
plugin_name = options.get_next_argument('name',expected: :single).downcase
|
786
|
+
plugin_folder = options.get_next_argument('folder',expected: :single,mandatory: false) || File.join(@main_folder,ASPERA_PLUGINS_FOLDERNAME)
|
787
|
+
plugin_file = File.join(plugin_folder,"#{plugin_name}.rb")
|
788
|
+
content = <<~END_OF_PLUGIN_CODE
|
789
|
+
require 'aspera/cli/plugin'
|
790
|
+
module Aspera
|
791
|
+
module Cli
|
792
|
+
module Plugins
|
793
|
+
class #{plugin_name.capitalize} < Plugin
|
794
|
+
ACTIONS=[]
|
795
|
+
def execute_action; return Main.result_status('You called plugin #{plugin_name}'); end
|
796
|
+
end # #{plugin_name.capitalize}
|
797
|
+
end # Plugins
|
798
|
+
end # Cli
|
799
|
+
end # Aspera
|
800
|
+
END_OF_PLUGIN_CODE
|
801
|
+
File.write(plugin_file,content)
|
802
|
+
return Main.result_status("Created #{plugin_file}")
|
803
|
+
end
|
703
804
|
when :wizard
|
704
805
|
# interactive mode
|
705
|
-
|
806
|
+
options.ask_missing_mandatory = true
|
706
807
|
# register url option
|
707
|
-
BasicAuthPlugin.
|
808
|
+
BasicAuthPlugin.register_options(@agents)
|
809
|
+
params={}
|
708
810
|
# get from option, or ask
|
709
|
-
instance_url=
|
811
|
+
params[:instance_url] = options.get_option(:url,is_type: :mandatory)
|
710
812
|
# allow user to tell the preset name
|
711
|
-
preset_name=
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
813
|
+
params[:preset_name] = options.get_option(:id)
|
814
|
+
# allow user to specify type of application
|
815
|
+
params[:application] = options.get_option(:value)
|
816
|
+
params[:application] = params[:application].nil? ? identify_plugin_for_url(params[:instance_url])[:product] : params[:application].to_sym
|
817
|
+
params[:plugin_name]=params[:application]
|
818
|
+
params[:test_args] = '<replace per app>'
|
819
|
+
case params[:application]
|
820
|
+
when :faspex5
|
821
|
+
wizard_faspex5(params)
|
716
822
|
when :aoc
|
717
|
-
|
718
|
-
plugin_name=AOC_COMMAND_CURRENT
|
719
|
-
organization,instance_domain=AoC.parse_url(instance_url)
|
720
|
-
# if not defined by user, generate name
|
721
|
-
preset_name=[appli[:product],organization].join('_') if preset_name.nil?
|
722
|
-
self.format.display_status("Preparing preset: #{preset_name}")
|
723
|
-
# init defaults if necessary
|
724
|
-
@config_presets[CONF_PRESET_DEFAULT]||={}
|
725
|
-
option_override=self.options.get_option(:override,:mandatory)
|
726
|
-
option_default=self.options.get_option(:default,:mandatory)
|
727
|
-
Log.log.error("override=#{option_override} -> #{option_override.class}")
|
728
|
-
raise CliError,"A default configuration already exists for plugin '#{plugin_name}' (use --override=yes or --default=no)" if !option_override and option_default and @config_presets[CONF_PRESET_DEFAULT].has_key?(plugin_name)
|
729
|
-
raise CliError,"Preset already exists: #{preset_name} (use --override=yes or --id=<name>)" if !option_override and @config_presets.has_key?(preset_name)
|
730
|
-
# lets see if path to priv key is provided
|
731
|
-
private_key_path=self.options.get_option(:pkeypath,:optional)
|
732
|
-
# give a chance to provide
|
733
|
-
if private_key_path.nil?
|
734
|
-
self.format.display_status('Please provide path to your private RSA key, or empty to generate one:')
|
735
|
-
private_key_path=self.options.get_option(:pkeypath,:mandatory).to_s
|
736
|
-
end
|
737
|
-
# else generate path
|
738
|
-
if private_key_path.empty?
|
739
|
-
private_key_path=File.join(@main_folder,DEFAULT_PRIV_KEY_FILENAME)
|
740
|
-
end
|
741
|
-
if File.exist?(private_key_path)
|
742
|
-
self.format.display_status('Using existing key:')
|
743
|
-
else
|
744
|
-
self.format.display_status("Generating #{DEFAULT_PRIVKEY_LENGTH} bit RSA key...")
|
745
|
-
generate_rsa_private_key(private_key_path,DEFAULT_PRIVKEY_LENGTH)
|
746
|
-
self.format.display_status('Created:')
|
747
|
-
end
|
748
|
-
self.format.display_status(private_key_path)
|
749
|
-
pub_key_pem=OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
|
750
|
-
# declare command line options for AoC
|
751
|
-
require 'aspera/cli/plugins/aoc'
|
752
|
-
# make username mandatory for jwt, this triggers interactive input
|
753
|
-
self.options.get_option(:username,:mandatory)
|
754
|
-
# instanciate AoC plugin, so that command line options are known
|
755
|
-
files_plugin=self.class.plugin_class(plugin_name).new(@agents.merge({skip_basic_auth_options: true, private_key_path: private_key_path}))
|
756
|
-
aoc_api=files_plugin.get_api
|
757
|
-
auto_set_pub_key=false
|
758
|
-
auto_set_jwt=false
|
759
|
-
use_browser_authentication=false
|
760
|
-
if self.options.get_option(:use_generic_client)
|
761
|
-
self.format.display_status('Using global client_id.')
|
762
|
-
self.format.display_status('Please Login to your Aspera on Cloud instance.'.red)
|
763
|
-
self.format.display_status('Navigate to your "Account Settings"'.red)
|
764
|
-
self.format.display_status('Check or update the value of "Public Key" to be:'.red.blink)
|
765
|
-
self.format.display_status("#{pub_key_pem}")
|
766
|
-
if ! self.options.get_option(:test_mode)
|
767
|
-
self.format.display_status('Once updated or validated, press enter.')
|
768
|
-
OpenApplication.instance.uri(instance_url)
|
769
|
-
STDIN.gets
|
770
|
-
end
|
771
|
-
else
|
772
|
-
self.format.display_status('Using organization specific client_id.')
|
773
|
-
if self.options.get_option(:client_id,:optional).nil? or self.options.get_option(:client_secret,:optional).nil?
|
774
|
-
self.format.display_status('Please login to your Aspera on Cloud instance.'.red)
|
775
|
-
self.format.display_status('Go to: Apps->Admin->Organization->Integrations')
|
776
|
-
self.format.display_status('Create or check if there is an existing integration named:')
|
777
|
-
self.format.display_status("- name: #{@tool_name}")
|
778
|
-
self.format.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
|
779
|
-
self.format.display_status('- origin: localhost')
|
780
|
-
self.format.display_status('Once created or identified,')
|
781
|
-
self.format.display_status('Please enter:'.red)
|
782
|
-
end
|
783
|
-
OpenApplication.instance.uri("#{instance_url}/#{AOC_PATH_API_CLIENTS}")
|
784
|
-
self.options.get_option(:client_id,:mandatory)
|
785
|
-
self.options.get_option(:client_secret,:mandatory)
|
786
|
-
use_browser_authentication=true
|
787
|
-
end
|
788
|
-
if use_browser_authentication
|
789
|
-
self.format.display_status('We will use web authentication to bootstrap.')
|
790
|
-
auto_set_pub_key=true
|
791
|
-
auto_set_jwt=true
|
792
|
-
@api_aoc.oauth.params[:auth]=:web
|
793
|
-
@api_aoc.oauth.params[:redirect_uri]=DEFAULT_REDIRECT
|
794
|
-
@api_aoc.oauth.params[:scope]=AoC::SCOPE_FILES_ADMIN
|
795
|
-
end
|
796
|
-
myself=aoc_api.read('self')[:data]
|
797
|
-
if auto_set_pub_key
|
798
|
-
raise CliError,'Public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? or option_override
|
799
|
-
self.format.display_status('Updating profile with new key')
|
800
|
-
aoc_api.update("users/#{myself['id']}",{'public_key'=>pub_key_pem})
|
801
|
-
end
|
802
|
-
if auto_set_jwt
|
803
|
-
self.format.display_status('Enabling JWT for client')
|
804
|
-
aoc_api.update("clients/#{self.options.get_option(:client_id)}",{'jwt_grant_enabled'=>true,'explicit_authorization_required'=>false})
|
805
|
-
end
|
806
|
-
self.format.display_status("Creating new config preset: #{preset_name}")
|
807
|
-
@config_presets[preset_name]={
|
808
|
-
:url.to_s =>self.options.get_option(:url),
|
809
|
-
:username.to_s =>myself['email'],
|
810
|
-
:auth.to_s =>:jwt.to_s,
|
811
|
-
:private_key.to_s =>'@file:'+private_key_path,
|
812
|
-
}
|
813
|
-
# set only if non nil
|
814
|
-
[:client_id,:client_secret].each do |s|
|
815
|
-
o=self.options.get_option(s)
|
816
|
-
@config_presets[preset_name][s.to_s] = o unless o.nil?
|
817
|
-
end
|
818
|
-
test_args="#{plugin_name} user info show"
|
823
|
+
wizard_aoc(params)
|
819
824
|
else
|
820
|
-
raise CliBadArgument,"Supports only: aoc. Detected: #{
|
825
|
+
raise CliBadArgument,"Supports only: aoc. Detected: #{params[:application]}"
|
821
826
|
end # product
|
822
|
-
if option_default
|
823
|
-
self.format.display_status("Setting config preset as default for #{plugin_name}")
|
824
|
-
@config_presets[CONF_PRESET_DEFAULT][plugin_name]=preset_name
|
827
|
+
if params[:option_default]
|
828
|
+
self.format.display_status("Setting config preset as default for #{params[:plugin_name]}")
|
829
|
+
@config_presets[CONF_PRESET_DEFAULT][params[:plugin_name]] = params[:preset_name]
|
825
830
|
else
|
826
|
-
test_args="-P#{preset_name} #{test_args}"
|
831
|
+
params[:test_args] = "-P#{params[:preset_name]} #{params[:test_args]}"
|
827
832
|
end
|
828
833
|
self.format.display_status('Saving config file.')
|
829
834
|
save_presets_to_config_file
|
830
|
-
return Main.result_status("Done.\nYou can test with:\n#{@
|
831
|
-
when :export_to_cli
|
835
|
+
return Main.result_status("Done.\nYou can test with:\n#{@info[:name]} #{params[:test_args]}")
|
836
|
+
when :export_to_cli # this method shall be deprecated in the future: it was used to export configuration to "aspera.exe" CLI
|
832
837
|
self.format.display_status('Exporting: Aspera on Cloud')
|
833
838
|
require 'aspera/cli/plugins/aoc'
|
834
839
|
# need url / username
|
835
840
|
add_plugin_default_preset(AOC_COMMAND_V3.to_sym)
|
836
841
|
# instanciate AoC plugin
|
837
|
-
|
838
|
-
url=
|
839
|
-
cli_conf_file=Fasp::Installation.instance.cli_conf_file
|
840
|
-
data=JSON.parse(File.read(cli_conf_file))
|
841
|
-
organization,instance_domain=AoC.parse_url(url)
|
842
|
-
key_basename='org_'+organization+'.pem'
|
843
|
-
key_file=File.join(File.dirname(File.dirname(cli_conf_file)),'etc',key_basename)
|
844
|
-
File.write(key_file,
|
845
|
-
new_conf={
|
842
|
+
self.class.plugin_class(AOC_COMMAND_CURRENT).new(@agents) # TODO: is this line needed ? get options ?
|
843
|
+
url = options.get_option(:url,is_type: :mandatory)
|
844
|
+
cli_conf_file = Fasp::Installation.instance.cli_conf_file
|
845
|
+
data = JSON.parse(File.read(cli_conf_file))
|
846
|
+
organization,instance_domain = AoC.parse_url(url)
|
847
|
+
key_basename = 'org_' + organization + '.pem'
|
848
|
+
key_file = File.join(File.dirname(File.dirname(cli_conf_file)),'etc',key_basename)
|
849
|
+
File.write(key_file,options.get_option(:private_key,is_type: :mandatory))
|
850
|
+
new_conf = {
|
846
851
|
'organization' => organization,
|
847
852
|
'hostname' => [organization,instance_domain].join('.'),
|
848
853
|
'privateKeyFilename' => key_basename,
|
849
|
-
'username' =>
|
854
|
+
'username' => options.get_option(:username,is_type: :mandatory)
|
850
855
|
}
|
851
|
-
new_conf['clientId']=
|
852
|
-
new_conf['clientSecret']=
|
856
|
+
new_conf['clientId'] = options.get_option(:client_id)
|
857
|
+
new_conf['clientSecret'] = options.get_option(:client_secret)
|
853
858
|
if new_conf['clientId'].nil?
|
854
|
-
new_conf['clientId'],new_conf['clientSecret']=AoC.get_client_info
|
859
|
+
new_conf['clientId'],new_conf['clientSecret'] = AoC.get_client_info
|
855
860
|
end
|
856
|
-
entry=data['AoCAccounts'].
|
861
|
+
entry = data['AoCAccounts'].find{|i|i['organization'].eql?(organization)}
|
857
862
|
if entry.nil?
|
858
863
|
data['AoCAccounts'].push(new_conf)
|
859
864
|
self.format.display_status("Creating new aoc entry: #{organization}")
|
@@ -865,15 +870,19 @@ END_OF_TEMPLATE
|
|
865
870
|
return Main.result_status("Updated: #{cli_conf_file}")
|
866
871
|
when :detect
|
867
872
|
# need url / username
|
868
|
-
BasicAuthPlugin.
|
869
|
-
return
|
873
|
+
BasicAuthPlugin.register_options(@agents)
|
874
|
+
return {type: :single_object, data: identify_plugin_for_url(options.get_option(:url,is_type: :mandatory))}
|
870
875
|
when :coffee
|
871
876
|
OpenApplication.instance.uri('https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg')
|
872
877
|
return Main.result_nothing
|
873
878
|
when :ascp
|
874
879
|
execute_action_ascp
|
875
|
-
when :
|
876
|
-
|
880
|
+
when :gem
|
881
|
+
case options.get_next_command(%i[path version name])
|
882
|
+
when :path then return Main.result_status(self.class.gem_src_root)
|
883
|
+
when :version then return Main.result_status(Aspera::Cli::VERSION)
|
884
|
+
when :name then return Main.result_status(@info[:gem])
|
885
|
+
end
|
877
886
|
when :folder
|
878
887
|
return Main.result_status(@main_folder)
|
879
888
|
when :file
|
@@ -884,9 +893,10 @@ END_OF_TEMPLATE
|
|
884
893
|
when :smtp_settings
|
885
894
|
return {type: :single_object, data: email_settings}
|
886
895
|
when :proxy_check
|
887
|
-
|
888
|
-
|
889
|
-
|
896
|
+
# ensure fpac was provided
|
897
|
+
options.get_option(:fpac,is_type: :mandatory)
|
898
|
+
server_url = options.get_next_argument('server url')
|
899
|
+
return Main.result_status(@pac_exec.find_proxy_for_url(server_url))
|
890
900
|
when :check_update
|
891
901
|
return {type: :single_object, data: check_gem_version}
|
892
902
|
when :initdemo
|
@@ -894,57 +904,62 @@ END_OF_TEMPLATE
|
|
894
904
|
Log.log.warn("Demo server preset already present: #{DEMO_SERVER_PRESET}")
|
895
905
|
else
|
896
906
|
Log.log.info("Creating Demo server preset: #{DEMO_SERVER_PRESET}")
|
897
|
-
@config_presets[DEMO_SERVER_PRESET]={
|
907
|
+
@config_presets[DEMO_SERVER_PRESET] = {
|
908
|
+
'url' => 'ssh://' + DEMO + '.asperasoft.com:33001',
|
909
|
+
'username' => AOC_COMMAND_V2,
|
910
|
+
'ssAP'.downcase.reverse + 'drow'.reverse => DEMO + AOC_COMMAND_V2
|
911
|
+
}
|
898
912
|
end
|
899
|
-
@config_presets[CONF_PRESET_DEFAULT]||={}
|
913
|
+
@config_presets[CONF_PRESET_DEFAULT] ||= {}
|
900
914
|
if @config_presets[CONF_PRESET_DEFAULT].has_key?(SERVER_COMMAND)
|
901
915
|
Log.log.warn("Server default preset already set to: #{@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND]}")
|
902
|
-
Log.log.warn("Use #{DEMO_SERVER_PRESET} for demo: -P#{DEMO_SERVER_PRESET}") unless
|
916
|
+
Log.log.warn("Use #{DEMO_SERVER_PRESET} for demo: -P#{DEMO_SERVER_PRESET}") unless
|
917
|
+
DEMO_SERVER_PRESET.eql?(@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND])
|
903
918
|
else
|
904
|
-
@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND]=DEMO_SERVER_PRESET
|
919
|
+
@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND] = DEMO_SERVER_PRESET
|
905
920
|
Log.log.info("Setting server default preset to : #{DEMO_SERVER_PRESET}")
|
906
921
|
end
|
907
922
|
save_presets_to_config_file
|
908
|
-
return Main.result_status(
|
923
|
+
return Main.result_status('Done')
|
909
924
|
when :vault
|
910
|
-
command=
|
925
|
+
command = options.get_next_command(%i[init list get set delete])
|
911
926
|
case command
|
912
927
|
when :init
|
913
|
-
type=
|
928
|
+
type = options.get_option(:value)
|
914
929
|
case type
|
915
930
|
when 'config',NilClass
|
916
|
-
raise
|
917
|
-
@config_presets[CONF_PRESET_SECRETS]={}
|
931
|
+
raise 'default secrets already exists' if @config_presets.has_key?(CONF_PRESET_SECRETS)
|
932
|
+
@config_presets[CONF_PRESET_SECRETS] = {}
|
918
933
|
set_global_default(:secrets,"@preset:#{CONF_PRESET_SECRETS}")
|
919
|
-
else raise
|
934
|
+
else raise 'no such vault type'
|
920
935
|
end
|
921
|
-
return Main.result_status(
|
936
|
+
return Main.result_status('Done')
|
922
937
|
when :list
|
923
938
|
return {type: :object_list, data: vault.list}
|
924
939
|
when :set
|
925
940
|
# register url option
|
926
|
-
BasicAuthPlugin.
|
927
|
-
username=
|
928
|
-
url=
|
929
|
-
description=
|
930
|
-
secret=
|
941
|
+
BasicAuthPlugin.register_options(@agents)
|
942
|
+
username = options.get_option(:username,is_type: :mandatory)
|
943
|
+
url = options.get_option(:url,is_type: :mandatory)
|
944
|
+
description = options.get_option(:value)
|
945
|
+
secret = options.get_next_argument('secret')
|
931
946
|
vault.set(username: username, url: url, description: description, secret: secret)
|
932
947
|
save_presets_to_config_file if vault.is_a?(Keychain::EncryptedHash)
|
933
|
-
return Main.result_status(
|
948
|
+
return Main.result_status('Done')
|
934
949
|
when :get
|
935
950
|
# register url option
|
936
|
-
BasicAuthPlugin.
|
937
|
-
username=
|
938
|
-
url=
|
939
|
-
result=vault.get(username: username, url: url)
|
951
|
+
BasicAuthPlugin.register_options(@agents)
|
952
|
+
username = options.get_option(:username,is_type: :mandatory)
|
953
|
+
url = options.get_option(:url)
|
954
|
+
result = vault.get(username: username, url: url)
|
940
955
|
return {type: :single_object, data: result}
|
941
956
|
when :delete
|
942
957
|
# register url option
|
943
|
-
BasicAuthPlugin.
|
944
|
-
username=
|
945
|
-
url=
|
946
|
-
|
947
|
-
return Main.result_status(
|
958
|
+
BasicAuthPlugin.register_options(@agents)
|
959
|
+
username = options.get_option(:username,is_type: :mandatory)
|
960
|
+
url = options.get_option(:url)
|
961
|
+
vault.delete(username: username, url: url)
|
962
|
+
return Main.result_status('Done')
|
948
963
|
end
|
949
964
|
else raise 'INTERNAL ERROR: wrong case'
|
950
965
|
end
|
@@ -952,17 +967,17 @@ END_OF_TEMPLATE
|
|
952
967
|
|
953
968
|
# @return email server setting with defaults if not defined
|
954
969
|
def email_settings
|
955
|
-
smtp=
|
970
|
+
smtp = options.get_option(:smtp,is_type: :mandatory)
|
956
971
|
# change string keys into symbol keys
|
957
|
-
smtp=smtp.keys.
|
972
|
+
smtp = smtp.keys.each_with_object({}){|v,m|m[v.to_sym] = smtp[v];}
|
958
973
|
# defaults
|
959
|
-
smtp[:tls]||=true
|
960
|
-
smtp[:port]||=smtp[:tls]?587:25
|
961
|
-
smtp[:from_email]||=smtp[:username] if smtp.has_key?(:username)
|
962
|
-
smtp[:from_name]||=smtp[:from_email].gsub(/@.*$/,'').gsub(/[^a-zA-Z]/,' ').capitalize if smtp.has_key?(:username)
|
963
|
-
smtp[:domain]||=smtp[:from_email].gsub(/^.*@/,'') if smtp.has_key?(:from_email)
|
974
|
+
smtp[:tls] ||= true
|
975
|
+
smtp[:port] ||= smtp[:tls] ? 587 : 25
|
976
|
+
smtp[:from_email] ||= smtp[:username] if smtp.has_key?(:username)
|
977
|
+
smtp[:from_name] ||= smtp[:from_email].gsub(/@.*$/,'').gsub(/[^a-zA-Z]/,' ').capitalize if smtp.has_key?(:username)
|
978
|
+
smtp[:domain] ||= smtp[:from_email].gsub(/^.*@/,'') if smtp.has_key?(:from_email)
|
964
979
|
# check minimum required
|
965
|
-
[
|
980
|
+
%i[server port domain].each do |n|
|
966
981
|
raise "Missing smtp parameter: #{n}" unless smtp.has_key?(n)
|
967
982
|
end
|
968
983
|
Log.log.debug("smtp=#{smtp}")
|
@@ -975,30 +990,30 @@ END_OF_TEMPLATE
|
|
975
990
|
end
|
976
991
|
|
977
992
|
def send_email_template(vars,email_template_default=nil)
|
978
|
-
vars[:to]||=options.get_option(:notif_to
|
979
|
-
notif_template=options.get_option(:notif_template,email_template_default.nil? ? :mandatory : :optional) || email_template_default
|
980
|
-
mail_conf=email_settings
|
981
|
-
vars[:from_name]||=mail_conf[:from_name]
|
982
|
-
vars[:from_email]||=mail_conf[:from_email]
|
983
|
-
[
|
993
|
+
vars[:to] ||= options.get_option(:notif_to,is_type: :mandatory)
|
994
|
+
notif_template = options.get_option(:notif_template,is_type: email_template_default.nil? ? :mandatory : :optional) || email_template_default
|
995
|
+
mail_conf = email_settings
|
996
|
+
vars[:from_name] ||= mail_conf[:from_name]
|
997
|
+
vars[:from_email] ||= mail_conf[:from_email]
|
998
|
+
%i[from_name from_email].each do |n|
|
984
999
|
raise "Missing email parameter: #{n}" unless vars.has_key?(n)
|
985
1000
|
end
|
986
|
-
start_options=[mail_conf[:domain]]
|
987
|
-
start_options.push(mail_conf[:username],mail_conf[:password],:login) if mail_conf.has_key?(:username)
|
1001
|
+
start_options = [mail_conf[:domain]]
|
1002
|
+
start_options.push(mail_conf[:username],mail_conf[:password],:login) if mail_conf.has_key?(:username) && mail_conf.has_key?(:password)
|
988
1003
|
# create a binding with only variables defined in vars
|
989
|
-
template_binding=empty_binding
|
1004
|
+
template_binding = empty_binding
|
990
1005
|
# add variables to binding
|
991
1006
|
vars.each do |k,v|
|
992
1007
|
raise "key (#{k.class}) must be Symbol" unless k.is_a?(Symbol)
|
993
1008
|
template_binding.local_variable_set(k,v)
|
994
1009
|
end
|
995
1010
|
# execute template
|
996
|
-
msg_with_headers=ERB.new(notif_template).result(template_binding)
|
1011
|
+
msg_with_headers = ERB.new(notif_template).result(template_binding)
|
997
1012
|
Log.dump(:msg_with_headers,msg_with_headers)
|
998
1013
|
smtp = Net::SMTP.new(mail_conf[:server], mail_conf[:port])
|
999
1014
|
smtp.enable_starttls if mail_conf[:tls]
|
1000
|
-
smtp.start(*start_options) do |
|
1001
|
-
|
1015
|
+
smtp.start(*start_options) do |smtp_session|
|
1016
|
+
smtp_session.send_message(msg_with_headers, vars[:from_email], vars[:to])
|
1002
1017
|
end
|
1003
1018
|
end
|
1004
1019
|
|
@@ -1012,16 +1027,18 @@ END_OF_TEMPLATE
|
|
1012
1027
|
# returns [String] name if config_presets has default
|
1013
1028
|
# returns nil if there is no config or bypass default params
|
1014
1029
|
def get_plugin_default_config_name(plugin_sym)
|
1015
|
-
raise
|
1030
|
+
raise 'internal error: config_presets shall be defined' if @config_presets.nil?
|
1016
1031
|
if !@use_plugin_defaults
|
1017
1032
|
Log.log.debug('skip default config')
|
1018
1033
|
return nil
|
1019
1034
|
end
|
1020
|
-
if @config_presets.has_key?(CONF_PRESET_DEFAULT)
|
1035
|
+
if @config_presets.has_key?(CONF_PRESET_DEFAULT) &&
|
1021
1036
|
@config_presets[CONF_PRESET_DEFAULT].has_key?(plugin_sym.to_s)
|
1022
|
-
default_config_name
|
1037
|
+
default_config_name = @config_presets[CONF_PRESET_DEFAULT][plugin_sym.to_s]
|
1023
1038
|
if !@config_presets.has_key?(default_config_name)
|
1024
|
-
Log.log.error("Default config name [#{default_config_name}] specified for plugin [#{plugin_sym
|
1039
|
+
Log.log.error("Default config name [#{default_config_name}] specified for plugin [#{plugin_sym}], but it does not exist in config file.\n"\
|
1040
|
+
'Please fix the issue: either create preset with one parameter: '\
|
1041
|
+
"(#{@info[:name]} config id #{default_config_name} init @json:'{}') or remove default (#{@info[:name]} config id default remove #{plugin_sym}).")
|
1025
1042
|
end
|
1026
1043
|
raise CliError,"Config name [#{default_config_name}] must be a hash, check config file." if !@config_presets[default_config_name].is_a?(Hash)
|
1027
1044
|
return default_config_name
|
@@ -1031,18 +1048,18 @@ END_OF_TEMPLATE
|
|
1031
1048
|
|
1032
1049
|
def vault
|
1033
1050
|
if @vault.nil?
|
1034
|
-
vault_info=
|
1051
|
+
vault_info = options.get_option(:secrets)
|
1035
1052
|
case vault_info
|
1036
1053
|
when Hash
|
1037
|
-
@vault=Keychain::EncryptedHash.new(vault_info)
|
1054
|
+
@vault = Keychain::EncryptedHash.new(vault_info)
|
1038
1055
|
when /^system/
|
1039
|
-
name=vault_info.start_with?('system:') ? vault_info[7..-1] : nil
|
1056
|
+
name = vault_info.start_with?('system:') ? vault_info[7..-1] : nil
|
1040
1057
|
case Environment.os
|
1041
1058
|
when Environment::OS_X
|
1042
|
-
@vault=Keychain::MacosSecurity.new(name)
|
1059
|
+
@vault = Keychain::MacosSecurity.new(name)
|
1043
1060
|
when Environment::OS_WINDOWS,Environment::OS_LINUX,Environment::OS_AIX
|
1044
|
-
raise
|
1045
|
-
else raise
|
1061
|
+
raise 'not implemented'
|
1062
|
+
else raise 'Error'
|
1046
1063
|
end
|
1047
1064
|
when NilClass
|
1048
1065
|
# keep nil
|
@@ -1050,21 +1067,184 @@ END_OF_TEMPLATE
|
|
1050
1067
|
raise CliBadArgument,'secrets shall be Hash'
|
1051
1068
|
end
|
1052
1069
|
end
|
1053
|
-
raise
|
1070
|
+
raise 'No vault defined' if @vault.nil?
|
1054
1071
|
@vault
|
1055
1072
|
end
|
1056
1073
|
|
1057
1074
|
def get_secret(options)
|
1058
|
-
raise
|
1059
|
-
raise
|
1060
|
-
secret=self.options.get_option(:secret
|
1075
|
+
raise 'options shall be Hash' unless options.is_a?(Hash)
|
1076
|
+
raise 'options shall have username' unless options.has_key?(:username)
|
1077
|
+
secret = self.options.get_option(:secret)
|
1061
1078
|
if secret.nil?
|
1062
|
-
secret=vault.get(options) rescue nil
|
1079
|
+
secret = vault.get(options) rescue nil
|
1063
1080
|
# mandatory by default
|
1064
|
-
raise "please provide secret for #{options[:username]}" if secret.nil?
|
1081
|
+
raise "please provide secret for #{options[:username]}" if secret.nil? && (options[:mandatory].nil? || options[:mandatory])
|
1065
1082
|
end
|
1066
1083
|
return secret
|
1067
1084
|
end
|
1085
|
+
|
1086
|
+
def wizard_aoc(params)
|
1087
|
+
self.format.display_status('Detected: Aspera on Cloud'.bold)
|
1088
|
+
params[:plugin_name] = AOC_COMMAND_CURRENT
|
1089
|
+
organization = AoC.parse_url(params[:instance_url]).first
|
1090
|
+
# if not defined by user, generate name
|
1091
|
+
params[:preset_name] = [params[:application],organization].join('_') if params[:preset_name].nil?
|
1092
|
+
self.format.display_status("Preparing preset: #{params[:preset_name]}")
|
1093
|
+
# init defaults if necessary
|
1094
|
+
@config_presets[CONF_PRESET_DEFAULT] ||= {}
|
1095
|
+
option_override = options.get_option(:override,is_type: :mandatory)
|
1096
|
+
params[:option_default] = options.get_option(:default,is_type: :mandatory)
|
1097
|
+
Log.log.error("override=#{option_override} -> #{option_override.class}")
|
1098
|
+
raise CliError,"A default configuration already exists for plugin '#{params[:plugin_name]}' (use --override=yes or --default=no)" \
|
1099
|
+
if !option_override && params[:option_default] && @config_presets[CONF_PRESET_DEFAULT].has_key?(params[:plugin_name])
|
1100
|
+
raise CliError,"Preset already exists: #{params[:preset_name]} (use --override=yes or --id=<name>)" \
|
1101
|
+
if !option_override && @config_presets.has_key?(params[:preset_name])
|
1102
|
+
# lets see if path to priv key is provided
|
1103
|
+
private_key_path = options.get_option(:pkeypath)
|
1104
|
+
# give a chance to provide
|
1105
|
+
if private_key_path.nil?
|
1106
|
+
self.format.display_status('Please provide path to your private RSA key, or empty to generate one:')
|
1107
|
+
private_key_path = options.get_option(:pkeypath,is_type: :mandatory).to_s
|
1108
|
+
end
|
1109
|
+
# else generate path
|
1110
|
+
if private_key_path.empty?
|
1111
|
+
private_key_path = File.join(@main_folder,DEFAULT_PRIV_KEY_FILENAME)
|
1112
|
+
end
|
1113
|
+
if File.exist?(private_key_path)
|
1114
|
+
self.format.display_status('Using existing key:')
|
1115
|
+
else
|
1116
|
+
self.format.display_status("Generating #{DEFAULT_PRIVKEY_LENGTH} bit RSA key...")
|
1117
|
+
generate_rsa_private_key(private_key_path,DEFAULT_PRIVKEY_LENGTH)
|
1118
|
+
self.format.display_status('Created:')
|
1119
|
+
end
|
1120
|
+
self.format.display_status(private_key_path)
|
1121
|
+
pub_key_pem = OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
|
1122
|
+
# declare command line options for AoC
|
1123
|
+
require 'aspera/cli/plugins/aoc'
|
1124
|
+
# make username mandatory for jwt, this triggers interactive input
|
1125
|
+
options.get_option(:username,is_type: :mandatory)
|
1126
|
+
# instanciate AoC plugin, so that command line options are known
|
1127
|
+
aoc_api = self.class.plugin_class(params[:plugin_name]).new(@agents.merge({skip_basic_auth_options: true, private_key_path: private_key_path})).aoc_api
|
1128
|
+
auto_set_pub_key = false
|
1129
|
+
auto_set_jwt = false
|
1130
|
+
use_browser_authentication = false
|
1131
|
+
if options.get_option(:use_generic_client)
|
1132
|
+
self.format.display_status('Using global client_id.')
|
1133
|
+
self.format.display_status('Please Login to your Aspera on Cloud instance.'.red)
|
1134
|
+
self.format.display_status('Navigate to your "Account Settings"'.red)
|
1135
|
+
self.format.display_status('Check or update the value of "Public Key" to be:'.red.blink)
|
1136
|
+
self.format.display_status(pub_key_pem.to_s)
|
1137
|
+
if !options.get_option(:test_mode)
|
1138
|
+
self.format.display_status('Once updated or validated, press enter.')
|
1139
|
+
OpenApplication.instance.uri(params[:instance_url])
|
1140
|
+
$stdin.gets
|
1141
|
+
end
|
1142
|
+
else
|
1143
|
+
self.format.display_status('Using organization specific client_id.')
|
1144
|
+
if options.get_option(:client_id).nil? || options.get_option(:client_secret,is_type: :optional).nil?
|
1145
|
+
self.format.display_status('Please login to your Aspera on Cloud instance.'.red)
|
1146
|
+
self.format.display_status('Go to: Apps->Admin->Organization->Integrations')
|
1147
|
+
self.format.display_status('Create or check if there is an existing integration named:')
|
1148
|
+
self.format.display_status("- name: #{@info[:name]}")
|
1149
|
+
self.format.display_status("- redirect uri: #{DEFAULT_REDIRECT}")
|
1150
|
+
self.format.display_status('- origin: localhost')
|
1151
|
+
self.format.display_status('Once created or identified,')
|
1152
|
+
self.format.display_status('Please enter:'.red)
|
1153
|
+
end
|
1154
|
+
OpenApplication.instance.uri("#{params[:instance_url]}/#{AOC_PATH_API_CLIENTS}")
|
1155
|
+
options.get_option(:client_id,is_type: :mandatory)
|
1156
|
+
options.get_option(:client_secret,is_type: :mandatory)
|
1157
|
+
use_browser_authentication = true
|
1158
|
+
end
|
1159
|
+
if use_browser_authentication
|
1160
|
+
self.format.display_status('We will use web authentication to bootstrap.')
|
1161
|
+
auto_set_pub_key = true
|
1162
|
+
auto_set_jwt = true
|
1163
|
+
aoc_api.oauth.gparams[:crtype] = :web
|
1164
|
+
aoc_api.oauth.gparams[:scope] = AoC::SCOPE_FILES_ADMIN
|
1165
|
+
aoc_api.oauth.sparams[:redirect_uri] = DEFAULT_REDIRECT
|
1166
|
+
end
|
1167
|
+
myself = aoc_api.read('self')[:data]
|
1168
|
+
if auto_set_pub_key
|
1169
|
+
raise CliError,'Public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? || option_override
|
1170
|
+
self.format.display_status('Updating profile with new key')
|
1171
|
+
aoc_api.update("users/#{myself['id']}",{'public_key' => pub_key_pem})
|
1172
|
+
end
|
1173
|
+
if auto_set_jwt
|
1174
|
+
self.format.display_status('Enabling JWT for client')
|
1175
|
+
aoc_api.update("clients/#{options.get_option(:client_id)}",{'jwt_grant_enabled' => true,'explicit_authorization_required' => false})
|
1176
|
+
end
|
1177
|
+
self.format.display_status("Creating new config preset: #{params[:preset_name]}")
|
1178
|
+
@config_presets[params[:preset_name]] = {
|
1179
|
+
:url.to_s => options.get_option(:url),
|
1180
|
+
:username.to_s => myself['email'],
|
1181
|
+
:auth.to_s => :jwt.to_s,
|
1182
|
+
:private_key.to_s => '@file:' + private_key_path
|
1183
|
+
}
|
1184
|
+
# set only if non nil
|
1185
|
+
%i[client_id client_secret].each do |s|
|
1186
|
+
o = options.get_option(s)
|
1187
|
+
@config_presets[params[:preset_name]][s.to_s] = o unless o.nil?
|
1188
|
+
end
|
1189
|
+
params[:test_args] = "#{params[:plugin_name]} user profile show"
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
def wizard_faspex5(params)
|
1193
|
+
self.format.display_status('Detected: Faspex v5'.bold)
|
1194
|
+
# if not defined by user, generate unique name
|
1195
|
+
params[:preset_name] = [params[:application],URI.parse(params[:instance_url]).host.gsub(/[^a-z0-9.]/,'').split('.')].flatten.join('_') \
|
1196
|
+
if params[:preset_name].nil?
|
1197
|
+
self.format.display_status("Preparing preset: #{params[:preset_name]}")
|
1198
|
+
# init defaults if necessary
|
1199
|
+
@config_presets[CONF_PRESET_DEFAULT] ||= {}
|
1200
|
+
option_override = options.get_option(:override,is_type: :mandatory)
|
1201
|
+
params[:option_default] = options.get_option(:default,is_type: :mandatory)
|
1202
|
+
Log.log.error("override=#{option_override} -> #{option_override.class}")
|
1203
|
+
raise CliError,"A default configuration already exists for plugin '#{params[:plugin_name]}' (use --override=yes or --default=no)" \
|
1204
|
+
if !option_override && params[:option_default] && @config_presets[CONF_PRESET_DEFAULT].has_key?(params[:plugin_name])
|
1205
|
+
raise CliError,"Preset already exists: #{params[:preset_name]} (use --override=yes or --id=<name>)" \
|
1206
|
+
if !option_override && @config_presets.has_key?(params[:preset_name])
|
1207
|
+
# lets see if path to priv key is provided
|
1208
|
+
private_key_path = options.get_option(:pkeypath)
|
1209
|
+
# give a chance to provide
|
1210
|
+
if private_key_path.nil?
|
1211
|
+
self.format.display_status('Please provide path to your private RSA key, or empty to generate one:')
|
1212
|
+
private_key_path = options.get_option(:pkeypath,is_type: :mandatory).to_s
|
1213
|
+
end
|
1214
|
+
# else generate path
|
1215
|
+
if private_key_path.empty?
|
1216
|
+
private_key_path = File.join(@main_folder,DEFAULT_PRIV_KEY_FILENAME)
|
1217
|
+
end
|
1218
|
+
if File.exist?(private_key_path)
|
1219
|
+
self.format.display_status('Using existing key:')
|
1220
|
+
else
|
1221
|
+
self.format.display_status("Generating #{DEFAULT_PRIVKEY_LENGTH} bit RSA key...")
|
1222
|
+
generate_rsa_private_key(private_key_path,DEFAULT_PRIVKEY_LENGTH)
|
1223
|
+
self.format.display_status('Created:')
|
1224
|
+
end
|
1225
|
+
self.format.display_status(private_key_path)
|
1226
|
+
pub_key_pem = OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
|
1227
|
+
# declare command line options for AoC
|
1228
|
+
require 'aspera/cli/plugins/faspex5'
|
1229
|
+
self.class.plugin_class(params[:plugin_name]).new(@agents.merge({skip_basic_auth_options: true}))
|
1230
|
+
self.format.display_status('Please login to Faspex 5.'.red)
|
1231
|
+
OpenApplication.instance.uri(params[:instance_url])
|
1232
|
+
self.format.display_status('Navigate to: 𓃑 → Admin → Configurations → API clients')
|
1233
|
+
self.format.display_status('Create a client with:')
|
1234
|
+
self.format.display_status('- JWT enabled')
|
1235
|
+
self.format.display_status('- The following public key:')
|
1236
|
+
self.format.display_status(pub_key_pem.to_s)
|
1237
|
+
self.format.display_status('Once created, copy the following parameters:')
|
1238
|
+
@config_presets[params[:preset_name]] = {
|
1239
|
+
:url.to_s => options.get_option(:url),
|
1240
|
+
:username.to_s => options.get_option(:username),
|
1241
|
+
:auth.to_s => :jwt.to_s,
|
1242
|
+
:private_key.to_s => '@file:' + private_key_path,
|
1243
|
+
:client_id.to_s => options.get_option(:client_id,is_type: :mandatory),
|
1244
|
+
:client_secret.to_s => options.get_option(:client_secret,is_type: :mandatory)
|
1245
|
+
}
|
1246
|
+
params[:test_args] = "#{params[:plugin_name]} user profile show"
|
1247
|
+
end
|
1068
1248
|
end
|
1069
1249
|
end
|
1070
1250
|
end
|