aspera-cli 4.2.1 → 4.5.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
- data/README.md +1580 -946
- data/bin/ascli +1 -1
- data/bin/asession +3 -5
- data/docs/Makefile +8 -11
- data/docs/README.erb.md +1521 -829
- data/docs/doc_tools.rb +58 -0
- data/docs/test_env.conf +3 -1
- data/examples/faspex4.rb +28 -19
- data/examples/transfer.rb +2 -2
- data/lib/aspera/aoc.rb +157 -134
- data/lib/aspera/cli/listener/progress_multi.rb +5 -5
- data/lib/aspera/cli/main.rb +106 -48
- data/lib/aspera/cli/manager.rb +19 -20
- data/lib/aspera/cli/plugin.rb +22 -7
- data/lib/aspera/cli/plugins/aoc.rb +260 -208
- data/lib/aspera/cli/plugins/ats.rb +11 -10
- data/lib/aspera/cli/plugins/bss.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +360 -189
- data/lib/aspera/cli/plugins/faspex.rb +119 -56
- data/lib/aspera/cli/plugins/faspex5.rb +32 -17
- data/lib/aspera/cli/plugins/node.rb +72 -31
- data/lib/aspera/cli/plugins/orchestrator.rb +5 -3
- data/lib/aspera/cli/plugins/preview.rb +94 -68
- data/lib/aspera/cli/plugins/server.rb +16 -5
- data/lib/aspera/cli/plugins/shares.rb +17 -0
- data/lib/aspera/cli/transfer_agent.rb +64 -82
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +48 -31
- data/lib/aspera/cos_node.rb +4 -3
- data/lib/aspera/environment.rb +4 -4
- data/lib/aspera/fasp/{manager.rb → agent_base.rb} +7 -6
- data/lib/aspera/fasp/{connect.rb → agent_connect.rb} +46 -39
- data/lib/aspera/fasp/{local.rb → agent_direct.rb} +42 -38
- data/lib/aspera/fasp/{http_gw.rb → agent_httpgw.rb} +50 -29
- data/lib/aspera/fasp/{node.rb → agent_node.rb} +43 -4
- data/lib/aspera/fasp/agent_trsdk.rb +106 -0
- data/lib/aspera/fasp/default.rb +17 -0
- data/lib/aspera/fasp/installation.rb +64 -48
- data/lib/aspera/fasp/parameters.rb +78 -91
- data/lib/aspera/fasp/parameters.yaml +531 -0
- data/lib/aspera/fasp/uri.rb +1 -1
- data/lib/aspera/faspex_gw.rb +12 -11
- data/lib/aspera/id_generator.rb +22 -0
- data/lib/aspera/keychain/encrypted_hash.rb +120 -0
- data/lib/aspera/keychain/macos_security.rb +94 -0
- data/lib/aspera/log.rb +45 -32
- data/lib/aspera/node.rb +9 -4
- data/lib/aspera/oauth.rb +116 -100
- data/lib/aspera/persistency_action_once.rb +11 -7
- data/lib/aspera/persistency_folder.rb +6 -26
- data/lib/aspera/rest.rb +66 -50
- data/lib/aspera/sync.rb +40 -35
- data/lib/aspera/timer_limiter.rb +22 -0
- metadata +86 -29
- data/docs/transfer_spec.html +0 -99
- data/lib/aspera/api_detector.rb +0 -60
- data/lib/aspera/fasp/aoc.rb +0 -24
- data/lib/aspera/secrets.rb +0 -20
@@ -1,18 +1,22 @@
|
|
1
1
|
require 'aspera/cli/basic_auth_plugin'
|
2
2
|
require 'aspera/cli/extended_value'
|
3
3
|
require 'aspera/fasp/installation'
|
4
|
-
require 'aspera/
|
4
|
+
require 'aspera/fasp/parameters'
|
5
5
|
require 'aspera/open_application'
|
6
6
|
require 'aspera/aoc'
|
7
7
|
require 'aspera/proxy_auto_config'
|
8
8
|
require 'aspera/uri_reader'
|
9
9
|
require 'aspera/rest'
|
10
10
|
require 'aspera/persistency_action_once'
|
11
|
+
require 'aspera/id_generator'
|
12
|
+
require 'aspera/keychain/encrypted_hash'
|
13
|
+
require 'aspera/keychain/macos_security'
|
11
14
|
require 'xmlsimple'
|
12
15
|
require 'base64'
|
13
16
|
require 'net/smtp'
|
14
17
|
require 'open3'
|
15
18
|
require 'date'
|
19
|
+
require 'erb'
|
16
20
|
|
17
21
|
module Aspera
|
18
22
|
module Cli
|
@@ -28,6 +32,7 @@ module Aspera
|
|
28
32
|
CONF_PRESET_VERSION='version'
|
29
33
|
CONF_PRESET_DEFAULT='default'
|
30
34
|
CONF_PRESET_GLOBAL='global_common_defaults'
|
35
|
+
CONF_PRESET_SECRETS='default_secrets'
|
31
36
|
CONF_PLUGIN_SYM = :config # Plugins::Config.name.split('::').last.downcase.to_sym
|
32
37
|
CONF_GLOBAL_SYM = :config
|
33
38
|
# old tool name
|
@@ -42,28 +47,53 @@ module Aspera
|
|
42
47
|
AOC_COMMAND_V2='aspera'
|
43
48
|
AOC_COMMAND_V3='aoc'
|
44
49
|
AOC_COMMAND_CURRENT=AOC_COMMAND_V3
|
50
|
+
SERVER_COMMAND='server'
|
45
51
|
CONNECT_WEB_URL = 'https://d3gcli72yxqn2z.cloudfront.net/connect'
|
46
52
|
CONNECT_VERSIONS = 'connectversions.js'
|
47
|
-
TRANSFER_SDK_ARCHIVE_URL = 'https://ibm.biz/
|
53
|
+
TRANSFER_SDK_ARCHIVE_URL = 'https://ibm.biz/aspera_transfer_sdk'
|
48
54
|
DEMO='demo'
|
49
55
|
DEMO_SERVER_PRESET='demoserver'
|
50
56
|
AOC_PATH_API_CLIENTS='admin/api-clients'
|
57
|
+
EMAIL_TEST_TEMPLATE=<<END_OF_TEMPLATE
|
58
|
+
From: <%=from_name%> <<%=from_email%>>
|
59
|
+
To: <<%=to%>>
|
60
|
+
Subject: Amelia email test
|
61
|
+
|
62
|
+
It worked !
|
63
|
+
END_OF_TEMPLATE
|
64
|
+
# special extended values
|
65
|
+
EXTV_INCLUDE_PRESETS='incps'
|
66
|
+
EXTV_PRESET='preset'
|
67
|
+
DEFAULT_CHECK_NEW_VERSION_DAYS=7
|
68
|
+
DEFAULT_PRIV_KEY_FILENAME='aspera_aoc_key'
|
69
|
+
DEFAULT_PRIVKEY_LENGTH=4096
|
70
|
+
private_constant :DEFAULT_CONFIG_FILENAME,:CONF_PRESET_CONFIG,:CONF_PRESET_VERSION,:CONF_PRESET_DEFAULT,
|
71
|
+
:CONF_PRESET_GLOBAL,:PROGRAM_NAME_V1,:PROGRAM_NAME_V2,:DEFAULT_REDIRECT,:ASPERA_PLUGINS_FOLDERNAME,
|
72
|
+
:RUBY_FILE_EXT,:AOC_COMMAND_V1,:AOC_COMMAND_V2,:AOC_COMMAND_V3,:AOC_COMMAND_CURRENT,:DEMO,
|
73
|
+
:TRANSFER_SDK_ARCHIVE_URL,:AOC_PATH_API_CLIENTS,:DEMO_SERVER_PRESET,:EMAIL_TEST_TEMPLATE,:EXTV_INCLUDE_PRESETS,
|
74
|
+
:EXTV_PRESET,:DEFAULT_CHECK_NEW_VERSION_DAYS,:DEFAULT_PRIV_KEY_FILENAME,:SERVER_COMMAND,:CONF_PRESET_SECRETS
|
51
75
|
def option_preset; nil; end
|
52
76
|
|
53
77
|
def option_preset=(value)
|
54
|
-
|
78
|
+
case value
|
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
|
55
87
|
end
|
56
88
|
|
57
|
-
private_constant :DEFAULT_CONFIG_FILENAME,:CONF_PRESET_CONFIG,:CONF_PRESET_VERSION,:CONF_PRESET_DEFAULT,:CONF_PRESET_GLOBAL,:PROGRAM_NAME_V1,:PROGRAM_NAME_V2,:DEFAULT_REDIRECT,:ASPERA_PLUGINS_FOLDERNAME,:RUBY_FILE_EXT,:AOC_COMMAND_V1,:AOC_COMMAND_V2,:AOC_COMMAND_V3,:AOC_COMMAND_CURRENT,:DEMO,:TRANSFER_SDK_ARCHIVE_URL,:AOC_PATH_API_CLIENTS,:DEMO_SERVER_PRESET
|
58
|
-
|
59
89
|
def initialize(env,tool_name,help_url,version,main_folder)
|
60
90
|
super(env)
|
61
|
-
raise 'missing secret manager' if @agents[:secret].nil?
|
62
91
|
@plugins={}
|
63
92
|
@plugin_lookup_folders=[]
|
64
93
|
@use_plugin_defaults=true
|
65
94
|
@config_presets=nil
|
66
95
|
@connect_versions=nil
|
96
|
+
@vault=nil
|
67
97
|
@program_version=version
|
68
98
|
@tool_name=tool_name
|
69
99
|
@help_url=help_url
|
@@ -83,35 +113,38 @@ module Aspera
|
|
83
113
|
# add preset handler (needed for smtp)
|
84
114
|
ExtendedValue.instance.set_handler(EXTV_PRESET,:reader,lambda{|v|preset_by_name(v)})
|
85
115
|
ExtendedValue.instance.set_handler(EXTV_INCLUDE_PRESETS,:decoder,lambda{|v|expanded_with_preset_includes(v)})
|
86
|
-
|
116
|
+
# load defaults before it can be overriden
|
117
|
+
self.add_plugin_default_preset(CONF_GLOBAL_SYM)
|
118
|
+
self.options.parse_options!
|
87
119
|
self.options.set_obj_attr(:ascp_path,self,:option_ascp_path)
|
88
120
|
self.options.set_obj_attr(:use_product,self,:option_use_product)
|
89
121
|
self.options.set_obj_attr(:preset,self,:option_preset)
|
90
|
-
self.options.set_obj_attr(:secret,@agents[:secret],:default_secret)
|
91
|
-
self.options.set_obj_attr(:secrets,@agents[:secret],:all_secrets)
|
92
|
-
self.options.add_opt_boolean(:override,'override existing value')
|
93
122
|
self.options.add_opt_switch(:no_default,'-N','do not load default configuration for plugin') { @use_plugin_defaults=false }
|
94
|
-
self.options.add_opt_boolean(:
|
95
|
-
self.options.
|
123
|
+
self.options.add_opt_boolean(:override,'Wizard: override existing value')
|
124
|
+
self.options.add_opt_boolean(:use_generic_client,'Wizard: AoC: use global or org specific jwt client id')
|
125
|
+
self.options.add_opt_boolean(:default,'Wizard: set as default configuration for specified plugin (also: update)')
|
126
|
+
self.options.add_opt_boolean(:test_mode,'Wizard: skip private key check step')
|
127
|
+
self.options.add_opt_simple(:preset,'-PVALUE','load the named option preset from current config file')
|
128
|
+
self.options.add_opt_simple(:pkeypath,'Wizard: path to private key for JWT')
|
96
129
|
self.options.add_opt_simple(:ascp_path,'path to ascp')
|
97
130
|
self.options.add_opt_simple(:use_product,'use ascp from specified product')
|
98
131
|
self.options.add_opt_simple(:smtp,'smtp configuration (extended value: hash)')
|
99
132
|
self.options.add_opt_simple(:fpac,'proxy auto configuration URL')
|
100
|
-
self.options.add_opt_simple(:preset,'-PVALUE','load the named option preset from current config file')
|
101
|
-
self.options.add_opt_simple(:default,'set as default configuration for specified plugin')
|
102
133
|
self.options.add_opt_simple(:secret,'default secret')
|
103
|
-
self.options.add_opt_simple(:secrets,'secret
|
134
|
+
self.options.add_opt_simple(:secrets,'secret vault')
|
104
135
|
self.options.add_opt_simple(:sdk_url,'URL to get SDK')
|
105
|
-
self.options.add_opt_simple(:sdk_folder,'SDK folder
|
106
|
-
self.options.
|
107
|
-
self.options.add_opt_simple(:
|
136
|
+
self.options.add_opt_simple(:sdk_folder,'SDK folder path')
|
137
|
+
self.options.add_opt_simple(:notif_to,'email recipient for notification of transfers')
|
138
|
+
self.options.add_opt_simple(:notif_template,'email ERB template for notification of transfers')
|
139
|
+
self.options.add_opt_simple(:version_check_days,Integer,'period in days to check new version (zero to disable)')
|
108
140
|
self.options.set_option(:use_generic_client,true)
|
109
141
|
self.options.set_option(:test_mode,false)
|
110
|
-
self.options.set_option(:
|
142
|
+
self.options.set_option(:default,true)
|
143
|
+
self.options.set_option(:version_check_days,DEFAULT_CHECK_NEW_VERSION_DAYS)
|
111
144
|
self.options.set_option(:sdk_url,TRANSFER_SDK_ARCHIVE_URL)
|
112
145
|
self.options.set_option(:sdk_folder,File.join(@main_folder,'sdk'))
|
146
|
+
self.options.set_option(:override,:no)
|
113
147
|
self.options.parse_options!
|
114
|
-
raise CliBadArgument,'secrets shall be Hash' unless @agents[:secret].all_secrets.is_a?(Hash)
|
115
148
|
Fasp::Installation.instance.folder=self.options.get_option(:sdk_folder,:mandatory)
|
116
149
|
end
|
117
150
|
|
@@ -137,7 +170,7 @@ module Aspera
|
|
137
170
|
check_date_persist=PersistencyActionOnce.new(
|
138
171
|
manager: persistency,
|
139
172
|
data: last_check_array,
|
140
|
-
|
173
|
+
id: 'version_last_check')
|
141
174
|
# get persisted date or nil
|
142
175
|
last_check_date = begin
|
143
176
|
Date.strptime(last_check_array.first, '%Y/%m/%d')
|
@@ -160,8 +193,8 @@ module Aspera
|
|
160
193
|
# retrieve structure from cloud (CDN) with all versions available
|
161
194
|
def connect_versions
|
162
195
|
if @connect_versions.nil?
|
163
|
-
api_connect_cdn=Rest.new({:
|
164
|
-
javascript=api_connect_cdn.call({:
|
196
|
+
api_connect_cdn=Rest.new({base_url: CONNECT_WEB_URL})
|
197
|
+
javascript=api_connect_cdn.call({operation: 'GET',subpath: CONNECT_VERSIONS})
|
165
198
|
# get result on one line
|
166
199
|
connect_versions_javascript=javascript[:http].body.gsub(/\r?\n\s*/,'')
|
167
200
|
Log.log.debug("javascript=[\n#{connect_versions_javascript}\n]")
|
@@ -186,9 +219,9 @@ module Aspera
|
|
186
219
|
end
|
187
220
|
private
|
188
221
|
|
189
|
-
def
|
222
|
+
def generate_rsa_private_key(private_key_path,length)
|
190
223
|
require 'openssl'
|
191
|
-
priv_key = OpenSSL::PKey::RSA.new(
|
224
|
+
priv_key = OpenSSL::PKey::RSA.new(length)
|
192
225
|
File.write(private_key_path,priv_key.to_s)
|
193
226
|
File.write(private_key_path+'.pub',priv_key.public_key.to_s)
|
194
227
|
nil
|
@@ -207,9 +240,9 @@ module Aspera
|
|
207
240
|
|
208
241
|
# instanciate a plugin
|
209
242
|
# plugins must be Capitalized
|
210
|
-
def self.
|
243
|
+
def self.plugin_class(plugin_name_sym)
|
211
244
|
# Module.nesting[2] is Aspera::Cli
|
212
|
-
return Object::const_get("#{Module.nesting[2].to_s}::Plugins::#{plugin_name_sym.to_s.capitalize}")
|
245
|
+
return Object::const_get("#{Module.nesting[2].to_s}::Plugins::#{plugin_name_sym.to_s.capitalize}")
|
213
246
|
end
|
214
247
|
|
215
248
|
def self.flatten_all_config(t)
|
@@ -224,10 +257,15 @@ module Aspera
|
|
224
257
|
|
225
258
|
# set parameter and value in global config
|
226
259
|
# creates one if none already created
|
227
|
-
# @return preset that contains global default
|
260
|
+
# @return preset name that contains global default
|
228
261
|
def set_global_default(key,value)
|
229
262
|
# get default preset if it exists
|
230
|
-
global_default_preset_name=get_plugin_default_config_name(CONF_GLOBAL_SYM)
|
263
|
+
global_default_preset_name=get_plugin_default_config_name(CONF_GLOBAL_SYM)
|
264
|
+
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
|
268
|
+
end
|
231
269
|
@config_presets[global_default_preset_name]||={}
|
232
270
|
@config_presets[global_default_preset_name][key.to_s]=value
|
233
271
|
self.format.display_status("Updated: #{global_default_preset_name}: #{key} <- #{value}")
|
@@ -241,12 +279,8 @@ module Aspera
|
|
241
279
|
attr_reader :main_folder
|
242
280
|
attr_reader :gem_url
|
243
281
|
attr_reader :plugins
|
244
|
-
attr_accessor :option_override
|
245
282
|
attr_accessor :option_config_file
|
246
283
|
|
247
|
-
EXTV_INCLUDE_PRESETS='incps'
|
248
|
-
EXTV_PRESET='preset'
|
249
|
-
|
250
284
|
# @return the hash from name (also expands possible includes)
|
251
285
|
def preset_by_name(config_name, include_path=[])
|
252
286
|
raise CliError,"no such config preset: #{config_name}" unless @config_presets.has_key?(config_name)
|
@@ -331,11 +365,11 @@ module Aspera
|
|
331
365
|
Log.log.warn("No config file found. Creating empty configuration file: #{@option_config_file}")
|
332
366
|
@config_presets={CONF_PRESET_CONFIG=>{CONF_PRESET_VERSION=>@program_version}}
|
333
367
|
else
|
334
|
-
Log.log.debug
|
368
|
+
Log.log.debug("loading #{@option_config_file}")
|
335
369
|
@config_presets=YAML.load_file(conf_file_to_load)
|
336
370
|
end
|
337
371
|
files_to_copy=[]
|
338
|
-
Log.log.debug
|
372
|
+
Log.log.debug("Available_presets: #{@config_presets}")
|
339
373
|
raise 'Expecting YAML Hash' unless @config_presets.is_a?(Hash)
|
340
374
|
# check there is at least the config section
|
341
375
|
if !@config_presets.has_key?(CONF_PRESET_CONFIG)
|
@@ -419,14 +453,42 @@ module Aspera
|
|
419
453
|
Log.log.warn("skipping plugin already registered: #{plugin_symbol}")
|
420
454
|
return
|
421
455
|
end
|
422
|
-
@plugins[plugin_symbol]={:
|
456
|
+
@plugins[plugin_symbol]={source: path,require_stanza: req}
|
457
|
+
end
|
458
|
+
|
459
|
+
def identify_plugin_for_url(url)
|
460
|
+
plugins.each do |plugin_name_sym,plugin_info|
|
461
|
+
next if plugin_name_sym.eql?(CONF_PLUGIN_SYM)
|
462
|
+
require plugin_info[:require_stanza]
|
463
|
+
c=self.class.plugin_class(plugin_name_sym)
|
464
|
+
if c.respond_to?(:detect)
|
465
|
+
current_url=url
|
466
|
+
begin
|
467
|
+
res=c.send(:detect,current_url)
|
468
|
+
return res.merge(product: plugin_name_sym, url: current_url) unless res.nil?
|
469
|
+
rescue
|
470
|
+
end
|
471
|
+
begin
|
472
|
+
# is there a redirect ?
|
473
|
+
result=Rest.new({:base_url=>url}).call({operation: 'GET',subpath: '',redirect_max: 1})
|
474
|
+
current_url=result[:http].uri.to_s
|
475
|
+
# check if redirect
|
476
|
+
if ! url.eql?(current_url)
|
477
|
+
res=c.send(:detect,current_url)
|
478
|
+
return res.merge(product: plugin_name_sym, url: current_url) unless res.nil?
|
479
|
+
end
|
480
|
+
rescue
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
484
|
+
raise "No known application found at #{url}"
|
423
485
|
end
|
424
486
|
|
425
487
|
def execute_connect_action
|
426
488
|
command=self.options.get_next_command([:list,:id])
|
427
489
|
case command
|
428
490
|
when :list
|
429
|
-
return {:
|
491
|
+
return {type: :object_list, data: connect_versions, fields: ['id','title','version']}
|
430
492
|
when :id
|
431
493
|
connect_id=self.options.get_next_argument('id or title')
|
432
494
|
one_res=connect_versions.select{|i|i['id'].eql?(connect_id) || i['title'].eql?(connect_id)}.first
|
@@ -435,13 +497,13 @@ module Aspera
|
|
435
497
|
case command
|
436
498
|
when :info # shows files used
|
437
499
|
one_res.delete('links')
|
438
|
-
return {:
|
500
|
+
return {type: :single_object, data: one_res}
|
439
501
|
when :links # shows files used
|
440
502
|
command=self.options.get_next_command([:list,:id])
|
441
503
|
all_links=one_res['links']
|
442
504
|
case command
|
443
505
|
when :list # shows files used
|
444
|
-
return {:
|
506
|
+
return {type: :object_list, data: all_links}
|
445
507
|
when :id
|
446
508
|
link_title=self.options.get_next_argument('title')
|
447
509
|
one_link=all_links.select {|i| i['title'].eql?(link_title)}.first
|
@@ -450,10 +512,10 @@ module Aspera
|
|
450
512
|
when :download #
|
451
513
|
folder_dest=self.transfer.destination_folder('receive')
|
452
514
|
#folder_dest=self.options.get_next_argument('destination folder')
|
453
|
-
api_connect_cdn=Rest.new({:
|
515
|
+
api_connect_cdn=Rest.new({base_url: CONNECT_WEB_URL})
|
454
516
|
fileurl = one_link['href']
|
455
517
|
filename=fileurl.gsub(%r{.*/},'')
|
456
|
-
api_connect_cdn.call({:
|
518
|
+
api_connect_cdn.call({operation: 'GET',subpath: fileurl,save_to_file: File.join(folder_dest,filename)})
|
457
519
|
return Main.result_status("Downloaded: #{filename}")
|
458
520
|
when :open #
|
459
521
|
OpenApplication.instance.uri(one_link['href'])
|
@@ -465,7 +527,7 @@ module Aspera
|
|
465
527
|
end
|
466
528
|
|
467
529
|
def execute_action_ascp
|
468
|
-
command=self.options.get_next_command([:connect,:use,:show,:products,:info,:install])
|
530
|
+
command=self.options.get_next_command([:connect,:use,:show,:products,:info,:install,:spec])
|
469
531
|
case command
|
470
532
|
when :connect
|
471
533
|
return execute_connect_action
|
@@ -476,7 +538,7 @@ module Aspera
|
|
476
538
|
preset_name=set_global_default(:ascp_path,ascp_path)
|
477
539
|
return Main.result_status("Saved to default global preset #{preset_name}")
|
478
540
|
when :show # shows files used
|
479
|
-
return {:
|
541
|
+
return {type: :status, data: Fasp::Installation.instance.path(:ascp)}
|
480
542
|
when :info # shows files used
|
481
543
|
data=Fasp::Installation::FILES.inject({}) do |m,v|
|
482
544
|
m[v.to_s]=Fasp::Installation.instance.path(v) rescue 'Not Found'
|
@@ -501,12 +563,12 @@ module Aspera
|
|
501
563
|
end
|
502
564
|
end
|
503
565
|
data['keypass']=Fasp::Installation.instance.bypass_pass
|
504
|
-
return {:
|
566
|
+
return {type: :single_object, data: data}
|
505
567
|
when :products
|
506
568
|
command=self.options.get_next_command([:list,:use])
|
507
569
|
case command
|
508
570
|
when :list
|
509
|
-
return {:
|
571
|
+
return {type: :object_list, data: Fasp::Installation.instance.installed_products, fields: ['name','app_root']}
|
510
572
|
when :use
|
511
573
|
default_product=self.options.get_next_argument('product name')
|
512
574
|
Fasp::Installation.instance.use_ascp_from_product(default_product)
|
@@ -516,131 +578,155 @@ module Aspera
|
|
516
578
|
when :install
|
517
579
|
v=Fasp::Installation.instance.install_sdk(self.options.get_option(:sdk_url,:mandatory))
|
518
580
|
return Main.result_status("Installed version #{v}")
|
581
|
+
when :spec
|
582
|
+
return {type: :object_list, data: Fasp::Parameters.man_table, fields: ['name','type',Fasp::Parameters::SUPPORTED_AGENTS_SHORT.map{|i|i.to_s},'description'].flatten}
|
519
583
|
end
|
520
584
|
raise "unexpected case: #{command}"
|
521
585
|
end
|
522
586
|
|
523
|
-
|
587
|
+
# legacy actions available globally
|
588
|
+
PRESET_GBL_ACTIONS=[:list,:overview].freeze
|
589
|
+
# require existing preset
|
590
|
+
PRESET_EXST_ACTIONS=[:show,:delete,:get,:unset].freeze
|
591
|
+
# require id
|
592
|
+
PRESET_INSTANCE_ACTIONS=[PRESET_EXST_ACTIONS,:initialize,:update,:ask,:set].flatten.freeze
|
593
|
+
PRESET_ALL_ACTIONS=[PRESET_GBL_ACTIONS,PRESET_INSTANCE_ACTIONS].flatten.freeze
|
594
|
+
|
595
|
+
def execute_file_action(action,config_name)
|
596
|
+
action=self.options.get_next_command(PRESET_ALL_ACTIONS) if action.nil?
|
597
|
+
config_name=instance_identifier() if config_name.nil? and PRESET_INSTANCE_ACTIONS.include?(action)
|
598
|
+
# those operations require existing option
|
599
|
+
raise "no such preset: #{config_name}" if PRESET_EXST_ACTIONS.include?(action) and !@config_presets.has_key?(config_name)
|
600
|
+
selected_preset=@config_presets[config_name]
|
601
|
+
case action
|
602
|
+
when :list
|
603
|
+
return {type: :value_list, data: @config_presets.keys, name: 'name'}
|
604
|
+
when :overview
|
605
|
+
return {type: :object_list, data: self.class.flatten_all_config(@config_presets)}
|
606
|
+
when :show
|
607
|
+
raise "no such config: #{config_name}" if selected_preset.nil?
|
608
|
+
return {type: :single_object, data: selected_preset}
|
609
|
+
when :delete
|
610
|
+
@config_presets.delete(config_name)
|
611
|
+
save_presets_to_config_file
|
612
|
+
return Main.result_status("Deleted: #{config_name}")
|
613
|
+
when :get
|
614
|
+
param_name=self.options.get_next_argument('parameter name')
|
615
|
+
value=selected_preset[param_name]
|
616
|
+
raise "no such option in preset #{config_name} : #{param_name}" if value.nil?
|
617
|
+
case value
|
618
|
+
when Numeric,String; return {type: :text, data: ExtendedValue.instance.evaluate(value.to_s)}
|
619
|
+
end
|
620
|
+
return {type: :single_object, data: value}
|
621
|
+
when :unset
|
622
|
+
param_name=self.options.get_next_argument('parameter name')
|
623
|
+
selected_preset.delete(param_name)
|
624
|
+
save_presets_to_config_file
|
625
|
+
return Main.result_status("Removed: #{config_name}: #{param_name}")
|
626
|
+
when :set
|
627
|
+
param_name=self.options.get_next_argument('parameter name')
|
628
|
+
param_value=self.options.get_next_argument('parameter value')
|
629
|
+
if !@config_presets.has_key?(config_name)
|
630
|
+
Log.log.debug("no such config name: #{config_name}, initializing")
|
631
|
+
selected_preset=@config_presets[config_name]={}
|
632
|
+
end
|
633
|
+
if selected_preset.has_key?(param_name)
|
634
|
+
Log.log.warn("overwriting value: #{selected_preset[param_name]}")
|
635
|
+
end
|
636
|
+
selected_preset[param_name]=param_value
|
637
|
+
save_presets_to_config_file
|
638
|
+
return Main.result_status("Updated: #{config_name}: #{param_name} <- #{param_value}")
|
639
|
+
when :initialize
|
640
|
+
config_value=self.options.get_next_argument('extended value (Hash)')
|
641
|
+
if @config_presets.has_key?(config_name)
|
642
|
+
Log.log.warn("configuration already exists: #{config_name}, overwriting")
|
643
|
+
end
|
644
|
+
@config_presets[config_name]=config_value
|
645
|
+
save_presets_to_config_file
|
646
|
+
return Main.result_status("Modified: #{@option_config_file}")
|
647
|
+
when :update
|
648
|
+
# get unprocessed options
|
649
|
+
theopts=self.options.get_options_table
|
650
|
+
Log.log.debug("opts=#{theopts}")
|
651
|
+
@config_presets[config_name]||={}
|
652
|
+
@config_presets[config_name].merge!(theopts)
|
653
|
+
# fix bug in 4.4 (creating key "true" in "default" preset)
|
654
|
+
@config_presets[CONF_PRESET_DEFAULT].delete(true) if @config_presets[CONF_PRESET_DEFAULT].is_a?(Hash)
|
655
|
+
save_presets_to_config_file
|
656
|
+
return Main.result_status("Updated: #{config_name}")
|
657
|
+
when :ask
|
658
|
+
self.options.ask_missing_mandatory=:yes
|
659
|
+
@config_presets[config_name]||={}
|
660
|
+
self.options.get_next_argument('option names',:multiple).each do |optionname|
|
661
|
+
option_value=self.options.get_interactive(:option,optionname)
|
662
|
+
@config_presets[config_name][optionname]=option_value
|
663
|
+
end
|
664
|
+
save_presets_to_config_file
|
665
|
+
return Main.result_status("Updated: #{config_name}")
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
ACTIONS=[PRESET_GBL_ACTIONS,:id,:preset,:open,:documentation,:genkey,:gem_path,:plugins,:flush_tokens,:echo,:wizard,:export_to_cli,:detect,:coffee,:ascp,:email_test,:smtp_settings,:proxy_check,:folder,:file,:check_update,:initdemo,:vault].flatten.freeze
|
524
670
|
|
525
671
|
# "config" plugin
|
526
672
|
def execute_action
|
527
673
|
action=self.options.get_next_command(ACTIONS)
|
528
674
|
case action
|
529
|
-
when
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
return {:type=>:single_object,:data=>selected_preset}
|
539
|
-
when :delete
|
540
|
-
@config_presets.delete(config_name)
|
541
|
-
save_presets_to_config_file
|
542
|
-
return Main.result_status("Deleted: #{config_name}")
|
543
|
-
when :get
|
544
|
-
param_name=self.options.get_next_argument('parameter name')
|
545
|
-
value=selected_preset[param_name]
|
546
|
-
raise "no such option in preset #{config_name} : #{param_name}" if value.nil?
|
547
|
-
case value
|
548
|
-
when Numeric,String; return {:type=>:text,:data=>ExtendedValue.instance.evaluate(value.to_s)}
|
549
|
-
end
|
550
|
-
return {:type=>:single_object,:data=>value}
|
551
|
-
when :unset
|
552
|
-
param_name=self.options.get_next_argument('parameter name')
|
553
|
-
selected_preset.delete(param_name)
|
554
|
-
save_presets_to_config_file
|
555
|
-
return Main.result_status("Removed: #{config_name}: #{param_name}")
|
556
|
-
when :set
|
557
|
-
param_name=self.options.get_next_argument('parameter name')
|
558
|
-
param_value=self.options.get_next_argument('parameter value')
|
559
|
-
if !@config_presets.has_key?(config_name)
|
560
|
-
Log.log.debug("no such config name: #{config_name}, initializing")
|
561
|
-
selected_preset=@config_presets[config_name]={}
|
562
|
-
end
|
563
|
-
if selected_preset.has_key?(param_name)
|
564
|
-
Log.log.warn("overwriting value: #{selected_preset[param_name]}")
|
565
|
-
end
|
566
|
-
selected_preset[param_name]=param_value
|
567
|
-
save_presets_to_config_file
|
568
|
-
return Main.result_status("Updated: #{config_name}: #{param_name} <- #{param_value}")
|
569
|
-
when :initialize
|
570
|
-
config_value=self.options.get_next_argument('extended value (Hash)')
|
571
|
-
if @config_presets.has_key?(config_name)
|
572
|
-
Log.log.warn("configuration already exists: #{config_name}, overwriting")
|
573
|
-
end
|
574
|
-
@config_presets[config_name]=config_value
|
575
|
-
save_presets_to_config_file
|
576
|
-
return Main.result_status("Modified: #{@option_config_file}")
|
577
|
-
when :update
|
578
|
-
default_for_plugin=self.options.get_option(:default,:optional)
|
579
|
-
# get unprocessed options
|
580
|
-
theopts=self.options.get_options_table
|
581
|
-
Log.log.debug("opts=#{theopts}")
|
582
|
-
@config_presets[config_name]||={}
|
583
|
-
@config_presets[config_name].merge!(theopts)
|
584
|
-
if ! default_for_plugin.nil?
|
585
|
-
@config_presets[CONF_PRESET_DEFAULT]||=Hash.new
|
586
|
-
@config_presets[CONF_PRESET_DEFAULT][default_for_plugin]=config_name
|
587
|
-
end
|
588
|
-
save_presets_to_config_file
|
589
|
-
return Main.result_status("Updated: #{config_name}")
|
590
|
-
when :ask
|
591
|
-
self.options.ask_missing_mandatory=:yes
|
592
|
-
@config_presets[config_name]||={}
|
593
|
-
self.options.get_next_argument('option names',:multiple).each do |optionname|
|
594
|
-
option_value=self.options.get_interactive(:option,optionname)
|
595
|
-
@config_presets[config_name][optionname]=option_value
|
596
|
-
end
|
597
|
-
save_presets_to_config_file
|
598
|
-
return Main.result_status("Updated: #{config_name}")
|
599
|
-
end
|
675
|
+
when *PRESET_GBL_ACTIONS # older syntax
|
676
|
+
return execute_file_action(action,nil)
|
677
|
+
when :id # older syntax
|
678
|
+
return execute_file_action(nil,self.options.get_next_argument('config name'))
|
679
|
+
when :preset # newer syntax
|
680
|
+
return execute_file_action(nil,nil)
|
681
|
+
when :open
|
682
|
+
OpenApplication.instance.uri("#{@option_config_file}") #file://
|
683
|
+
return Main.result_nothing
|
600
684
|
when :documentation
|
601
685
|
section=options.get_next_argument('private key file path',:single,:optional)
|
602
686
|
section='#'+section unless section.nil?
|
603
687
|
OpenApplication.instance.uri("#{@help_url}#{section}")
|
604
688
|
return Main.result_nothing
|
605
|
-
when :open
|
606
|
-
OpenApplication.instance.uri("#{@option_config_file}") #file://
|
607
|
-
return Main.result_nothing
|
608
689
|
when :genkey # generate new rsa key
|
609
690
|
private_key_path=self.options.get_next_argument('private key file path')
|
610
|
-
|
691
|
+
generate_rsa_private_key(private_key_path,DEFAULT_PRIVKEY_LENGTH)
|
611
692
|
return Main.result_status('Generated key: '+private_key_path)
|
612
693
|
when :echo # display the content of a value given on command line
|
613
|
-
result={:
|
694
|
+
result={type: :other_struct, data: self.options.get_next_argument('value')}
|
614
695
|
# special for csv
|
615
696
|
result[:type]=:object_list if result[:data].is_a?(Array) and result[:data].first.is_a?(Hash)
|
616
697
|
return result
|
617
698
|
when :flush_tokens
|
618
699
|
deleted_files=Oauth.flush_tokens
|
619
|
-
return {:
|
700
|
+
return {type: :value_list, data: deleted_files, name: 'file'}
|
620
701
|
when :plugins
|
621
|
-
return {:data
|
622
|
-
when :list
|
623
|
-
return {:data => @config_presets.keys, :type => :value_list, :name => 'name'}
|
624
|
-
when :overview
|
625
|
-
return {:type=>:object_list,:data=>self.class.flatten_all_config(@config_presets)}
|
702
|
+
return {type: :object_list, data: @plugins.keys.map { |i| { 'plugin' => i.to_s, 'path' => @plugins[i][:source] } } , fields: ['plugin','path']}
|
626
703
|
when :wizard
|
704
|
+
# interactive mode
|
627
705
|
self.options.ask_missing_mandatory=true
|
628
706
|
# register url option
|
629
707
|
BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
|
708
|
+
# get from option, or ask
|
630
709
|
instance_url=self.options.get_option(:url,:mandatory)
|
631
|
-
|
710
|
+
# allow user to tell the preset name
|
711
|
+
preset_name=self.options.get_option(:id,:optional)
|
712
|
+
appli=identify_plugin_for_url(instance_url)
|
713
|
+
plugin_name="<replace per app>"
|
714
|
+
test_args="<replace per app>"
|
632
715
|
case appli[:product]
|
633
716
|
when :aoc
|
634
717
|
self.format.display_status('Detected: Aspera on Cloud'.bold)
|
718
|
+
plugin_name=AOC_COMMAND_CURRENT
|
635
719
|
organization,instance_domain=AoC.parse_url(instance_url)
|
636
|
-
|
637
|
-
|
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}")
|
638
723
|
# init defaults if necessary
|
639
|
-
@config_presets[CONF_PRESET_DEFAULT]||=
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
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)
|
644
730
|
# lets see if path to priv key is provided
|
645
731
|
private_key_path=self.options.get_option(:pkeypath,:optional)
|
646
732
|
# give a chance to provide
|
@@ -650,23 +736,23 @@ module Aspera
|
|
650
736
|
end
|
651
737
|
# else generate path
|
652
738
|
if private_key_path.empty?
|
653
|
-
private_key_path=File.join(@main_folder,
|
739
|
+
private_key_path=File.join(@main_folder,DEFAULT_PRIV_KEY_FILENAME)
|
654
740
|
end
|
655
741
|
if File.exist?(private_key_path)
|
656
742
|
self.format.display_status('Using existing key:')
|
657
743
|
else
|
658
|
-
self.format.display_status(
|
659
|
-
|
744
|
+
self.format.display_status("Generating #{DEFAULT_PRIVKEY_LENGTH} bit RSA key...")
|
745
|
+
generate_rsa_private_key(private_key_path,DEFAULT_PRIVKEY_LENGTH)
|
660
746
|
self.format.display_status('Created:')
|
661
747
|
end
|
662
|
-
self.format.display_status(
|
748
|
+
self.format.display_status(private_key_path)
|
663
749
|
pub_key_pem=OpenSSL::PKey::RSA.new(File.read(private_key_path)).public_key.to_s
|
664
750
|
# declare command line options for AoC
|
665
751
|
require 'aspera/cli/plugins/aoc'
|
666
752
|
# make username mandatory for jwt, this triggers interactive input
|
667
753
|
self.options.get_option(:username,:mandatory)
|
668
754
|
# instanciate AoC plugin, so that command line options are known
|
669
|
-
files_plugin=self.class.
|
755
|
+
files_plugin=self.class.plugin_class(plugin_name).new(@agents.merge({skip_basic_auth_options: true, private_key_path: private_key_path}))
|
670
756
|
aoc_api=files_plugin.get_api
|
671
757
|
auto_set_pub_key=false
|
672
758
|
auto_set_jwt=false
|
@@ -709,7 +795,7 @@ module Aspera
|
|
709
795
|
end
|
710
796
|
myself=aoc_api.read('self')[:data]
|
711
797
|
if auto_set_pub_key
|
712
|
-
raise CliError,'
|
798
|
+
raise CliError,'Public key is already set in profile (use --override=yes)' unless myself['public_key'].empty? or option_override
|
713
799
|
self.format.display_status('Updating profile with new key')
|
714
800
|
aoc_api.update("users/#{myself['id']}",{'public_key'=>pub_key_pem})
|
715
801
|
end
|
@@ -717,8 +803,8 @@ module Aspera
|
|
717
803
|
self.format.display_status('Enabling JWT for client')
|
718
804
|
aoc_api.update("clients/#{self.options.get_option(:client_id)}",{'jwt_grant_enabled'=>true,'explicit_authorization_required'=>false})
|
719
805
|
end
|
720
|
-
self.format.display_status("
|
721
|
-
@config_presets[
|
806
|
+
self.format.display_status("Creating new config preset: #{preset_name}")
|
807
|
+
@config_presets[preset_name]={
|
722
808
|
:url.to_s =>self.options.get_option(:url),
|
723
809
|
:username.to_s =>myself['email'],
|
724
810
|
:auth.to_s =>:jwt.to_s,
|
@@ -727,23 +813,28 @@ module Aspera
|
|
727
813
|
# set only if non nil
|
728
814
|
[:client_id,:client_secret].each do |s|
|
729
815
|
o=self.options.get_option(s)
|
730
|
-
@config_presets[s.to_s] = o unless o.nil?
|
816
|
+
@config_presets[preset_name][s.to_s] = o unless o.nil?
|
731
817
|
end
|
732
|
-
|
733
|
-
@config_presets[CONF_PRESET_DEFAULT][AOC_COMMAND_CURRENT]=aspera_preset_name
|
734
|
-
self.format.display_status('saving config file')
|
735
|
-
save_presets_to_config_file
|
736
|
-
return Main.result_status("Done.\nYou can test with:\n#{@tool_name} #{AOC_COMMAND_CURRENT} user info show")
|
818
|
+
test_args="#{plugin_name} user info show"
|
737
819
|
else
|
738
820
|
raise CliBadArgument,"Supports only: aoc. Detected: #{appli}"
|
821
|
+
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
|
825
|
+
else
|
826
|
+
test_args="-P#{preset_name} #{test_args}"
|
739
827
|
end
|
828
|
+
self.format.display_status('Saving config file.')
|
829
|
+
save_presets_to_config_file
|
830
|
+
return Main.result_status("Done.\nYou can test with:\n#{@tool_name} #{test_args}")
|
740
831
|
when :export_to_cli
|
741
832
|
self.format.display_status('Exporting: Aspera on Cloud')
|
742
833
|
require 'aspera/cli/plugins/aoc'
|
743
834
|
# need url / username
|
744
835
|
add_plugin_default_preset(AOC_COMMAND_V3.to_sym)
|
745
836
|
# instanciate AoC plugin
|
746
|
-
files_plugin=self.class.
|
837
|
+
files_plugin=self.class.plugin_class(AOC_COMMAND_CURRENT).new(@agents) # TODO: is this line needed ?
|
747
838
|
url=self.options.get_option(:url,:mandatory)
|
748
839
|
cli_conf_file=Fasp::Installation.instance.cli_conf_file
|
749
840
|
data=JSON.parse(File.read(cli_conf_file))
|
@@ -775,7 +866,7 @@ module Aspera
|
|
775
866
|
when :detect
|
776
867
|
# need url / username
|
777
868
|
BasicAuthPlugin.new(@agents)
|
778
|
-
return Main.result_status("Found: #{
|
869
|
+
return Main.result_status("Found: #{identify_plugin_for_url(self.options.get_option(:url,:mandatory))}")
|
779
870
|
when :coffee
|
780
871
|
OpenApplication.instance.uri('https://enjoyjava.com/wp-content/uploads/2018/01/How-to-make-strong-coffee.jpg')
|
781
872
|
return Main.result_nothing
|
@@ -788,21 +879,16 @@ module Aspera
|
|
788
879
|
when :file
|
789
880
|
return Main.result_status(@option_config_file)
|
790
881
|
when :email_test
|
791
|
-
|
792
|
-
send_email({
|
793
|
-
to: dest_email,
|
794
|
-
subject: 'Amelia email test',
|
795
|
-
body: 'It worked !',
|
796
|
-
})
|
882
|
+
send_email_template({},EMAIL_TEST_TEMPLATE)
|
797
883
|
return Main.result_nothing
|
798
884
|
when :smtp_settings
|
799
|
-
return {:
|
885
|
+
return {type: :single_object, data: email_settings}
|
800
886
|
when :proxy_check
|
801
887
|
pac_url=self.options.get_option(:fpac,:mandatory)
|
802
888
|
server_url=self.options.get_next_argument('server url')
|
803
889
|
return Main.result_status(Aspera::ProxyAutoConfig.new(UriReader.read(pac_url)).get_proxy(server_url))
|
804
890
|
when :check_update
|
805
|
-
return {:
|
891
|
+
return {type: :single_object, data: check_gem_version}
|
806
892
|
when :initdemo
|
807
893
|
if @config_presets.has_key?(DEMO_SERVER_PRESET)
|
808
894
|
Log.log.warn("Demo server preset already present: #{DEMO_SERVER_PRESET}")
|
@@ -811,22 +897,63 @@ module Aspera
|
|
811
897
|
@config_presets[DEMO_SERVER_PRESET]={'url'=>'ssh://'+DEMO+'.asperasoft.com:33001','username'=>AOC_COMMAND_V2,'ssAP'.downcase.reverse+'drow'.reverse=>DEMO+AOC_COMMAND_V2}
|
812
898
|
end
|
813
899
|
@config_presets[CONF_PRESET_DEFAULT]||={}
|
814
|
-
if @config_presets[CONF_PRESET_DEFAULT].has_key?(
|
815
|
-
Log.log.warn("
|
816
|
-
Log.log.warn("
|
900
|
+
if @config_presets[CONF_PRESET_DEFAULT].has_key?(SERVER_COMMAND)
|
901
|
+
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 DEMO_SERVER_PRESET.eql?(@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND])
|
817
903
|
else
|
818
|
-
@config_presets[CONF_PRESET_DEFAULT][
|
819
|
-
Log.log.info("
|
904
|
+
@config_presets[CONF_PRESET_DEFAULT][SERVER_COMMAND]=DEMO_SERVER_PRESET
|
905
|
+
Log.log.info("Setting server default preset to : #{DEMO_SERVER_PRESET}")
|
820
906
|
end
|
821
907
|
save_presets_to_config_file
|
822
908
|
return Main.result_status("Done")
|
823
|
-
|
909
|
+
when :vault
|
910
|
+
command=self.options.get_next_command([:init,:list,:get,:set,:delete])
|
911
|
+
case command
|
912
|
+
when :init
|
913
|
+
type=self.options.get_option(:value,:optional)
|
914
|
+
case type
|
915
|
+
when 'config',NilClass
|
916
|
+
raise "default secrets already exists" if @config_presets.has_key?(CONF_PRESET_SECRETS)
|
917
|
+
@config_presets[CONF_PRESET_SECRETS]={}
|
918
|
+
set_global_default(:secrets,"@preset:#{CONF_PRESET_SECRETS}")
|
919
|
+
else raise "no such vault type"
|
920
|
+
end
|
921
|
+
return Main.result_status("Done")
|
922
|
+
when :list
|
923
|
+
return {type: :object_list, data: vault.list}
|
924
|
+
when :set
|
925
|
+
# register url option
|
926
|
+
BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
|
927
|
+
username=self.options.get_option(:username,:mandatory)
|
928
|
+
url=self.options.get_option(:url,:mandatory)
|
929
|
+
description=self.options.get_option(:value,:optional)
|
930
|
+
secret=self.options.get_next_argument('secret')
|
931
|
+
vault.set(username: username, url: url, description: description, secret: secret)
|
932
|
+
save_presets_to_config_file if vault.is_a?(Keychain::EncryptedHash)
|
933
|
+
return Main.result_status("Done")
|
934
|
+
when :get
|
935
|
+
# register url option
|
936
|
+
BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
|
937
|
+
username=self.options.get_option(:username,:mandatory)
|
938
|
+
url=self.options.get_option(:url,:optional)
|
939
|
+
result=vault.get(username: username, url: url)
|
940
|
+
return {type: :single_object, data: result}
|
941
|
+
when :delete
|
942
|
+
# register url option
|
943
|
+
BasicAuthPlugin.new(@agents.merge(skip_option_header: true))
|
944
|
+
username=self.options.get_option(:username,:mandatory)
|
945
|
+
url=self.options.get_option(:url,:optional)
|
946
|
+
result=vault.delete(username: username, url: url)
|
947
|
+
return Main.result_status("Done")
|
948
|
+
end
|
949
|
+
else raise 'INTERNAL ERROR: wrong case'
|
824
950
|
end
|
825
951
|
end
|
826
952
|
|
953
|
+
# @return email server setting with defaults if not defined
|
827
954
|
def email_settings
|
828
955
|
smtp=self.options.get_option(:smtp,:mandatory)
|
829
|
-
# change string keys into
|
956
|
+
# change string keys into symbol keys
|
830
957
|
smtp=smtp.keys.inject({}){|m,v|m[v.to_sym]=smtp[v];m}
|
831
958
|
# defaults
|
832
959
|
smtp[:tls]||=true
|
@@ -836,41 +963,49 @@ module Aspera
|
|
836
963
|
smtp[:domain]||=smtp[:from_email].gsub(/^.*@/,'') if smtp.has_key?(:from_email)
|
837
964
|
# check minimum required
|
838
965
|
[:server,:port,:domain].each do |n|
|
839
|
-
raise "
|
966
|
+
raise "Missing smtp parameter: #{n}" unless smtp.has_key?(n)
|
840
967
|
end
|
841
968
|
Log.log.debug("smtp=#{smtp}")
|
842
969
|
return smtp
|
843
970
|
end
|
844
971
|
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
972
|
+
# create a clean binding (ruby variable environment)
|
973
|
+
def empty_binding
|
974
|
+
Kernel.binding
|
975
|
+
end
|
976
|
+
|
977
|
+
def send_email_template(vars,email_template_default=nil)
|
978
|
+
vars[:to]||=options.get_option(:notif_to,:mandatory)
|
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
|
+
[:from_name,:from_email].each do |n|
|
984
|
+
raise "Missing email parameter: #{n}" unless vars.has_key?(n)
|
985
|
+
end
|
986
|
+
start_options=[mail_conf[:domain]]
|
987
|
+
start_options.push(mail_conf[:username],mail_conf[:password],:login) if mail_conf.has_key?(:username) and mail_conf.has_key?(:password)
|
988
|
+
# create a binding with only variables defined in vars
|
989
|
+
template_binding=empty_binding
|
990
|
+
# add variables to binding
|
991
|
+
vars.each do |k,v|
|
992
|
+
raise "key (#{k.class}) must be Symbol" unless k.is_a?(Symbol)
|
993
|
+
template_binding.local_variable_set(k,v)
|
852
994
|
end
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
#{email[:body]}
|
859
|
-
END_OF_MESSAGE
|
860
|
-
start_options=[opts[:domain]]
|
861
|
-
start_options.push(opts[:username],opts[:password],:login) if opts.has_key?(:username) and opts.has_key?(:password)
|
862
|
-
|
863
|
-
smtp = Net::SMTP.new(opts[:server], opts[:port])
|
864
|
-
smtp.enable_starttls if opts[:tls]
|
995
|
+
# execute template
|
996
|
+
msg_with_headers=ERB.new(notif_template).result(template_binding)
|
997
|
+
Log.dump(:msg_with_headers,msg_with_headers)
|
998
|
+
smtp = Net::SMTP.new(mail_conf[:server], mail_conf[:port])
|
999
|
+
smtp.enable_starttls if mail_conf[:tls]
|
865
1000
|
smtp.start(*start_options) do |smtp|
|
866
|
-
smtp.send_message(
|
1001
|
+
smtp.send_message(msg_with_headers, vars[:from_email], vars[:to])
|
867
1002
|
end
|
868
1003
|
end
|
869
1004
|
|
870
1005
|
def save_presets_to_config_file
|
871
1006
|
raise 'no configuration loaded' if @config_presets.nil?
|
872
1007
|
FileUtils.mkdir_p(@main_folder) unless Dir.exist?(@main_folder)
|
873
|
-
Log.log.debug
|
1008
|
+
Log.log.debug("Writing #{@option_config_file}")
|
874
1009
|
File.write(@option_config_file,@config_presets.to_yaml)
|
875
1010
|
end
|
876
1011
|
|
@@ -894,6 +1029,42 @@ END_OF_MESSAGE
|
|
894
1029
|
return nil
|
895
1030
|
end # get_plugin_default_config_name
|
896
1031
|
|
1032
|
+
def vault
|
1033
|
+
if @vault.nil?
|
1034
|
+
vault_info=self.options.get_option(:secrets,:optional)
|
1035
|
+
case vault_info
|
1036
|
+
when Hash
|
1037
|
+
@vault=Keychain::EncryptedHash.new(vault_info)
|
1038
|
+
when /^system/
|
1039
|
+
name=vault_info.start_with?('system:') ? vault_info[7..-1] : nil
|
1040
|
+
case Environment.os
|
1041
|
+
when Environment::OS_X
|
1042
|
+
@vault=Keychain::MacosSecurity.new(name)
|
1043
|
+
when Environment::OS_WINDOWS,Environment::OS_LINUX,Environment::OS_AIX
|
1044
|
+
raise "not implemented"
|
1045
|
+
else raise "Error"
|
1046
|
+
end
|
1047
|
+
when NilClass
|
1048
|
+
# keep nil
|
1049
|
+
else
|
1050
|
+
raise CliBadArgument,'secrets shall be Hash'
|
1051
|
+
end
|
1052
|
+
end
|
1053
|
+
raise "No vault defined" if @vault.nil?
|
1054
|
+
@vault
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def get_secret(options)
|
1058
|
+
raise "options shall be Hash" unless options.is_a?(Hash)
|
1059
|
+
raise "options shall have username" unless options.has_key?(:username)
|
1060
|
+
secret=self.options.get_option(:secret,:optional)
|
1061
|
+
if secret.nil?
|
1062
|
+
secret=vault.get(options) rescue nil
|
1063
|
+
# mandatory by default
|
1064
|
+
raise "please provide secret for #{options[:username]}" if secret.nil? and ( options[:mandatory].nil? or options[:mandatory] )
|
1065
|
+
end
|
1066
|
+
return secret
|
1067
|
+
end
|
897
1068
|
end
|
898
1069
|
end
|
899
1070
|
end
|