aspera-cli 4.27.2 → 4.27.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +133 -0
- data/CONTRIBUTING.md +5 -2
- data/bin/ascli +3 -1
- data/docs/README.md +1006 -766
- data/lib/aspera/agent/base.rb +7 -2
- data/lib/aspera/agent/connect.rb +6 -8
- data/lib/aspera/agent/desktop.rb +2 -6
- data/lib/aspera/agent/direct.rb +52 -22
- data/lib/aspera/agent/node.rb +9 -8
- data/lib/aspera/agent/transferd.rb +2 -2
- data/lib/aspera/api/alee.rb +1 -1
- data/lib/aspera/api/aoc.rb +14 -12
- data/lib/aspera/api/ats.rb +1 -1
- data/lib/aspera/api/cos_node.rb +2 -2
- data/lib/aspera/api/faspex.rb +11 -7
- data/lib/aspera/api/httpgw.rb +38 -35
- data/lib/aspera/api/node.rb +39 -34
- data/lib/aspera/ascmd.rb +3 -1
- data/lib/aspera/ascp/installation.rb +63 -28
- data/lib/aspera/ascp/management.rb +1 -0
- data/lib/aspera/assert.rb +4 -0
- data/lib/aspera/cli/ascp_actions.rb +20 -41
- data/lib/aspera/cli/async_transfer_store.rb +12 -11
- data/lib/aspera/cli/bootstrapper.rb +14 -16
- data/lib/aspera/cli/command_line.rb +252 -0
- data/lib/aspera/cli/command_registry.rb +215 -37
- data/lib/aspera/cli/command_spec.rb +104 -15
- data/lib/aspera/cli/completion/ascli.bash +12 -0
- data/lib/aspera/cli/completion/ascli.fish +16 -0
- data/lib/aspera/cli/completion/ascli.zsh +19 -0
- data/lib/aspera/cli/context.rb +3 -0
- data/lib/aspera/cli/deprecation.rb +37 -0
- data/lib/aspera/cli/extended_value.rb +6 -3
- data/lib/aspera/cli/formatter.rb +94 -80
- data/lib/aspera/cli/gem_checker.rb +1 -1
- data/lib/aspera/cli/hints.rb +7 -6
- data/lib/aspera/cli/http.rb +22 -34
- data/lib/aspera/cli/info.rb +3 -0
- data/lib/aspera/cli/mcp_tool.rb +47 -83
- data/lib/aspera/cli/option_declarator.rb +33 -42
- data/lib/aspera/cli/option_registry.rb +69 -0
- data/lib/aspera/cli/option_types.rb +105 -0
- data/lib/aspera/cli/option_value.rb +278 -0
- data/lib/aspera/cli/options.schema.yaml +124 -15
- data/lib/aspera/cli/parser.rb +333 -862
- data/lib/aspera/cli/plugins/alee.rb +7 -4
- data/lib/aspera/cli/plugins/aoc.rb +545 -518
- data/lib/aspera/cli/plugins/ats.rb +59 -80
- data/lib/aspera/cli/plugins/base.rb +221 -265
- data/lib/aspera/cli/plugins/basic_auth.rb +2 -10
- data/lib/aspera/cli/plugins/config.rb +263 -184
- data/lib/aspera/cli/plugins/console.rb +103 -39
- data/lib/aspera/cli/plugins/cos.rb +6 -23
- data/lib/aspera/cli/plugins/factory.rb +3 -0
- data/lib/aspera/cli/plugins/faspex5.rb +204 -182
- data/lib/aspera/cli/plugins/faspio.rb +6 -11
- data/lib/aspera/cli/plugins/httpgw.rb +8 -11
- data/lib/aspera/cli/plugins/mcp.rb +20 -55
- data/lib/aspera/cli/plugins/node.rb +300 -327
- data/lib/aspera/cli/plugins/orchestrator.rb +152 -110
- data/lib/aspera/cli/plugins/preview.rb +96 -105
- data/lib/aspera/cli/plugins/server.rb +78 -53
- data/lib/aspera/cli/plugins/shares.rb +80 -131
- data/lib/aspera/cli/preset_actions.rb +44 -27
- data/lib/aspera/cli/preset_manager.rb +44 -19
- data/lib/aspera/cli/prompt.rb +36 -0
- data/lib/aspera/cli/result.rb +42 -36
- data/lib/aspera/cli/runner.rb +32 -59
- data/lib/aspera/cli/special_values.rb +5 -0
- data/lib/aspera/cli/sync_actions.rb +51 -46
- data/lib/aspera/cli/terminal_formatter.rb +9 -3
- data/lib/aspera/cli/transfer_actions.rb +14 -9
- data/lib/aspera/cli/transfer_agent.rb +34 -38
- data/lib/aspera/cli/transfer_progress.rb +290 -55
- data/lib/aspera/cli/vault_manager.rb +0 -17
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +5 -3
- data/lib/aspera/coverage.rb +1 -1
- data/lib/aspera/environment.rb +35 -5
- data/lib/aspera/faspex_gw.rb +2 -1
- data/lib/aspera/faspex_postproc.rb +1 -0
- data/lib/aspera/graphql.rb +5 -5
- data/lib/aspera/json_rpc/client.rb +5 -5
- data/lib/aspera/keychain/encrypted_hash.rb +2 -2
- data/lib/aspera/keychain/factory.rb +2 -1
- data/lib/aspera/keychain/one_password_api.rb +1 -1
- data/lib/aspera/link_header.rb +2 -2
- data/lib/aspera/log.rb +47 -27
- data/lib/aspera/markdown.rb +2 -0
- data/lib/aspera/mime.rb +25 -0
- data/lib/aspera/node_emulator.rb +759 -0
- data/lib/aspera/oauth/base.rb +37 -26
- data/lib/aspera/oauth/factory.rb +7 -3
- data/lib/aspera/oauth/generic.rb +1 -1
- data/lib/aspera/oauth/json_credentials.rb +34 -0
- data/lib/aspera/oauth/jwt.rb +4 -5
- data/lib/aspera/oauth/web.rb +9 -8
- data/lib/aspera/oauth.rb +1 -0
- data/lib/aspera/persistency_folder.rb +1 -3
- data/lib/aspera/preview/file_types.rb +4 -4
- data/lib/aspera/preview/generator.rb +11 -1
- data/lib/aspera/preview/options.schema.yaml +119 -0
- data/lib/aspera/preview/terminal.rb +4 -3
- data/lib/aspera/preview/utils.rb +9 -6
- data/lib/aspera/products/connect.rb +1 -1
- data/lib/aspera/rainbow.rb +7 -0
- data/lib/aspera/rest/aspera_errors.rb +72 -0
- data/lib/aspera/rest/call_error.rb +27 -0
- data/lib/aspera/rest/client.rb +523 -0
- data/lib/aspera/rest/error_analyzer.rb +113 -0
- data/lib/aspera/rest/list.rb +149 -0
- data/lib/aspera/rest/parameters.rb +55 -0
- data/lib/aspera/rest/util.rb +176 -0
- data/lib/aspera/rest.rb +7 -621
- data/lib/aspera/schema/IBM Aspera Console-enhanced.yaml +1125 -0
- data/lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml +0 -20
- data/lib/aspera/schema/IBM Aspera Orchestrator API-v1.yaml +1784 -0
- data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +1230 -137
- data/lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml +2395 -0
- data/lib/aspera/schema/IBM_Aspera_Shares.yaml +14 -13
- data/lib/aspera/schema/documentation.rb +13 -3
- data/lib/aspera/schema/reader.rb +12 -18
- data/lib/aspera/schema/registry.rb +23 -1
- data/lib/aspera/schema/validator.rb +92 -0
- data/lib/aspera/secret_hider.rb +36 -25
- data/lib/aspera/string_ext.rb +15 -0
- data/lib/aspera/temp_file_manager.rb +6 -5
- data/lib/aspera/transfer/parameters.rb +2 -0
- data/lib/aspera/transfer/spec.rb +1 -0
- data/lib/aspera/uri_reader.rb +11 -11
- data/lib/aspera/web_auth/index.html +147 -0
- data/lib/aspera/web_auth/server.rb +81 -0
- data.tar.gz.sig +0 -0
- metadata +43 -9
- metadata.gz.sig +0 -0
- data/lib/aspera/colors.rb +0 -79
- data/lib/aspera/node_simulator.rb +0 -344
- data/lib/aspera/preview/options.rb +0 -45
- data/lib/aspera/rest_call_error.rb +0 -25
- data/lib/aspera/rest_error_analyzer.rb +0 -111
- data/lib/aspera/rest_errors_aspera.rb +0 -58
- data/lib/aspera/rest_list.rb +0 -136
- data/lib/aspera/web_auth.rb +0 -211
data/lib/aspera/rest_list.rb
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Aspera
|
|
4
|
-
# List and lookup methods for Rest
|
|
5
|
-
# To be included in classes inheriting Rest that require those methods.
|
|
6
|
-
module RestList
|
|
7
|
-
# `max`: special query parameter: max number of items for list command
|
|
8
|
-
MAX_ITEMS = 'max'
|
|
9
|
-
# `pmax`: special query parameter: max number of pages for list command
|
|
10
|
-
MAX_PAGES = 'pmax'
|
|
11
|
-
|
|
12
|
-
# Query entity by general search (read with parameter `q`)
|
|
13
|
-
#
|
|
14
|
-
# @param entity [String] Path of entity in API
|
|
15
|
-
# @param value [String] Value of field of searched entity
|
|
16
|
-
# @param field [String] Field of searched entity
|
|
17
|
-
# @param query [Hash] Optional additional search query parameters
|
|
18
|
-
# @return [Hash] A single entity matching the search, or an exception if not found or multiple found
|
|
19
|
-
def lookup_with_q(entity, value:, field: 'name', query: {})
|
|
20
|
-
Aspera.assert_type(query, Hash) { 'query' }
|
|
21
|
-
Aspera.assert_type(field, String) { 'field' }
|
|
22
|
-
# returns entities matching the query (it matches against several fields in case insensitive way)
|
|
23
|
-
# We don't do paging, as anyway, we look for only one match
|
|
24
|
-
matching_items = read(entity, query.merge({'q' => value}))
|
|
25
|
-
# API style: {totalcount:, ...} cspell: disable-line: TODO: is that total_count ?
|
|
26
|
-
# @type [Array<Hash{String => String}>]
|
|
27
|
-
matching_items = matching_items[entity] if matching_items.is_a?(Hash)
|
|
28
|
-
Aspera.assert_type(matching_items, Array)
|
|
29
|
-
case matching_items.length
|
|
30
|
-
when 1 then return matching_items.first
|
|
31
|
-
when 0 then raise EntityNotFound, %Q{No such #{entity}: "#{value}"}
|
|
32
|
-
else
|
|
33
|
-
# multiple case insensitive partial matches, try case insensitive full match
|
|
34
|
-
# (anyway AoC does not allow creation of 2 entities with same case insensitive field value)
|
|
35
|
-
value_matches = matching_items.select { |i| i[field].casecmp?(value) }
|
|
36
|
-
case value_matches.length
|
|
37
|
-
when 1 then return value_matches.first
|
|
38
|
-
when 0 then raise Error, "#{entity}: Multiple case insensitive partial match for: \"#{value}\" in #{matching_items.map { |i| i[field] }.join(', ')} but no case insensitive full match. Please be more specific or give exact #{field}."
|
|
39
|
-
else raise Error, "Two entities cannot have the same case insensitive #{field}: #{value_matches.map { |i| i[field] }}"
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Get a (full or partial) list of all entities of a given type.
|
|
45
|
-
# Using query: `offset` + `limit`
|
|
46
|
-
# And response `total_count`
|
|
47
|
-
# @param entity [String,Symbol] API endpoint of entity to list
|
|
48
|
-
# @param items_key [String] Key in the result to get the list of items (Default: same as `entity`)
|
|
49
|
-
# @param query [Hash,nil] Additional query parameters
|
|
50
|
-
# @return [Array<(Array<Hash>, Integer)>] items, total_count
|
|
51
|
-
def list_entities_limit_offset_total_count(
|
|
52
|
-
entity:,
|
|
53
|
-
operation: 'GET',
|
|
54
|
-
items_key: nil,
|
|
55
|
-
query: nil
|
|
56
|
-
)
|
|
57
|
-
entity = entity.to_s if entity.is_a?(Symbol)
|
|
58
|
-
items_key = entity.split('/').last if items_key.nil?
|
|
59
|
-
query = {} if query.nil?
|
|
60
|
-
Aspera.assert_type(entity, String)
|
|
61
|
-
Aspera.assert_type(items_key, String)
|
|
62
|
-
Aspera.assert_type(query, Hash)
|
|
63
|
-
Log.log.debug { "list_entities t=#{entity} k=#{items_key}" }
|
|
64
|
-
Log.dump(:query, query)
|
|
65
|
-
result = []
|
|
66
|
-
offset = 0
|
|
67
|
-
max_items = query.delete(MAX_ITEMS)
|
|
68
|
-
remain_pages = query.delete(MAX_PAGES)
|
|
69
|
-
# Merge default parameters, by default 100 per page
|
|
70
|
-
query = {'limit'=> PER_PAGE_DEFAULT}.merge(query)
|
|
71
|
-
total_count = nil
|
|
72
|
-
call_args = {
|
|
73
|
-
operation: operation,
|
|
74
|
-
subpath: entity,
|
|
75
|
-
query: query,
|
|
76
|
-
headers: {'Accept' => Mime::JSON}
|
|
77
|
-
}
|
|
78
|
-
loop do
|
|
79
|
-
query['offset'] = offset
|
|
80
|
-
page_result = call(**call_args)
|
|
81
|
-
Aspera.assert_type(page_result[items_key], Array)
|
|
82
|
-
result.concat(page_result[items_key])
|
|
83
|
-
# Reach the limit set by user ?
|
|
84
|
-
if !max_items.nil? && (result.length >= max_items)
|
|
85
|
-
result = result.slice(0, max_items)
|
|
86
|
-
break
|
|
87
|
-
end
|
|
88
|
-
total_count ||= page_result['total_count']
|
|
89
|
-
break if result.length >= total_count
|
|
90
|
-
remain_pages -= 1 unless remain_pages.nil?
|
|
91
|
-
break if remain_pages == 0
|
|
92
|
-
offset += page_result[items_key].length
|
|
93
|
-
RestParameters.instance.spinner_cb.call("#{result.length} / #{total_count || '?'}")
|
|
94
|
-
end
|
|
95
|
-
RestParameters.instance.spinner_cb.call(action: :success)
|
|
96
|
-
return result, total_count
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
# Lookup an entity id from its name.
|
|
100
|
-
# Uses query `q` if `query` is `:default` and `field` is `name`.
|
|
101
|
-
# @param entity [String] Type of entity to lookup, by default it is the path, and it is also the field name in result
|
|
102
|
-
# @param value [String] Value to lookup
|
|
103
|
-
# @param field [String] Field to match, by default it is `'name'`
|
|
104
|
-
# @param items_key [String] Key in the result to get the list of items (override entity)
|
|
105
|
-
# @param query [Hash] Additional query parameters (Default: `:default`)
|
|
106
|
-
def lookup_entity_by_field(entity:, value:, field: 'name', items_key: nil, query: :default)
|
|
107
|
-
if query.eql?(:default)
|
|
108
|
-
Aspera.assert_values(field, ['name']) { 'Default query field' }
|
|
109
|
-
query = {'q'=> value}
|
|
110
|
-
end
|
|
111
|
-
lookup_entity_generic(entity: entity, field: field, value: value) { list_entities_limit_offset_total_count(entity: entity, items_key: items_key, query: query).first }
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# Lookup entity by field and value.
|
|
115
|
-
# Extracts a single result from the list returned by the block.
|
|
116
|
-
#
|
|
117
|
-
# @param entity [String] Type of entity to lookup (path, and by default it is also the field name in result)
|
|
118
|
-
# @param value [String] Value to match against the field.
|
|
119
|
-
# @param field [String] Field to match in the hashes (defaults to 'name').
|
|
120
|
-
# @yield [] A mandatory block that returns an Array of Hashes.
|
|
121
|
-
# @return [Hash] The unique matching object.
|
|
122
|
-
# @raise [Cli::BadIdentifier] If 0 or >1 matches are found.
|
|
123
|
-
def lookup_entity_generic(entity:, value:, field: 'name')
|
|
124
|
-
Aspera.assert(block_given?, 'block required for lookup_entity_generic')
|
|
125
|
-
found = yield
|
|
126
|
-
Aspera.assert_array_all(found, Hash)
|
|
127
|
-
found = found.select { |i| i[field].eql?(value) }
|
|
128
|
-
return found.first if found.length.eql?(1)
|
|
129
|
-
raise Cli::BadIdentifier.new(entity, value, field: field, count: found.length)
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
PER_PAGE_DEFAULT = 1000
|
|
133
|
-
private_constant :PER_PAGE_DEFAULT
|
|
134
|
-
module_function :lookup_entity_generic
|
|
135
|
-
end
|
|
136
|
-
end
|
data/lib/aspera/web_auth.rb
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'aspera/web_server_simple'
|
|
4
|
-
require 'aspera/assert'
|
|
5
|
-
require 'erb'
|
|
6
|
-
|
|
7
|
-
module Aspera
|
|
8
|
-
# servlet called on callback: it records the callback request
|
|
9
|
-
class WebAuthServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
10
|
-
# @param server [WEBrick::HTTPServer] the HTTP server instance
|
|
11
|
-
# @param web_auth [WebAuth] the WebAuth instance to record the callback
|
|
12
|
-
def initialize(server, web_auth)
|
|
13
|
-
Log.log.debug('WebAuthServlet initialize')
|
|
14
|
-
super(server)
|
|
15
|
-
@web_auth = web_auth
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def service(request, response)
|
|
19
|
-
Log.log.debug { "received request from browser #{request.request_method} #{request.path}" }
|
|
20
|
-
Aspera.assert_values(request.request_method, ['GET'], type: WEBrick::HTTPStatus::MethodNotAllowed) { 'HTTP verb' }
|
|
21
|
-
additional_info = @web_auth.signal_request(request)
|
|
22
|
-
response.status = 200
|
|
23
|
-
response.content_type = 'text/html'
|
|
24
|
-
response.body = <<~HTML
|
|
25
|
-
<!DOCTYPE html>
|
|
26
|
-
<html lang="en">
|
|
27
|
-
<head>
|
|
28
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
29
|
-
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIiBmaWxsPSJub25lIiBzdHJva2U9IiMyMjIiIHN0cm9rZS13aWR0aD0iMyI+CiAgPGxpbmUgeDE9IjMiIHkxPSIzIiB4Mj0iMjkiIHkyPSIyOSIgIHN0cm9rZT0icmVkIi8+CiAgPGxpbmUgeDE9IjI5IiB5MT0iMyIgeDI9IjMiIHkyPSIyOSIgc3Ryb2tlPSJyZWQiIC8+Cjwvc3ZnPg==" type="image/svg+xml">
|
|
30
|
-
<title>Close Now</title>
|
|
31
|
-
<style>
|
|
32
|
-
body {
|
|
33
|
-
font-family: Arial, sans-serif;
|
|
34
|
-
text-align: center;
|
|
35
|
-
padding: 2rem;
|
|
36
|
-
margin: 0;
|
|
37
|
-
background: linear-gradient(135deg, #f0f4f8, #d9e2ec);
|
|
38
|
-
color: #333;
|
|
39
|
-
overflow: hidden; /* Ensure no scrollbars for the background animation */
|
|
40
|
-
position: relative;
|
|
41
|
-
}
|
|
42
|
-
h1 {
|
|
43
|
-
font-size: 2.5rem;
|
|
44
|
-
color: #0078d4;
|
|
45
|
-
}
|
|
46
|
-
p {
|
|
47
|
-
font-size: 1.2rem;
|
|
48
|
-
margin-top: 1rem;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/* Styling for animated IBM logos */
|
|
52
|
-
.logo {
|
|
53
|
-
position: absolute;
|
|
54
|
-
bottom: -100px;
|
|
55
|
-
width: 40px;
|
|
56
|
-
height: 40px;
|
|
57
|
-
background: none;
|
|
58
|
-
display: flex;
|
|
59
|
-
justify-content: center;
|
|
60
|
-
align-items: center;
|
|
61
|
-
animation: rise 10s infinite ease-in-out;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.logo svg {
|
|
65
|
-
width: 100%;
|
|
66
|
-
height: 100%;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
.logo:nth-child(odd) {
|
|
70
|
-
animation-duration: 8s;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
.logo:nth-child(even) {
|
|
74
|
-
animation-duration: 12s;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
@keyframes rise {
|
|
78
|
-
0% {
|
|
79
|
-
transform: translateY(0) scale(1);
|
|
80
|
-
opacity: 1;
|
|
81
|
-
}
|
|
82
|
-
50% {
|
|
83
|
-
opacity: 0.7;
|
|
84
|
-
}
|
|
85
|
-
100% {
|
|
86
|
-
transform: translateY(-120vh) scale(0.7);
|
|
87
|
-
opacity: 0;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
</style>
|
|
91
|
-
</head>
|
|
92
|
-
<body>
|
|
93
|
-
<h1>Thank You!</h1>
|
|
94
|
-
<p>You can close this window.</p>
|
|
95
|
-
<p>#{ERB::Util.html_escape(additional_info) unless additional_info.nil?}</p>
|
|
96
|
-
|
|
97
|
-
<!-- JavaScript to generate IBM logos -->
|
|
98
|
-
<script>
|
|
99
|
-
// Function to create logos dynamically
|
|
100
|
-
function createLogos() {
|
|
101
|
-
const body = document.body;
|
|
102
|
-
const svgContent = `
|
|
103
|
-
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000px" height="401.149px" viewBox="0 0 1000 401.149" xml:space="preserve">
|
|
104
|
-
<g>
|
|
105
|
-
<rect fill="#1F70C1" x="0" y="373.217" width="194.433" height="27.833"/>
|
|
106
|
-
<rect fill="#1F70C1" x="0" y="319.83" width="194.433" height="27.931"/>
|
|
107
|
-
<rect fill="#1F70C1" x="55.468" y="266.541" width="83.399" height="27.932"/>
|
|
108
|
-
<rect fill="#1F70C1" x="55.468" y="213.253" width="83.399" height="27.932"/>
|
|
109
|
-
<rect fill="#1F70C1" x="55.468" y="159.964" width="83.399" height="27.932"/>
|
|
110
|
-
<rect fill="#1F70C1" x="55.468" y="106.577" width="83.399" height="27.932"/>
|
|
111
|
-
<rect fill="#1F70C1" x="0" y="53.288" width="194.433" height="27.932"/>
|
|
112
|
-
<rect fill="#1F70C1" x="0" y="0" width="194.433" height="27.932"/>
|
|
113
|
-
<path fill="#1F70C1" d="M222.167,347.761h299.029c5.051-8.617,8.815-18.027,11.094-27.932H222.167V347.761z"/>
|
|
114
|
-
<path fill="#1F70C1" d="M497.92,213.253H277.734v27.932h243.463C514.857,230.487,507.032,221.078,497.92,213.253z"/>
|
|
115
|
-
<path fill="#1F70C1" d="M277.734,159.964v27.932H497.92c9.311-7.825,17.135-17.235,23.277-27.932H277.734z"/>
|
|
116
|
-
<path fill="#1F70C1" d="M521.197,53.288H222.167V81.22H532.29C529.715,71.315,525.951,61.906,521.197,53.288z"/>
|
|
117
|
-
<path fill="#1F70C1" d="M429.279,0H222.167v27.932h278.526C482.072,10.697,456.815,0,429.279,0z"/>
|
|
118
|
-
<rect fill="#1F70C1" x="277.734" y="106.577" width="83.3" height="27.932"/>
|
|
119
|
-
<path fill="#1F70C1" d="M444.433,134.509h87.163c2.476-8.914,3.764-18.324,3.764-27.932h-90.927z"/>
|
|
120
|
-
<rect fill="#1F70C1" x="277.734" y="266.541" width="83.3" height="27.932"/>
|
|
121
|
-
<path fill="#1F70C1" d="M444.433,266.541v27.932h90.927c0-9.608-1.288-19.017-3.764-27.932H444.433z"/>
|
|
122
|
-
<path fill="#1F70C1" d="M222.167,400.852h207.112c27.734,0,52.793-10.697,71.513-27.932H222.167V400.852z"/>
|
|
123
|
-
<rect fill="#1F70C1" x="555.567" y="373.217" width="138.866" height="27.833"/>
|
|
124
|
-
<rect fill="#1F70C1" x="555.567" y="319.83" width="138.866" height="27.931"/>
|
|
125
|
-
<rect fill="#1F70C1" x="611.034" y="266.541" width="83.399" height="27.932"/>
|
|
126
|
-
<rect fill="#1F70C1" x="611.034" y="213.253" width="83.399" height="27.932"/>
|
|
127
|
-
<polygon fill="#1F70C1" points="733.063,53.288 555.567,53.288 555.567,81.22 742.67,81.22"/>
|
|
128
|
-
<polygon fill="#1F70C1" points="714.639,0 555.567,0 555.567,27.932 724.247,27.932"/>
|
|
129
|
-
<rect fill="#1F70C1" x="861.034" y="373.217" width="138.866" height="27.833"/>
|
|
130
|
-
<rect fill="#1F70C1" x="861.034" y="319.83" width="138.866" height="27.931"/>
|
|
131
|
-
<rect fill="#1F70C1" x="861.034" y="266.541" width="83.399" height="27.932"/>
|
|
132
|
-
<rect fill="#1F70C1" x="861.034" y="213.253" width="83.399" height="27.932"/>
|
|
133
|
-
<polygon fill="#1F70C1" points="861.034,187.896 944.433,187.896 944.433,159.964 861.034,159.964 694.433,159.964 611.034,159.964 611.034,187.896 694.433,187.896 852.219,187.896"/>
|
|
134
|
-
<polygon fill="#1F70C1" points="944.433,106.577 803.982,106.577 794.374,134.509 944.433,134.509"/>
|
|
135
|
-
<polygon fill="#1F70C1" points="840.927,0 831.319,27.932 1000,27.932 1000,0"/>
|
|
136
|
-
<polygon fill="#1F70C1" points="777.734,400.852 787.341,373.217 768.126,373.217"/>
|
|
137
|
-
<polygon fill="#1F70C1" points="759.311,347.761 796.157,347.761 806.062,319.83 749.505,319.83"/>
|
|
138
|
-
<polygon fill="#1F70C1" points="740.59,294.473 814.877,294.473 824.683,266.541 730.784,266.541"/>
|
|
139
|
-
<polygon fill="#1F70C1" points="721.969,241.185 833.597,241.185 843.106,213.253 712.361,213.253"/>
|
|
140
|
-
<polygon fill="#1F70C1" points="611.034,134.509 761.093,134.509 751.486,106.577 611.034,106.577"/>
|
|
141
|
-
<polygon fill="#1F70C1" points="812.896,81.22 1000,81.22 1000,53.288 822.405,53.288"/>
|
|
142
|
-
</g>
|
|
143
|
-
</svg>
|
|
144
|
-
`;
|
|
145
|
-
for (let i = 0; i < 20; i++) {
|
|
146
|
-
const logo = document.createElement('div');
|
|
147
|
-
logo.className = 'logo';
|
|
148
|
-
const size = Math.random() * 30 + 20; // Random size between 20px and 50px
|
|
149
|
-
logo.style.width = `${size}px`;
|
|
150
|
-
logo.style.height = `${size}px`;
|
|
151
|
-
logo.style.left = `${Math.random() * 100}vw`;
|
|
152
|
-
logo.style.animationDelay = `${Math.random() * 5}s`;
|
|
153
|
-
logo.innerHTML = svgContent;
|
|
154
|
-
body.appendChild(logo);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Call the function to create logos on load
|
|
159
|
-
createLogos();
|
|
160
|
-
</script>
|
|
161
|
-
</body>
|
|
162
|
-
</html>
|
|
163
|
-
HTML
|
|
164
|
-
|
|
165
|
-
return
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
# start a local web server
|
|
170
|
-
# then start a browser that will callback the local server upon authentication
|
|
171
|
-
# store the final query
|
|
172
|
-
class WebAuth < WebServerSimple
|
|
173
|
-
# @param endpoint_url [String] e.g. 'https://127.0.0.1:12345'
|
|
174
|
-
# @param additional_info [String] Information in web page
|
|
175
|
-
def initialize(endpoint_url, additional_info = nil)
|
|
176
|
-
uri = URI.parse(endpoint_url)
|
|
177
|
-
super(uri)
|
|
178
|
-
@mutex = Mutex.new
|
|
179
|
-
@cond = ConditionVariable.new
|
|
180
|
-
@expected_path = uri.path.empty? ? '/' : uri.path
|
|
181
|
-
@query = nil
|
|
182
|
-
@additional_info = additional_info
|
|
183
|
-
# last argument (self) is provided to constructor of servlet
|
|
184
|
-
mount(@expected_path, WebAuthServlet, self)
|
|
185
|
-
# server runs in thread
|
|
186
|
-
Thread.new { start }
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
# Called by web server thread on received request
|
|
190
|
-
# @return [String] additional information for web page
|
|
191
|
-
def signal_request(request)
|
|
192
|
-
raise WEBrick::HTTPStatus::NotFound, "unexpected path: #{request.path}" unless request.path.eql?(@expected_path)
|
|
193
|
-
# acquire lock and signal change
|
|
194
|
-
@mutex.synchronize do
|
|
195
|
-
@query = request.query
|
|
196
|
-
@cond.signal
|
|
197
|
-
end
|
|
198
|
-
return @additional_info
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
# wait for request on web server (main thread)
|
|
202
|
-
# @return [Hash] the query
|
|
203
|
-
def received_request
|
|
204
|
-
# wait for signal from thread
|
|
205
|
-
@mutex.synchronize { @cond.wait(@mutex) }
|
|
206
|
-
# tell server thread to stop
|
|
207
|
-
shutdown
|
|
208
|
-
return @query
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
end
|