aspera-cli 4.0.0.pre3 → 4.2.1
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 +695 -205
- data/bin/dascli +13 -0
- data/docs/README.erb.md +615 -157
- data/docs/test_env.conf +23 -5
- data/docs/transfer_spec.html +1 -1
- data/examples/aoc.rb +14 -3
- data/examples/faspex4.rb +78 -0
- data/lib/aspera/aoc.rb +87 -108
- data/lib/aspera/cli/formater.rb +2 -0
- data/lib/aspera/cli/main.rb +46 -34
- data/lib/aspera/cli/plugin.rb +9 -4
- data/lib/aspera/cli/plugins/alee.rb +1 -1
- data/lib/aspera/cli/plugins/aoc.rb +207 -182
- data/lib/aspera/cli/plugins/ats.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +173 -117
- data/lib/aspera/cli/plugins/console.rb +2 -2
- data/lib/aspera/cli/plugins/faspex.rb +51 -36
- data/lib/aspera/cli/plugins/faspex5.rb +82 -41
- data/lib/aspera/cli/plugins/node.rb +3 -3
- data/lib/aspera/cli/plugins/preview.rb +35 -25
- data/lib/aspera/cli/plugins/server.rb +23 -8
- data/lib/aspera/cli/transfer_agent.rb +7 -6
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cos_node.rb +33 -28
- data/lib/aspera/environment.rb +2 -2
- data/lib/aspera/fasp/connect.rb +28 -21
- data/lib/aspera/fasp/http_gw.rb +140 -28
- data/lib/aspera/fasp/installation.rb +101 -53
- data/lib/aspera/fasp/local.rb +88 -45
- data/lib/aspera/fasp/manager.rb +15 -0
- data/lib/aspera/fasp/node.rb +4 -4
- data/lib/aspera/fasp/parameters.rb +6 -18
- data/lib/aspera/fasp/resume_policy.rb +13 -12
- data/lib/aspera/log.rb +1 -1
- data/lib/aspera/node.rb +61 -1
- data/lib/aspera/oauth.rb +49 -46
- data/lib/aspera/persistency_folder.rb +9 -4
- data/lib/aspera/preview/file_types.rb +53 -21
- data/lib/aspera/preview/generator.rb +3 -3
- data/lib/aspera/rest.rb +29 -18
- data/lib/aspera/secrets.rb +20 -0
- data/lib/aspera/temp_file_manager.rb +19 -0
- data/lib/aspera/web_auth.rb +105 -0
- metadata +42 -22
data/lib/aspera/fasp/manager.rb
CHANGED
@@ -45,6 +45,18 @@ module Aspera
|
|
45
45
|
end
|
46
46
|
end # notify_listeners
|
47
47
|
|
48
|
+
def notify_begin(id,size)
|
49
|
+
notify_listeners('emulated',{LISTENER_SESSION_ID_B=>id,'Type'=>'NOTIFICATION','PreTransferBytes'=>size})
|
50
|
+
end
|
51
|
+
|
52
|
+
def notify_progress(id,size)
|
53
|
+
notify_listeners('emulated',{LISTENER_SESSION_ID_B=>id,'Type'=>'STATS','Bytescont'=>size})
|
54
|
+
end
|
55
|
+
|
56
|
+
def notify_end(id)
|
57
|
+
notify_listeners('emulated',{LISTENER_SESSION_ID_B=>id,'Type'=>'DONE'})
|
58
|
+
end
|
59
|
+
|
48
60
|
public
|
49
61
|
LISTENER_SESSION_ID_B='ListenerSessionId'
|
50
62
|
LISTENER_SESSION_ID_S='listener_session_id'
|
@@ -60,6 +72,9 @@ module Aspera
|
|
60
72
|
# start_transfer(transfer_spec,options) : start and wait for completion
|
61
73
|
# wait_for_transfers_completion : wait for termination of all transfers, @return list of : :success or error message
|
62
74
|
# optional: shutdown
|
75
|
+
|
76
|
+
# This checks the validity of the value returned by wait_for_transfers_completion
|
77
|
+
# it must be a list of :success or exception
|
63
78
|
def self.validate_status_list(statuses)
|
64
79
|
raise "internal error: bad statuses type: #{statuses.class}" unless statuses.is_a?(Array)
|
65
80
|
raise "internal error: bad statuses content: #{statuses}" unless statuses.select{|i|!i.eql?(:success) and !i.is_a?(StandardError)}.empty?
|
data/lib/aspera/fasp/node.rb
CHANGED
@@ -55,7 +55,7 @@ module Aspera
|
|
55
55
|
trdata=node_api_.read("ops/transfers/#{@transfer_id}")[:data] || {"status"=>"unknown"} rescue {"status"=>"waiting(read error)"}
|
56
56
|
case trdata['status']
|
57
57
|
when 'completed'
|
58
|
-
|
58
|
+
notify_end(@transfer_id)
|
59
59
|
break
|
60
60
|
when 'waiting','partially_completed','unknown','waiting(read error)'
|
61
61
|
if spinner.nil?
|
@@ -69,10 +69,10 @@ module Aspera
|
|
69
69
|
#puts "running: sessions:#{trdata["sessions"].length}, #{trdata["sessions"].map{|i| i['bytes_transferred']}.join(',')}"
|
70
70
|
if !started and trdata['precalc'].is_a?(Hash) and
|
71
71
|
trdata['precalc']['status'].eql?('ready')
|
72
|
-
|
72
|
+
notify_begin(@transfer_id,trdata['precalc']['bytes_expected'])
|
73
73
|
started=true
|
74
74
|
else
|
75
|
-
|
75
|
+
notify_progress(@transfer_id,trdata['bytes_transferred'])
|
76
76
|
end
|
77
77
|
else
|
78
78
|
Log.log.warn("trdata -> #{trdata}")
|
@@ -81,7 +81,7 @@ module Aspera
|
|
81
81
|
sleep 1
|
82
82
|
end
|
83
83
|
#TODO get status of sessions
|
84
|
-
return []
|
84
|
+
return []
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
@@ -16,10 +16,6 @@ module Aspera
|
|
16
16
|
# because of garbage collection takes any file there
|
17
17
|
# this could be refined, as , for instance, on macos, temp folder is already user specific
|
18
18
|
@@file_list_folder=TempFileManager.instance.new_file_path_global('asession_filelists')
|
19
|
-
SEC_IN_DAY=86400
|
20
|
-
# assume no transfer last longer than this
|
21
|
-
# (garbage collect file list which were not deleted after transfer)
|
22
|
-
FILE_LIST_AGE_MAX_SEC=5*SEC_IN_DAY
|
23
19
|
PARAM_DEFINITION={
|
24
20
|
# parameters with env vars
|
25
21
|
'remote_password' => { :type => :envvar, :variable=>'ASPERA_SCP_PASS'},
|
@@ -63,7 +59,7 @@ module Aspera
|
|
63
59
|
'exclude_older_than' => { :type => :opt_with_arg, :accepted_types=>Integer},
|
64
60
|
'preserve_acls' => { :type => :opt_with_arg, :accepted_types=>String},
|
65
61
|
'move_after_transfer' => { :type => :opt_with_arg, :accepted_types=>String},
|
66
|
-
'multi_session_threshold' => { :type => :opt_with_arg, :accepted_types=>
|
62
|
+
'multi_session_threshold' => { :type => :opt_with_arg, :accepted_types=>Integer},
|
67
63
|
# non standard parameters
|
68
64
|
'EX_fasp_proxy_url' => { :type => :opt_with_arg, :option_switch=>'--proxy',:accepted_types=>String},
|
69
65
|
'EX_http_proxy_url' => { :type => :opt_with_arg, :option_switch=>'-x',:accepted_types=>String},
|
@@ -82,11 +78,12 @@ module Aspera
|
|
82
78
|
'lock_rate_policy' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
|
83
79
|
'lock_min_rate' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
|
84
80
|
'lock_target_rate' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
|
85
|
-
|
81
|
+
'authentication' => { :type => :ignore, :accepted_types=>String}, # value = token
|
86
82
|
'https_fallback_port' => { :type => :ignore, :accepted_types=>Integer}, # same as http fallback, option -t ?
|
87
83
|
'content_protection' => { :type => :ignore, :accepted_types=>String},
|
88
84
|
'cipher_allowed' => { :type => :ignore, :accepted_types=>String},
|
89
85
|
'multi_session' => { :type => :ignore, :accepted_types=>Integer}, # managed
|
86
|
+
'obfuscate_file_names' => { :type => :ignore, :accepted_types=>Aspera::CommandLineBuilder::BOOLEAN_CLASSES},
|
90
87
|
# optional tags ( additional option to generate: {:space=>' ',:object_nl=>' ',:space_before=>'+',:array_nl=>'1'} )
|
91
88
|
'tags' => { :type => :opt_with_arg, :option_switch=>'--tags64',:accepted_types=>Hash,:encode=>lambda{|tags|Base64.strict_encode64(JSON.generate(tags))}},
|
92
89
|
# special processing @builder.process_param( called individually
|
@@ -100,7 +97,7 @@ module Aspera
|
|
100
97
|
'wss_port' => { :type => :defer, :accepted_types=>Integer},
|
101
98
|
}
|
102
99
|
|
103
|
-
private_constant :
|
100
|
+
private_constant :PARAM_DEFINITION
|
104
101
|
|
105
102
|
def initialize(job_spec,options)
|
106
103
|
@job_spec=job_spec
|
@@ -207,18 +204,9 @@ module Aspera
|
|
207
204
|
# temp file list files are created here
|
208
205
|
def self.file_list_folder=(v)
|
209
206
|
@@file_list_folder=v
|
210
|
-
|
207
|
+
if !@@file_list_folder.nil?
|
211
208
|
FileUtils.mkdir_p(@@file_list_folder)
|
212
|
-
|
213
|
-
Dir.entries(@@file_list_folder).each do |name|
|
214
|
-
file_path=File.join(@@file_list_folder,name)
|
215
|
-
age_sec=(Time.now - File.stat(file_path).mtime).to_i
|
216
|
-
# check age of file, delete too old
|
217
|
-
if File.file?(file_path) and age_sec > FILE_LIST_AGE_MAX_SEC
|
218
|
-
Log.log.debug("garbage collecting #{name}")
|
219
|
-
File.delete(file_path)
|
220
|
-
end
|
221
|
-
end
|
209
|
+
TempFileManager.instance.cleanup_expired(@@file_list_folder)
|
222
210
|
end
|
223
211
|
end
|
224
212
|
|
@@ -14,17 +14,21 @@ module Aspera
|
|
14
14
|
:sleep_max => 60
|
15
15
|
}
|
16
16
|
|
17
|
-
|
17
|
+
# @param params see DEFAULTS
|
18
|
+
def initialize(params=nil)
|
18
19
|
@parameters=DEFAULTS.clone
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
if !params.nil?
|
21
|
+
raise "expecting Hash (or nil), but have #{params.class}" unless params.is_a?(Hash)
|
22
|
+
params.each do |k,v|
|
23
|
+
if DEFAULTS.has_key?(k)
|
24
|
+
raise "#{k} must be Integer" unless v.is_a?(Integer)
|
25
|
+
@parameters[k]=v
|
26
|
+
else
|
27
|
+
raise "unknown resume parameter: #{k}, expect one of #{DEFAULTS.keys.map{|i|i.to_s}.join(",")}"
|
28
|
+
end
|
26
29
|
end
|
27
30
|
end
|
31
|
+
Log.log.debug("resume params=#{@parameters}")
|
28
32
|
end
|
29
33
|
|
30
34
|
# calls block a number of times (resumes) until success or limit reached
|
@@ -45,10 +49,7 @@ module Aspera
|
|
45
49
|
# failure in ascp
|
46
50
|
if e.retryable? then
|
47
51
|
# exit if we exceed the max number of retry
|
48
|
-
|
49
|
-
Log.log.error "Maximum number of retry reached"
|
50
|
-
raise Fasp::Error,"max retry after: [#{status[:message]}]"
|
51
|
-
end
|
52
|
+
raise Fasp::Error,'Maximum number of retry reached' if remaining_resumes <= 0
|
52
53
|
else
|
53
54
|
# give one chance only to non retryable errors
|
54
55
|
unless remaining_resumes.eql?(@parameters[:iter_max])
|
data/lib/aspera/log.rb
CHANGED
@@ -14,7 +14,7 @@ module Aspera
|
|
14
14
|
attr_reader :logger
|
15
15
|
attr_reader :logger_type
|
16
16
|
# levels are :debug,:info,:warn,:error,fatal,:unknown
|
17
|
-
def self.levels; Logger::Severity.constants.map{|c|
|
17
|
+
def self.levels; Logger::Severity.constants.sort{|a,b|Logger::Severity.const_get(a)<=>Logger::Severity.const_get(b)}.map{|c|c.downcase.to_sym};end
|
18
18
|
|
19
19
|
# where logs are sent to
|
20
20
|
def self.logtypes; [:stderr,:stdout,:syslog];end
|
data/lib/aspera/node.rb
CHANGED
@@ -1,14 +1,74 @@
|
|
1
|
+
require 'aspera/rest'
|
2
|
+
require 'aspera/log'
|
1
3
|
require 'zlib'
|
2
4
|
require 'base64'
|
5
|
+
|
3
6
|
module Aspera
|
4
7
|
# Provides additional functions using node API.
|
5
8
|
class Node < Rest
|
9
|
+
# permissions
|
10
|
+
ACCESS_LEVELS=['delete','list','mkdir','preview','read','rename','write']
|
11
|
+
MATCH_EXEC_PREFIX='exec:'
|
12
|
+
|
13
|
+
# for information only
|
6
14
|
def self.decode_bearer_token(token)
|
7
15
|
return JSON.parse(Zlib::Inflate.inflate(Base64.decode64(token)).partition('==SIGNATURE==').first)
|
8
16
|
end
|
17
|
+
|
18
|
+
# for access keys: provide expression to match entry in folder
|
19
|
+
# if no prefix: regex
|
20
|
+
# if prefix: ruby code
|
21
|
+
# if filder is nil, then always match
|
22
|
+
def self.file_matcher(match_expression)
|
23
|
+
match_expression||="#{MATCH_EXEC_PREFIX}true"
|
24
|
+
if match_expression.start_with?(MATCH_EXEC_PREFIX)
|
25
|
+
return eval "lambda{|f|#{match_expression[MATCH_EXEC_PREFIX.length..-1]}}"
|
26
|
+
end
|
27
|
+
return lambda{|f|f['name'].match(/#{match_expression}/)}
|
28
|
+
end
|
29
|
+
|
9
30
|
def initialize(rest_params)
|
10
31
|
super(rest_params)
|
11
|
-
|
32
|
+
end
|
33
|
+
|
34
|
+
# recursively crawl in a folder.
|
35
|
+
# subfolders a processed if the processing method returns true
|
36
|
+
# @param processor must provide a method to process each entry
|
37
|
+
# @param opt options
|
38
|
+
# - top_file_id file id to start at (default = access key root file id)
|
39
|
+
# - top_file_path path of top folder (default = /)
|
40
|
+
# - method processing method (default= process_entry)
|
41
|
+
def crawl(processor,opt={})
|
42
|
+
Log.log.debug("crawl1 #{opt}")
|
43
|
+
# not possible with bearer token
|
44
|
+
opt[:top_file_id] ||= read('access_keys/self')[:data]['root_file_id']
|
45
|
+
opt[:top_file_path] ||= '/'
|
46
|
+
opt[:method] ||= :process_entry
|
47
|
+
raise "processor must have #{opt[:method]}" unless processor.respond_to?(opt[:method])
|
48
|
+
Log.log.debug("crawl #{opt}")
|
49
|
+
#top_info=read("files/#{opt[:top_file_id]}")[:data]
|
50
|
+
folders_to_explore=[{id: opt[:top_file_id], relpath: opt[:top_file_path]}]
|
51
|
+
Log.dump(:folders_to_explore,folders_to_explore)
|
52
|
+
while !folders_to_explore.empty? do
|
53
|
+
current_item = folders_to_explore.shift
|
54
|
+
Log.log.debug("searching #{current_item[:relpath]}".bg_green)
|
55
|
+
# get folder content
|
56
|
+
folder_contents = begin
|
57
|
+
read("files/#{current_item[:id]}/files")[:data]
|
58
|
+
rescue => e
|
59
|
+
Log.log.warn("#{current_item[:relpath]}: #{e.class} #{e.message}")
|
60
|
+
[]
|
61
|
+
end
|
62
|
+
Log.dump(:folder_contents,folder_contents)
|
63
|
+
folder_contents.each do |entry|
|
64
|
+
relative_path=File.join(current_item[:relpath],entry['name'])
|
65
|
+
Log.log.debug("looking #{relative_path}".bg_green)
|
66
|
+
# entry type is file, folder or link
|
67
|
+
if processor.send(opt[:method],entry,relative_path) and entry['type'].eql?('folder')
|
68
|
+
folders_to_explore.push({:id=>entry['id'],:relpath=>relative_path})
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
12
72
|
end
|
13
73
|
end
|
14
74
|
end
|
data/lib/aspera/oauth.rb
CHANGED
@@ -1,22 +1,26 @@
|
|
1
1
|
require 'aspera/open_application'
|
2
|
+
require 'aspera/web_auth'
|
2
3
|
require 'base64'
|
3
4
|
require 'date'
|
4
5
|
require 'socket'
|
5
6
|
require 'securerandom'
|
6
7
|
|
7
8
|
module Aspera
|
8
|
-
#
|
9
|
+
# Implement OAuth 2 for the REST client and generate a bearer token
|
9
10
|
# call get_authorization() to get a token.
|
10
11
|
# bearer tokens are kept in memory and also in a file cache for later re-use
|
11
12
|
# if a token is expired (api returns 4xx), call again get_authorization({:refresh=>true})
|
12
13
|
class Oauth
|
13
14
|
private
|
14
15
|
# remove 5 minutes to account for time offset (TODO: configurable?)
|
15
|
-
|
16
|
+
JWT_NOTBEFORE_OFFSET_SEC=300
|
16
17
|
# one hour validity (TODO: configurable?)
|
17
|
-
|
18
|
+
JWT_EXPIRY_OFFSET_SEC=3600
|
19
|
+
# tokens older than 30 minutes will be discarded from cache
|
20
|
+
TOKEN_CACHE_EXPIRY_SEC=1800
|
21
|
+
# a prefix for persistency of tokens (garbage collect)
|
18
22
|
PERSIST_CATEGORY_TOKEN='token'
|
19
|
-
private_constant :
|
23
|
+
private_constant :JWT_NOTBEFORE_OFFSET_SEC,:JWT_EXPIRY_OFFSET_SEC,:PERSIST_CATEGORY_TOKEN,:TOKEN_CACHE_EXPIRY_SEC
|
20
24
|
class << self
|
21
25
|
# OAuth methods supported
|
22
26
|
def auth_types
|
@@ -28,12 +32,18 @@ module Aspera
|
|
28
32
|
end
|
29
33
|
|
30
34
|
def persist_mgr
|
31
|
-
|
35
|
+
if @persist.nil?
|
36
|
+
Log.log.warn('Not using persistency (use Aspera::Oauth.persist_mgr=Aspera::PersistencyFolder.new)')
|
37
|
+
# create NULL persistency class
|
38
|
+
@persist=Class.new do
|
39
|
+
def get(x);nil;end;def delete(x);nil;end;def put(x,y);nil;end;def garbage_collect(x,y);nil;end
|
40
|
+
end.new
|
41
|
+
end
|
32
42
|
return @persist
|
33
43
|
end
|
34
44
|
|
35
45
|
def flush_tokens
|
36
|
-
persist_mgr.
|
46
|
+
persist_mgr.garbage_collect(PERSIST_CATEGORY_TOKEN,nil)
|
37
47
|
end
|
38
48
|
end
|
39
49
|
|
@@ -79,13 +89,19 @@ module Aspera
|
|
79
89
|
raise "redirect_uri must have a port" if uri.port.nil?
|
80
90
|
# we could check that host is localhost or local address
|
81
91
|
end
|
92
|
+
# cleanup expired tokens
|
93
|
+
self.class.persist_mgr.garbage_collect(PERSIST_CATEGORY_TOKEN,TOKEN_CACHE_EXPIRY_SEC)
|
82
94
|
end
|
83
95
|
|
84
|
-
THANK_YOU_HTML = "<html><head><title>Ok</title></head><body><h1>Thank you !</h1><p>You can close this window.</p></body></html>"
|
85
|
-
|
86
96
|
# open the login page, wait for code and check_code, then return code
|
87
97
|
def goto_page_and_get_code(login_page_url,check_code)
|
88
|
-
|
98
|
+
Log.log.info("login_page_url=#{login_page_url}".bg_red.gray)
|
99
|
+
# start a web server to receive request code
|
100
|
+
webserver=WebAuth.new(@params[:redirect_uri])
|
101
|
+
# start browser on login page
|
102
|
+
OpenApplication.instance.uri(login_page_url)
|
103
|
+
# wait for code in request
|
104
|
+
request_params=webserver.get_request
|
89
105
|
Log.log.error("state does not match") if !check_code.eql?(request_params['state'])
|
90
106
|
code=request_params['code']
|
91
107
|
return code
|
@@ -117,6 +133,9 @@ module Aspera
|
|
117
133
|
|
118
134
|
public
|
119
135
|
|
136
|
+
# used to change parameter, such as scope
|
137
|
+
attr_reader :params
|
138
|
+
|
120
139
|
# @param options : :scope and :refresh
|
121
140
|
def get_authorization(options={})
|
122
141
|
# api scope can be overriden to get auth for other scope
|
@@ -184,14 +203,13 @@ module Aspera
|
|
184
203
|
when :web
|
185
204
|
# AoC Web based Auth
|
186
205
|
check_code=SecureRandom.uuid
|
187
|
-
|
188
|
-
"#{@params[:base_url]}/#{@params[:path_authorize]}",
|
189
|
-
p_client_id_and_scope.merge({
|
206
|
+
auth_params=p_client_id_and_scope.merge({
|
190
207
|
:response_type => 'code',
|
191
208
|
:redirect_uri => @params[:redirect_uri],
|
192
|
-
:client_secret => @params[:client_secret],
|
193
209
|
:state => check_code
|
194
|
-
})
|
210
|
+
})
|
211
|
+
auth_params[:client_secret]=@params[:client_secret] if @params.has_key?(:client_secret)
|
212
|
+
login_page_url=Rest.build_uri("#{@params[:base_url]}/#{@params[:path_authorize]}",auth_params)
|
195
213
|
# here, we need a human to authorize on a web page
|
196
214
|
code=goto_page_and_get_code(login_page_url,check_code)
|
197
215
|
# exchange code for token
|
@@ -211,9 +229,19 @@ module Aspera
|
|
211
229
|
:iss => @params[:client_id], # issuer
|
212
230
|
:sub => @params[:jwt_subject], # subject
|
213
231
|
:aud => @params[:jwt_audience], # audience
|
214
|
-
:nbf => seconds_since_epoch-
|
215
|
-
:exp => seconds_since_epoch+
|
232
|
+
:nbf => seconds_since_epoch-JWT_NOTBEFORE_OFFSET_SEC, # not before
|
233
|
+
:exp => seconds_since_epoch+JWT_EXPIRY_OFFSET_SEC # expiration
|
216
234
|
}
|
235
|
+
# Hum.. compliant ? TODO: remove when Faspex5 API is clarified
|
236
|
+
if @params[:jwt_is_f5]
|
237
|
+
payload[:jti] = SecureRandom.uuid
|
238
|
+
payload[:iat] = seconds_since_epoch
|
239
|
+
payload.delete(:nbf)
|
240
|
+
p_scope[:redirect_uri]="https://127.0.0.1:5000/token"
|
241
|
+
p_scope[:state]=SecureRandom.uuid
|
242
|
+
p_scope[:client_id]=@params[:client_id]
|
243
|
+
@token_auth_api.params[:auth]={:type=>:none}
|
244
|
+
end
|
217
245
|
|
218
246
|
# non standard, only for global ids
|
219
247
|
payload.merge!(@params[:jwt_add]) if @params.has_key?(:jwt_add)
|
@@ -222,8 +250,8 @@ module Aspera
|
|
222
250
|
|
223
251
|
Log.log.debug("private=[#{rsa_private}]")
|
224
252
|
|
225
|
-
Log.log.debug("JWT
|
226
|
-
assertion = JWT.encode(payload, rsa_private, 'RS256')
|
253
|
+
Log.log.debug("JWT payload=[#{payload}]")
|
254
|
+
assertion = JWT.encode(payload, rsa_private, 'RS256',@params[:jwt_headers]||{})
|
227
255
|
|
228
256
|
Log.log.debug("assertion=[#{assertion}]")
|
229
257
|
|
@@ -233,8 +261,10 @@ module Aspera
|
|
233
261
|
}))
|
234
262
|
when :url_token
|
235
263
|
# AoC Public Link
|
264
|
+
params={:url_token=>@params[:url_token]}
|
265
|
+
params[:password]=@params[:password] if @params.has_key?(:password)
|
236
266
|
resp=create_token_advanced({
|
237
|
-
:json_params =>
|
267
|
+
:json_params => params,
|
238
268
|
:url_params => p_scope.merge({
|
239
269
|
:grant_type => 'url_token'
|
240
270
|
})})
|
@@ -288,32 +318,5 @@ module Aspera
|
|
288
318
|
return 'Bearer '+token_data[@params[:token_field]]
|
289
319
|
end
|
290
320
|
|
291
|
-
# open the login page, wait for code and return parameters
|
292
|
-
def self.goto_page_and_get_request(redirect_uri,login_page_url,html_page=THANK_YOU_HTML)
|
293
|
-
Log.log.info "login_page_url=#{login_page_url}".bg_red().gray()
|
294
|
-
# browser start is not blocking, we hope here that starting is slower than opening port
|
295
|
-
OpenApplication.instance.uri(login_page_url)
|
296
|
-
port=URI.parse(redirect_uri).port
|
297
|
-
Log.log.info "listening on port #{port}"
|
298
|
-
request_params=nil
|
299
|
-
TCPServer.open('127.0.0.1', port) { |webserver|
|
300
|
-
Log.log.info "server=#{webserver}"
|
301
|
-
websession = webserver.accept
|
302
|
-
sleep 1 # TODO: sometimes: returns nil ? use webrick ?
|
303
|
-
line = websession.gets.chomp
|
304
|
-
Log.log.info "line=#{line}"
|
305
|
-
if ! line.start_with?('GET /?') then
|
306
|
-
raise "unexpected request"
|
307
|
-
end
|
308
|
-
request = line.partition('?').last.partition(' ').first
|
309
|
-
data=URI.decode_www_form(request)
|
310
|
-
request_params=data.to_h
|
311
|
-
Log.log.debug "request_params=#{request_params}"
|
312
|
-
websession.print "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n#{html_page}"
|
313
|
-
websession.close
|
314
|
-
}
|
315
|
-
return request_params
|
316
|
-
end
|
317
|
-
|
318
321
|
end # OAuth
|
319
322
|
end # Aspera
|
@@ -55,12 +55,17 @@ module Aspera
|
|
55
55
|
@cache.delete(object_id)
|
56
56
|
end
|
57
57
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
58
|
+
def garbage_collect(persist_category,max_age_seconds=nil)
|
59
|
+
garbage_files=Dir[File.join(@folder,persist_category+'*'+FILE_SUFFIX)]
|
60
|
+
if !max_age_seconds.nil?
|
61
|
+
current_time = Time.now
|
62
|
+
garbage_files.select! { |filepath| (current_time - File.stat(filepath).mtime).to_i > max_age_seconds}
|
63
|
+
end
|
64
|
+
garbage_files.each do |filepath|
|
61
65
|
File.delete(filepath)
|
66
|
+
Log.log.debug("Deleted expired: #{filepath}")
|
62
67
|
end
|
63
|
-
return
|
68
|
+
return garbage_files
|
64
69
|
end
|
65
70
|
|
66
71
|
private
|