gloo 3.6.2 → 3.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/VERSION +1 -1
- data/lib/VERSION_NOTES +13 -0
- data/lib/gloo/app/platform.rb +1 -0
- data/lib/gloo/objs/security/csrf_token.rb +72 -0
- data/lib/gloo/objs/system/file_handle.rb +44 -2
- data/lib/gloo/objs/web/uri.rb +0 -2
- data/lib/gloo/objs/web_svr/svr.rb +85 -7
- data/lib/gloo/web_svr/asset.rb +95 -2
- data/lib/gloo/web_svr/asset_info.rb +112 -0
- data/lib/gloo/web_svr/embedded_renderer.rb +52 -0
- data/lib/gloo/web_svr/handler.rb +3 -0
- data/lib/gloo/web_svr/request.rb +8 -2
- data/lib/gloo/web_svr/request_params.rb +23 -0
- data/lib/gloo/web_svr/response.rb +4 -1
- data/lib/gloo/web_svr/routing/router.rb +7 -0
- data/lib/gloo/web_svr/routing/show_routes.rb +2 -3
- data/lib/gloo/web_svr/session.rb +54 -6
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c8d357cda5602195adcfddc50c58705d34670b6ac01848eb8a1d66243571356
|
4
|
+
data.tar.gz: 86687c8e18f4843dc9bca97111e140c26750479fce8619341a902284dde5a573
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: baa186fd096e79a6152b7c287e23048a4b2fa67af5aa5db1c4e860918f42477b75e52fabbae8309506adfa32a77f5616bc2c4f4b22b6972142cb3977c9c965c9
|
7
|
+
data.tar.gz: 8467cf3db96cd931cad4dc06910a4933c65284b25675a3f884e17d5639cb8b3d9b50ff8bd1c171d329f318317390e715a9a5af62dceed681509fe336d28c3439
|
data/lib/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.8.0
|
data/lib/VERSION_NOTES
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
3.8.0 - 2025.01.23
|
2
|
+
- Fixes issue with sessions
|
3
|
+
- Adds authenticity token tag and supporting session id and validation
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
3.7.0 - 2025.01.09
|
8
|
+
- Adds File message to get SHA256 hash
|
9
|
+
- Asset Fingerprinting
|
10
|
+
- Adds message to web app to show assets (in the terminal)
|
11
|
+
- Adds asset helper tags
|
12
|
+
|
13
|
+
|
1
14
|
3.6.2 - 2024.12.19
|
2
15
|
- Bug fix for URI open
|
3
16
|
|
data/lib/gloo/app/platform.rb
CHANGED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2025 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# Helper class to generate and verify a csrf token.
|
5
|
+
#
|
6
|
+
require 'securerandom'
|
7
|
+
require 'base64'
|
8
|
+
require 'active_support/security_utils'
|
9
|
+
|
10
|
+
module Gloo
|
11
|
+
module Objs
|
12
|
+
class CsrfToken
|
13
|
+
|
14
|
+
TOKEN_LENGTH = 32
|
15
|
+
AUTHENTICITY_TOKEN = 'authenticity_token'.freeze
|
16
|
+
|
17
|
+
#
|
18
|
+
# Generate a random token
|
19
|
+
#
|
20
|
+
def self.generate_csrf_token
|
21
|
+
SecureRandom.base64( TOKEN_LENGTH )
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Generate a masked token.
|
26
|
+
#
|
27
|
+
def self.mask_token( base_token )
|
28
|
+
one_time_pad = SecureRandom.random_bytes( base_token.bytesize )
|
29
|
+
masked_token = one_time_pad.bytes.zip( base_token.bytes ).map { |a, b| a ^ b }.pack('C*')
|
30
|
+
return Base64.urlsafe_encode64( one_time_pad + masked_token ) # Encode the result
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Unmask a masked token.
|
35
|
+
#
|
36
|
+
def self.unmask_token( masked_token )
|
37
|
+
decoded = Base64.urlsafe_decode64( masked_token )
|
38
|
+
one_time_pad, masked_token = decoded[0...decoded.length / 2], decoded[decoded.length / 2..]
|
39
|
+
return one_time_pad.bytes.zip( masked_token.bytes ).map { |a, b| (a ^ b).chr }.join
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Compare two tokens.
|
44
|
+
# Use ActiveSupport::SecurityUtils.secure_compare to avoid timing attacks.
|
45
|
+
#
|
46
|
+
def self.compare_tokens( token1, token2 )
|
47
|
+
return ActiveSupport::SecurityUtils.secure_compare( token1, token2 )
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Return a hidden field with the masked csrf token.
|
52
|
+
#
|
53
|
+
def self.get_csrf_token_hidden_field( base_token )
|
54
|
+
form_token = mask_token( base_token )
|
55
|
+
|
56
|
+
return "<input type='hidden' name='#{AUTHENTICITY_TOKEN}' value='#{form_token}' />"
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Validate a masked csrf token that came from a form submit.
|
61
|
+
#
|
62
|
+
def self.valid_csrf_token?( base_token, masked_token )
|
63
|
+
return false unless base_token && masked_token
|
64
|
+
|
65
|
+
unmasked_token = unmask_token( masked_token )
|
66
|
+
|
67
|
+
return compare_tokens( base_token, unmasked_token )
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -11,6 +11,10 @@ module Gloo
|
|
11
11
|
KEYWORD = 'file'.freeze
|
12
12
|
KEYWORD_SHORT = 'dir'.freeze
|
13
13
|
|
14
|
+
FILE_NAME_ERR = 'file and path name expected'.freeze
|
15
|
+
FILE_MISSING_ERR = 'file not found'.freeze
|
16
|
+
|
17
|
+
|
14
18
|
#
|
15
19
|
# The name of the object type.
|
16
20
|
#
|
@@ -33,7 +37,7 @@ module Gloo
|
|
33
37
|
# Get a list of message names that this object receives.
|
34
38
|
#
|
35
39
|
def self.messages
|
36
|
-
basic = %w[read write get_name get_ext get_parent]
|
40
|
+
basic = %w[read write get_name get_ext get_parent get_sha256]
|
37
41
|
checks = %w[exists? is_file? is_dir?]
|
38
42
|
search = %w[find_match]
|
39
43
|
show = %w[show page open]
|
@@ -73,7 +77,7 @@ module Gloo
|
|
73
77
|
# Read the contents of the file into the object.
|
74
78
|
#
|
75
79
|
def msg_read
|
76
|
-
return unless
|
80
|
+
return unless check_file_exists?
|
77
81
|
|
78
82
|
data = File.read( value )
|
79
83
|
if @params&.token_count&.positive?
|
@@ -165,6 +169,44 @@ module Gloo
|
|
165
169
|
end
|
166
170
|
end
|
167
171
|
|
172
|
+
#
|
173
|
+
# Get the SHA256 hash of the file contents.
|
174
|
+
#
|
175
|
+
def msg_get_sha256
|
176
|
+
return unless check_file_exists?
|
177
|
+
|
178
|
+
file_hash = FileHandle.hash_for_file( value )
|
179
|
+
@engine.heap.it.set_to file_hash
|
180
|
+
end
|
181
|
+
|
182
|
+
#
|
183
|
+
# Get the SHA256 hash of the file contents.
|
184
|
+
#
|
185
|
+
def self.hash_for_file( file_path )
|
186
|
+
require 'digest'
|
187
|
+
file_data = File.read( file_path )
|
188
|
+
file_hash = Digest::SHA256.hexdigest( file_data )
|
189
|
+
return file_hash
|
190
|
+
end
|
191
|
+
|
192
|
+
#
|
193
|
+
# Check to see if the file exists.
|
194
|
+
# Show error if not.
|
195
|
+
#
|
196
|
+
def check_file_exists?
|
197
|
+
if value.blank?
|
198
|
+
@engine.log.error FILE_NAME_ERR
|
199
|
+
return false
|
200
|
+
end
|
201
|
+
|
202
|
+
unless File.exist?( value )
|
203
|
+
@engine.log.error FILE_MISSING_ERR
|
204
|
+
return false
|
205
|
+
end
|
206
|
+
|
207
|
+
return true
|
208
|
+
end
|
209
|
+
|
168
210
|
end
|
169
211
|
end
|
170
212
|
end
|
data/lib/gloo/objs/web/uri.rb
CHANGED
@@ -51,7 +51,8 @@ module Gloo
|
|
51
51
|
ELAPSED = 'elapsed'.freeze
|
52
52
|
DB = 'db'.freeze
|
53
53
|
PAGE = 'page'.freeze
|
54
|
-
|
54
|
+
CURRENT_PAGE = 'current_page'.freeze
|
55
|
+
|
55
56
|
# Container with pages in the web app.
|
56
57
|
PAGES = 'pages'.freeze
|
57
58
|
|
@@ -303,7 +304,7 @@ module Gloo
|
|
303
304
|
# Important to do this after the response is sent
|
304
305
|
# to avoid holding on to data that is no longer needed.
|
305
306
|
#
|
306
|
-
def
|
307
|
+
def reset_session_data
|
307
308
|
session_container.children.each do |session_var|
|
308
309
|
session_var.value = ''
|
309
310
|
end
|
@@ -405,7 +406,10 @@ module Gloo
|
|
405
406
|
# Get a list of message names that this object receives.
|
406
407
|
#
|
407
408
|
def self.messages
|
408
|
-
return super + [ 'start', 'stop',
|
409
|
+
return super + [ 'start', 'stop',
|
410
|
+
'list_routes', 'list_assets',
|
411
|
+
'add_session_to_response', 'clear_session_data',
|
412
|
+
'list_asset_img', 'list_asset_css', 'list_asset_js' ]
|
409
413
|
end
|
410
414
|
|
411
415
|
#
|
@@ -434,8 +438,9 @@ module Gloo
|
|
434
438
|
|
435
439
|
#
|
436
440
|
# Helper message to show all routes in the running server.
|
441
|
+
# A Debugging tool.
|
437
442
|
#
|
438
|
-
def
|
443
|
+
def msg_list_routes
|
439
444
|
if @router
|
440
445
|
@router.show_routes
|
441
446
|
else
|
@@ -443,6 +448,70 @@ module Gloo
|
|
443
448
|
end
|
444
449
|
end
|
445
450
|
|
451
|
+
#
|
452
|
+
# Helper message to show all assets in the running server.
|
453
|
+
# A Debugging tool.
|
454
|
+
#
|
455
|
+
def msg_list_assets
|
456
|
+
if @router
|
457
|
+
Gloo::WebSvr::AssetInfo.list_all( @engine )
|
458
|
+
else
|
459
|
+
@engine.err SERVER_NOT_RUNNING
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
#
|
464
|
+
# List all asset images in the running server.
|
465
|
+
# A Debugging tool.
|
466
|
+
#
|
467
|
+
def msg_list_asset_img
|
468
|
+
if @router
|
469
|
+
@asset.list_image_assets
|
470
|
+
else
|
471
|
+
@engine.err SERVER_NOT_RUNNING
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
#
|
476
|
+
# List all asset css in the running server.
|
477
|
+
# A Debugging tool.
|
478
|
+
#
|
479
|
+
def msg_list_asset_css
|
480
|
+
if @router
|
481
|
+
@asset.list_css_assets
|
482
|
+
else
|
483
|
+
@engine.err SERVER_NOT_RUNNING
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
#
|
488
|
+
# List all asset javascript in the running server.
|
489
|
+
# A Debugging tool.
|
490
|
+
#
|
491
|
+
def msg_list_asset_js
|
492
|
+
if @router
|
493
|
+
@asset.list_js_assets
|
494
|
+
else
|
495
|
+
@engine.err SERVER_NOT_RUNNING
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
#
|
500
|
+
# Add the session data to the response.
|
501
|
+
# This will be done for the current (next) request only.
|
502
|
+
#
|
503
|
+
def msg_add_session_to_response
|
504
|
+
@session.add_session_to_response if @session
|
505
|
+
end
|
506
|
+
|
507
|
+
#
|
508
|
+
# Clear out the session data, and remove it from the response.
|
509
|
+
#
|
510
|
+
def msg_clear_session_data
|
511
|
+
reset_session_data
|
512
|
+
@session.clear_session_data if @session
|
513
|
+
end
|
514
|
+
|
446
515
|
|
447
516
|
# ---------------------------------------------------------------------
|
448
517
|
# Start and Stop Events
|
@@ -482,7 +551,7 @@ module Gloo
|
|
482
551
|
@engine.log.info "Stopping web server…"
|
483
552
|
|
484
553
|
# Last chance to clear out session data.
|
485
|
-
|
554
|
+
reset_session_data
|
486
555
|
|
487
556
|
@web_server.stop
|
488
557
|
@web_server = nil
|
@@ -519,13 +588,18 @@ module Gloo
|
|
519
588
|
|
520
589
|
#
|
521
590
|
# Run the on request script if there is one.
|
591
|
+
# Set thee current page object so the app knows
|
592
|
+
# which page is being requested.
|
522
593
|
#
|
523
|
-
def run_on_request
|
594
|
+
def run_on_request current_page
|
595
|
+
for_page = find_child CURRENT_PAGE
|
596
|
+
alias_value = current_page.pn
|
597
|
+
for_page.set_value( alias_value ) if for_page
|
524
598
|
o = find_child ON_REQUEST
|
525
599
|
return unless o
|
526
600
|
o = Gloo::Objs::Alias.resolve_alias( @engine, o )
|
527
601
|
|
528
|
-
Gloo::Exec::Dispatch.message( @engine, 'run', o )
|
602
|
+
Gloo::Exec::Dispatch.message( @engine, 'run', o, CURRENT_PAGE => current_page )
|
529
603
|
end
|
530
604
|
|
531
605
|
#
|
@@ -544,6 +618,10 @@ module Gloo
|
|
544
618
|
# This is done before the on_request event is fired.
|
545
619
|
#
|
546
620
|
def set_request_data( request )
|
621
|
+
# Clear out the redirect if there is one since this is the start of
|
622
|
+
# a new request.
|
623
|
+
@redirect = nil
|
624
|
+
|
547
625
|
data = find_child RESQUEST_DATA
|
548
626
|
return unless data
|
549
627
|
data = Gloo::Objs::Alias.resolve_alias( @engine, data )
|
data/lib/gloo/web_svr/asset.rb
CHANGED
@@ -116,6 +116,38 @@ module Gloo
|
|
116
116
|
return Gloo::WebSvr::Response.new( @engine, code, type, data )
|
117
117
|
end
|
118
118
|
|
119
|
+
#
|
120
|
+
# Check if the given name is an asset.
|
121
|
+
#
|
122
|
+
def is_asset? name
|
123
|
+
return name == ASSET_FOLDER
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
# ---------------------------------------------------------------------
|
128
|
+
# Asset with Fingerprints
|
129
|
+
# ---------------------------------------------------------------------
|
130
|
+
|
131
|
+
#
|
132
|
+
# Register an asset with the web server.
|
133
|
+
# Adds fingerprint to the file names for later access.
|
134
|
+
#
|
135
|
+
# full_path is the FILE from which we build the SHA256 hash
|
136
|
+
# pn is the path and name within the assets directory
|
137
|
+
# name is the simple file name (icon.png)
|
138
|
+
#
|
139
|
+
def register_asset name, pn, full_path
|
140
|
+
asset_pn = "/asset/#{pn}"
|
141
|
+
return AssetInfo.new( @engine, full_path, name, asset_pn ).register
|
142
|
+
end
|
143
|
+
|
144
|
+
#
|
145
|
+
# Get the published name for the given asset name.
|
146
|
+
#
|
147
|
+
def published_name asset_name
|
148
|
+
return AssetInfo.find_published_name_for( asset_name )
|
149
|
+
end
|
150
|
+
|
119
151
|
|
120
152
|
# ---------------------------------------------------------------------
|
121
153
|
# Dynamic Add Assets
|
@@ -170,7 +202,8 @@ module Gloo
|
|
170
202
|
|
171
203
|
add_files_in_folder( full_path, child, pn )
|
172
204
|
else
|
173
|
-
|
205
|
+
info = register_asset( name, pn, full_path )
|
206
|
+
add_file_obj( container, name, pn, info )
|
174
207
|
end
|
175
208
|
end
|
176
209
|
end
|
@@ -227,7 +260,7 @@ module Gloo
|
|
227
260
|
#
|
228
261
|
# Add a file object (page route) to the given container.
|
229
262
|
#
|
230
|
-
def add_file_obj( can, name, pn )
|
263
|
+
def add_file_obj( can, name, pn, info )
|
231
264
|
name = name.gsub( '.', '_' )
|
232
265
|
@log.debug "Adding route for file: #{name}"
|
233
266
|
|
@@ -236,6 +269,66 @@ module Gloo
|
|
236
269
|
return if child
|
237
270
|
|
238
271
|
@factory.create_file( name, pn, can )
|
272
|
+
# @factory.create_file( info.published_name, pn, can )
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
# ---------------------------------------------------------------------
|
277
|
+
# List Asset Helpers
|
278
|
+
# ---------------------------------------------------------------------
|
279
|
+
|
280
|
+
#
|
281
|
+
# List all image assets.
|
282
|
+
# This looks in the image container and lists the images found earlier.
|
283
|
+
# A Debugging tool.
|
284
|
+
#
|
285
|
+
def list_image_assets
|
286
|
+
data = []
|
287
|
+
@images.children.each do |o|
|
288
|
+
data << [ o.name, o.pn, o.value ]
|
289
|
+
end
|
290
|
+
headers = [ "Name", "PN", "Value" ]
|
291
|
+
|
292
|
+
puts Gloo::App::Platform::RETURN
|
293
|
+
title = "Image Assets with Routes"
|
294
|
+
@engine.platform.table.show headers, data, title
|
295
|
+
puts Gloo::App::Platform::RETURN
|
296
|
+
end
|
297
|
+
|
298
|
+
#
|
299
|
+
# List all js assets.
|
300
|
+
# This looks in the js container and lists the js files found earlier.
|
301
|
+
# A Debugging tool.
|
302
|
+
#
|
303
|
+
def list_js_assets
|
304
|
+
data = []
|
305
|
+
@javascript.children.each do |o|
|
306
|
+
data << [ o.name, o.pn, o.value ]
|
307
|
+
end
|
308
|
+
headers = [ "Name", "PN", "Value" ]
|
309
|
+
|
310
|
+
puts Gloo::App::Platform::RETURN
|
311
|
+
title = "JavaScript Assets with Routes"
|
312
|
+
@engine.platform.table.show headers, data, title
|
313
|
+
puts Gloo::App::Platform::RETURN
|
314
|
+
end
|
315
|
+
|
316
|
+
#
|
317
|
+
# List all css assets.
|
318
|
+
# This looks in the css container and lists the css files found earlier.
|
319
|
+
# A Debugging tool.
|
320
|
+
#
|
321
|
+
def list_css_assets
|
322
|
+
data = []
|
323
|
+
@stylesheets.children.each do |o|
|
324
|
+
data << [ o.name, o.pn, o.value ]
|
325
|
+
end
|
326
|
+
headers = [ "Name", "PN", "Value" ]
|
327
|
+
|
328
|
+
puts Gloo::App::Platform::RETURN
|
329
|
+
title = "Stylesheet Assets with Routes"
|
330
|
+
@engine.platform.table.show headers, data, title
|
331
|
+
puts Gloo::App::Platform::RETURN
|
239
332
|
end
|
240
333
|
|
241
334
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2025 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# Information about a single asset.
|
5
|
+
#
|
6
|
+
# Full Path is the full path to the file in the file system.
|
7
|
+
# Name is the name of the file with extension.
|
8
|
+
# PN is the path within assets and the name.
|
9
|
+
# ie: /asset/stylesheet/stylesheet.css
|
10
|
+
# Hash is the SHA256 hash of the file.
|
11
|
+
# Published Name is the name of the file that is published
|
12
|
+
# to the web server, and includes the hash.
|
13
|
+
#
|
14
|
+
|
15
|
+
module Gloo
|
16
|
+
module WebSvr
|
17
|
+
class AssetInfo
|
18
|
+
|
19
|
+
# Class Variables
|
20
|
+
@@index_by_published = {}
|
21
|
+
@@index_by_pn = {}
|
22
|
+
|
23
|
+
attr_reader :name, :pn, :published_name, :published_pn, :hash
|
24
|
+
|
25
|
+
|
26
|
+
# ---------------------------------------------------------------------
|
27
|
+
# Initialization
|
28
|
+
# ---------------------------------------------------------------------
|
29
|
+
|
30
|
+
#
|
31
|
+
# Set up an asset information object.
|
32
|
+
#
|
33
|
+
def initialize( engine, full_path, name, pn )
|
34
|
+
@engine = engine
|
35
|
+
@log = @engine.log
|
36
|
+
|
37
|
+
@full_path = full_path
|
38
|
+
@name = name
|
39
|
+
@pn = pn
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
# ---------------------------------------------------------------------
|
44
|
+
# Functions
|
45
|
+
# ---------------------------------------------------------------------
|
46
|
+
|
47
|
+
#
|
48
|
+
# Register the asset with indexes, inflating all needed data elements.
|
49
|
+
#
|
50
|
+
def register
|
51
|
+
@log.debug "*** REGISTERING ASSET: #{@name}"
|
52
|
+
@log.debug "*** #{@full_path} "
|
53
|
+
@log.debug "*** #PN: #{@pn} name: #{@name}"
|
54
|
+
|
55
|
+
@hash = Gloo::Objs::FileHandle.hash_for_file( @full_path )
|
56
|
+
|
57
|
+
# Build published name
|
58
|
+
ext = File.extname( @pn ) # Gets just the extension
|
59
|
+
n = @name[ 0..-ext.length - 1 ]
|
60
|
+
pn = @pn[ 0..-ext.length - 1 ]
|
61
|
+
|
62
|
+
@published_name = "#{n}-#{@hash}#{ext}"
|
63
|
+
@published_pn = "#{pn}-#{@hash}#{ext}"
|
64
|
+
|
65
|
+
@log.debug "*** Published Name: #{@published_name}"
|
66
|
+
@log.debug "*** Published Path: #{@published_pn}"
|
67
|
+
|
68
|
+
# Add to indexes
|
69
|
+
AssetInfo.index self
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Index the the given asset info record.
|
74
|
+
#
|
75
|
+
def self.index info
|
76
|
+
@@index_by_pn[ info.pn ] = info
|
77
|
+
@@index_by_published[ info.published_pn ] = info
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Find the asset info for the given published name.
|
82
|
+
#
|
83
|
+
def self.find_published_name_for pn
|
84
|
+
return @@index_by_pn[ pn ].published_pn
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Find the asset info for the given published name.
|
89
|
+
#
|
90
|
+
def self.find_info_for pn
|
91
|
+
return @@index_by_published[ pn ]
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# List All assets.
|
96
|
+
#
|
97
|
+
def self.list_all engine
|
98
|
+
data = []
|
99
|
+
@@index_by_pn.each do |pn, info|
|
100
|
+
data << [ info.name, info.pn, info.published_pn ]
|
101
|
+
end
|
102
|
+
headers = [ "Name", "Asset Path", "Published" ]
|
103
|
+
|
104
|
+
puts Gloo::App::Platform::RETURN
|
105
|
+
title = "Assets in Running Web App"
|
106
|
+
engine.platform.table.show headers, data, title
|
107
|
+
puts Gloo::App::Platform::RETURN
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -29,6 +29,58 @@ module Gloo
|
|
29
29
|
end
|
30
30
|
|
31
31
|
|
32
|
+
# ---------------------------------------------------------------------
|
33
|
+
# Tag Helpers
|
34
|
+
# ---------------------------------------------------------------------
|
35
|
+
|
36
|
+
#
|
37
|
+
# Render a favicon tag.
|
38
|
+
# By default the name is 'favicon.ico' and does not need to be provided
|
39
|
+
# if that is the correct file name.
|
40
|
+
#
|
41
|
+
def favicon_tag( name = 'favicon.ico' )
|
42
|
+
icon_path = "/#{Asset::ASSET_FOLDER}/#{Asset::IMAGE_FOLDER}/#{name}"
|
43
|
+
published_name = @engine.running_app.obj.asset.published_name( icon_path )
|
44
|
+
return "<link rel='shortcut icon' type='image/x-icon' href='#{published_name}' />"
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Render an image tag for the given image name.
|
49
|
+
# Include optional proterties as part of the tag.
|
50
|
+
#
|
51
|
+
def image_tag( img_name, properties = '' )
|
52
|
+
image_path = "/#{Asset::ASSET_FOLDER}/#{Asset::IMAGE_FOLDER}/#{img_name}"
|
53
|
+
published_name = @engine.running_app.obj.asset.published_name( image_path )
|
54
|
+
return "<image src='#{published_name}' #{properties} />"
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Render a script tag for the given script name.
|
59
|
+
#
|
60
|
+
def js_tag( name )
|
61
|
+
js_path = "/#{Asset::ASSET_FOLDER}/#{Asset::JAVASCRIPT_FOLDER}/#{name}"
|
62
|
+
published_name = @engine.running_app.obj.asset.published_name( js_path )
|
63
|
+
return "<script src='#{published_name}'></script>"
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Render a stylesheet tag for the given stylesheet name.
|
68
|
+
#
|
69
|
+
def css_tag( name )
|
70
|
+
css_path = "/#{Asset::ASSET_FOLDER}/#{Asset::STYLESHEET_FOLDER}/#{name}"
|
71
|
+
published_name = @engine.running_app.obj.asset.published_name( css_path )
|
72
|
+
return "<link rel='stylesheet' media='all' href='#{published_name}' />"
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Embed a hidden field with the autenticity token.
|
77
|
+
#
|
78
|
+
def autenticity_token_tag
|
79
|
+
session_id = @engine.running_app.obj&.session&.get_session_id
|
80
|
+
return Gloo::Objs::CsrfToken.get_csrf_token_hidden_field( session_id )
|
81
|
+
end
|
82
|
+
|
83
|
+
|
32
84
|
# ---------------------------------------------------------------------
|
33
85
|
# Obj Helper Functions
|
34
86
|
# ---------------------------------------------------------------------
|
data/lib/gloo/web_svr/handler.rb
CHANGED
data/lib/gloo/web_svr/request.rb
CHANGED
@@ -59,9 +59,15 @@ module Gloo
|
|
59
59
|
|
60
60
|
# Run the on_request script if there is one.
|
61
61
|
@handler.server_obj.set_request_data self
|
62
|
-
@handler.server_obj.run_on_request
|
63
62
|
|
64
|
-
|
63
|
+
# Check authenticity token if it's given.
|
64
|
+
if @request_params.check_authenticity_token( @engine )
|
65
|
+
result, page_obj = @handler.handle self
|
66
|
+
else
|
67
|
+
# Render the error page.
|
68
|
+
result = @handler.server_error_result
|
69
|
+
end
|
70
|
+
|
65
71
|
finish_timer
|
66
72
|
|
67
73
|
# Run the on_response script if there is one.
|
@@ -56,6 +56,29 @@ module Gloo
|
|
56
56
|
end
|
57
57
|
|
58
58
|
|
59
|
+
# ---------------------------------------------------------------------
|
60
|
+
# Authenticity Token checking
|
61
|
+
# ---------------------------------------------------------------------
|
62
|
+
|
63
|
+
#
|
64
|
+
# Check the authenticity token if it is present.
|
65
|
+
# Returns true if it is present and valid, and
|
66
|
+
# also if it is not present.
|
67
|
+
# Returns false if it is present but not valid.
|
68
|
+
#
|
69
|
+
def check_authenticity_token engine
|
70
|
+
auth_token = @query_params[ Gloo::Objs::CsrfToken::AUTHENTICITY_TOKEN ]
|
71
|
+
if auth_token
|
72
|
+
session_id = engine.running_app.obj&.session&.get_session_id
|
73
|
+
return false unless session_id
|
74
|
+
|
75
|
+
return Gloo::Objs::CsrfToken.valid_csrf_token?( session_id, auth_token )
|
76
|
+
end
|
77
|
+
|
78
|
+
return true
|
79
|
+
end
|
80
|
+
|
81
|
+
|
59
82
|
# ---------------------------------------------------------------------
|
60
83
|
# Helper functions
|
61
84
|
# ---------------------------------------------------------------------
|
@@ -122,9 +122,12 @@ module Gloo
|
|
122
122
|
headers[ 'Location' ] = @location
|
123
123
|
end
|
124
124
|
|
125
|
-
session = @engine&.running_app&.obj&.session
|
125
|
+
session = @engine&.running_app&.obj&.session
|
126
126
|
headers = session.add_session_for_response( headers ) if session
|
127
127
|
|
128
|
+
# Clear out session data after the response is prepared.
|
129
|
+
@engine&.running_app&.obj&.reset_session_data
|
130
|
+
|
128
131
|
return headers
|
129
132
|
end
|
130
133
|
|
@@ -201,6 +201,13 @@ module Gloo
|
|
201
201
|
# Create a list of path segments.
|
202
202
|
#
|
203
203
|
def detect_segments path
|
204
|
+
# For Assets, substitute the published name with fingerprint
|
205
|
+
# for the simple asset name (if it is found).
|
206
|
+
asset_info = Gloo::WebSvr::AssetInfo.find_info_for( path )
|
207
|
+
unless asset_info.blank?
|
208
|
+
path = asset_info.pn
|
209
|
+
end
|
210
|
+
|
204
211
|
# Split the path into segments.
|
205
212
|
@route_segments = path.split SEGMENT_DIVIDER
|
206
213
|
|
@@ -10,7 +10,6 @@ module Gloo
|
|
10
10
|
class ShowRoutes
|
11
11
|
|
12
12
|
SEGMENT_DIVIDER = '/'.freeze
|
13
|
-
RETURN = "\n".freeze
|
14
13
|
|
15
14
|
|
16
15
|
# ---------------------------------------------------------------------
|
@@ -76,10 +75,10 @@ module Gloo
|
|
76
75
|
# Show the Routes title.
|
77
76
|
#
|
78
77
|
def show_table
|
79
|
-
puts RETURN
|
78
|
+
puts Gloo::App::Platform::RETURN
|
80
79
|
title = "Routes in Running Web App"
|
81
80
|
@engine.platform.table.show headers, @found_routes, title
|
82
|
-
puts RETURN
|
81
|
+
puts Gloo::App::Platform::RETURN
|
83
82
|
end
|
84
83
|
|
85
84
|
#
|
data/lib/gloo/web_svr/session.rb
CHANGED
@@ -15,6 +15,7 @@ module Gloo
|
|
15
15
|
class Session
|
16
16
|
|
17
17
|
SESSION_CONTAINER = 'session'.freeze
|
18
|
+
SESSION_ID_NAME = 'session_id'.freeze
|
18
19
|
|
19
20
|
|
20
21
|
# ---------------------------------------------------------------------
|
@@ -29,6 +30,8 @@ module Gloo
|
|
29
30
|
@log = @engine.log
|
30
31
|
|
31
32
|
@server_obj = server_obj
|
33
|
+
@include_in_response = false
|
34
|
+
@clearing_session = false
|
32
35
|
end
|
33
36
|
|
34
37
|
|
@@ -52,8 +55,12 @@ module Gloo
|
|
52
55
|
data = decode_decrypt( data )
|
53
56
|
return unless data
|
54
57
|
|
58
|
+
@session_id = data[ SESSION_ID_NAME ]
|
59
|
+
|
55
60
|
data.each do |key, value|
|
56
|
-
|
61
|
+
unless key == SESSION_ID_NAME
|
62
|
+
@server_obj.set_session_var( key, value )
|
63
|
+
end
|
57
64
|
end
|
58
65
|
end
|
59
66
|
end
|
@@ -64,18 +71,62 @@ module Gloo
|
|
64
71
|
|
65
72
|
|
66
73
|
# ---------------------------------------------------------------------
|
67
|
-
#
|
74
|
+
# Set Session Data for Response
|
68
75
|
# ---------------------------------------------------------------------
|
69
76
|
|
77
|
+
#
|
78
|
+
# Temporarily set the flag to add the session data to the response.
|
79
|
+
# Once this is done, the flag will be cleared and it will not
|
80
|
+
# be added to the next request unless specifically set.
|
81
|
+
#
|
82
|
+
def add_session_to_response
|
83
|
+
@include_in_response = true
|
84
|
+
end
|
85
|
+
|
86
|
+
def init_session_id
|
87
|
+
@session_id = Gloo::Objs::CsrfToken.generate_csrf_token
|
88
|
+
return @session_id
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Initialize the session id and add it to the data.
|
93
|
+
# Use the current session ID if it is there.
|
94
|
+
#
|
95
|
+
def get_session_id
|
96
|
+
if @clearing_session
|
97
|
+
@clearing_session = false
|
98
|
+
return nil
|
99
|
+
end
|
100
|
+
|
101
|
+
init_session_id if @session_id.blank?
|
102
|
+
|
103
|
+
return @session_id
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Clear out the session Id.
|
108
|
+
# Set the flag to add the session data to the response.
|
109
|
+
#
|
110
|
+
def clear_session_data
|
111
|
+
@session_id = nil
|
112
|
+
@clearing_session = true
|
113
|
+
add_session_to_response
|
114
|
+
end
|
115
|
+
|
70
116
|
#
|
71
117
|
# If there is session data, encrypt and add it to the response.
|
72
118
|
# Once done, clear out the session data.
|
73
119
|
#
|
74
120
|
def add_session_for_response( headers )
|
75
121
|
# Are we using sessions?
|
76
|
-
if @server_obj.use_session?
|
122
|
+
if @server_obj.use_session? && @include_in_response
|
123
|
+
# Reset the flag because we are adding to the session data now
|
124
|
+
@include_in_response = false
|
125
|
+
|
77
126
|
# Build and add encrypted session data
|
78
127
|
data = @server_obj.get_session_data
|
128
|
+
data[ SESSION_ID_NAME ] = get_session_id
|
129
|
+
|
79
130
|
unless data.empty?
|
80
131
|
data = encrypt_encode( data )
|
81
132
|
session_hash = {
|
@@ -90,9 +141,6 @@ module Gloo
|
|
90
141
|
|
91
142
|
Rack::Utils.set_cookie_header!( headers, session_name, session_hash )
|
92
143
|
end
|
93
|
-
|
94
|
-
# Clear out session data
|
95
|
-
@server_obj.clear_session_data
|
96
144
|
end
|
97
145
|
|
98
146
|
return headers
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gloo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Crane
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -462,6 +462,7 @@ files:
|
|
462
462
|
- lib/gloo/objs/ror/erb.rb
|
463
463
|
- lib/gloo/objs/ror/eval.rb
|
464
464
|
- lib/gloo/objs/security/cipher.rb
|
465
|
+
- lib/gloo/objs/security/csrf_token.rb
|
465
466
|
- lib/gloo/objs/security/password.rb
|
466
467
|
- lib/gloo/objs/system/file_handle.rb
|
467
468
|
- lib/gloo/objs/system/ssh_exec.rb
|
@@ -514,6 +515,7 @@ files:
|
|
514
515
|
- lib/gloo/verbs/version.rb
|
515
516
|
- lib/gloo/verbs/wait.rb
|
516
517
|
- lib/gloo/web_svr/asset.rb
|
518
|
+
- lib/gloo/web_svr/asset_info.rb
|
517
519
|
- lib/gloo/web_svr/config.rb
|
518
520
|
- lib/gloo/web_svr/embedded_renderer.rb
|
519
521
|
- lib/gloo/web_svr/handler.rb
|