gloo 3.6.2 → 3.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|