gloo 3.7.0 → 3.9.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 +15 -0
- data/lib/gloo/app/log.rb +1 -1
- data/lib/gloo/core/op.rb +27 -7
- data/lib/gloo/expr/op_div.rb +2 -0
- data/lib/gloo/expr/op_eq.rb +29 -0
- data/lib/gloo/expr/op_gt.rb +26 -0
- data/lib/gloo/expr/op_gteq.rb +26 -0
- data/lib/gloo/expr/op_ineq.rb +28 -0
- data/lib/gloo/expr/op_lt.rb +26 -0
- data/lib/gloo/expr/op_lteq.rb +26 -0
- data/lib/gloo/expr/op_minus.rb +2 -0
- data/lib/gloo/expr/op_mult.rb +2 -0
- data/lib/gloo/expr/op_plus.rb +2 -0
- data/lib/gloo/objs/basic/string.rb +87 -1
- data/lib/gloo/objs/ctrl/each_child.rb +87 -0
- data/lib/gloo/objs/security/csrf_token.rb +72 -0
- data/lib/gloo/objs/web_svr/page.rb +2 -0
- data/lib/gloo/objs/web_svr/svr.rb +32 -5
- data/lib/gloo/verbs/load.rb +1 -1
- data/lib/gloo/verbs/save.rb +1 -1
- data/lib/gloo/verbs/show.rb +1 -1
- data/lib/gloo/web_svr/embedded_renderer.rb +8 -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/session.rb +54 -6
- data/lib/gloo/web_svr/table_renderer.rb +3 -3
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afc950a2a2470041f3a3d990480cf26bee1005e6f4e00bcc95feb4e38d8de394
|
4
|
+
data.tar.gz: fe2cf5549734e2779ed1ed1f90bc5974fcae7c0b8245b22626a9828d2f54c54e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7eed261a94581ca0a1e7f5c9a61657bd8e39f1455d55f4754bc4530641fe33ef359d7055f191dd204c505b31e501291803f5ef5822672640a280845c5c27b0d1
|
7
|
+
data.tar.gz: 643bd6cc65823bf8d1a8d1666e0b5b51abf5c44d0a8f2b25b51c901a1f18c3efda08264c5e686fe34efb0063a7e9e56b7040c50befa353e17369f0c04f32b186
|
data/lib/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.
|
1
|
+
3.9.0
|
data/lib/VERSION_NOTES
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
3.9.0 - 2025.02.21
|
2
|
+
- Fixes alias in page parameters
|
3
|
+
- Adds comparison operators
|
4
|
+
- Renames some verb shortcuts for compatibility
|
5
|
+
- Adds Group-By option in for each child loop
|
6
|
+
- Adds starts_with?, ends_with?, contains?, and format_for_html messages to string
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
3.8.0 - 2025.01.23
|
11
|
+
- Fixes issue with sessions
|
12
|
+
- Adds authenticity token tag and supporting session id and validation
|
13
|
+
|
14
|
+
|
15
|
+
|
1
16
|
3.7.0 - 2025.01.09
|
2
17
|
- Adds File message to get SHA256 hash
|
3
18
|
- Asset Fingerprinting
|
data/lib/gloo/app/log.rb
CHANGED
data/lib/gloo/core/op.rb
CHANGED
@@ -13,19 +13,39 @@ module Gloo
|
|
13
13
|
# Is the token an operator?
|
14
14
|
#
|
15
15
|
def self.op?( token )
|
16
|
-
return [
|
16
|
+
return [
|
17
|
+
Gloo::Expr::OpPlus::SYMBOL,
|
18
|
+
Gloo::Expr::OpMinus::SYMBOL,
|
19
|
+
Gloo::Expr::OpMult::SYMBOL,
|
20
|
+
Gloo::Expr::OpDiv::SYMBOL,
|
21
|
+
Gloo::Expr::OpEq::SYMBOL,
|
22
|
+
Gloo::Expr::OpEq::ALT_SYMBOL,
|
23
|
+
Gloo::Expr::OpIneq::SYMBOL,
|
24
|
+
Gloo::Expr::OpGt::SYMBOL,
|
25
|
+
Gloo::Expr::OpLt::SYMBOL,
|
26
|
+
Gloo::Expr::OpGteq::SYMBOL,
|
27
|
+
Gloo::Expr::OpLteq::SYMBOL
|
28
|
+
].include?( token.strip )
|
17
29
|
end
|
18
30
|
|
19
31
|
#
|
20
32
|
# Create the operator for the given token.
|
21
33
|
#
|
22
34
|
def self.create_op( token )
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
35
|
+
case token
|
36
|
+
when Gloo::Expr::OpPlus::SYMBOL then Gloo::Expr::OpPlus.new
|
37
|
+
when Gloo::Expr::OpMinus::SYMBOL then Gloo::Expr::OpMinus.new
|
38
|
+
when Gloo::Expr::OpMult::SYMBOL then Gloo::Expr::OpMult.new
|
39
|
+
when Gloo::Expr::OpDiv::SYMBOL then Gloo::Expr::OpDiv.new
|
40
|
+
when Gloo::Expr::OpEq::SYMBOL then return Gloo::Expr::OpEq.new
|
41
|
+
when Gloo::Expr::OpEq::ALT_SYMBOL then return Gloo::Expr::OpEq.new
|
42
|
+
when Gloo::Expr::OpIneq::SYMBOL then return Gloo::Expr::OpIneq.new
|
43
|
+
when Gloo::Expr::OpGt::SYMBOL then return Gloo::Expr::OpGt.new
|
44
|
+
when Gloo::Expr::OpLt::SYMBOL then return Gloo::Expr::OpLt.new
|
45
|
+
when Gloo::Expr::OpGteq::SYMBOL then return Gloo::Expr::OpGteq.new
|
46
|
+
when Gloo::Expr::OpLteq::SYMBOL then return Gloo::Expr::OpLteq.new
|
47
|
+
else return default_op
|
48
|
+
end
|
29
49
|
end
|
30
50
|
|
31
51
|
#
|
data/lib/gloo/expr/op_div.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2025 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# Equality operator.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Gloo
|
8
|
+
module Expr
|
9
|
+
class OpEq < Gloo::Core::Op
|
10
|
+
|
11
|
+
SYMBOL = '='.freeze
|
12
|
+
ALT_SYMBOL = '=='.freeze
|
13
|
+
|
14
|
+
#
|
15
|
+
# Perform the operation and return the result.
|
16
|
+
#
|
17
|
+
def perform( left, right )
|
18
|
+
return left == right.to_s if left.is_a? String
|
19
|
+
|
20
|
+
return left == right.to_i if left.is_a? Integer
|
21
|
+
|
22
|
+
return left == right.to_f if left.is_a? Numeric
|
23
|
+
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2025 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# Greater than operator.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Gloo
|
8
|
+
module Expr
|
9
|
+
class OpGt < Gloo::Core::Op
|
10
|
+
|
11
|
+
SYMBOL = '>'.freeze
|
12
|
+
|
13
|
+
#
|
14
|
+
# Perform the operation and return the result.
|
15
|
+
#
|
16
|
+
def perform( left, right )
|
17
|
+
return left > right.to_i if left.is_a? Integer
|
18
|
+
|
19
|
+
return left > right.to_f if left.is_a? Numeric
|
20
|
+
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2025 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# Greater than or equal operator.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Gloo
|
8
|
+
module Expr
|
9
|
+
class OpGteq < Gloo::Core::Op
|
10
|
+
|
11
|
+
SYMBOL = '>='.freeze
|
12
|
+
|
13
|
+
#
|
14
|
+
# Perform the operation and return the result.
|
15
|
+
#
|
16
|
+
def perform( left, right )
|
17
|
+
return left >= right.to_i if left.is_a? Integer
|
18
|
+
|
19
|
+
return left >= right.to_f if left.is_a? Numeric
|
20
|
+
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2025 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# Inequality operator.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Gloo
|
8
|
+
module Expr
|
9
|
+
class OpIneq < Gloo::Core::Op
|
10
|
+
|
11
|
+
SYMBOL = '!='.freeze
|
12
|
+
|
13
|
+
#
|
14
|
+
# Perform the operation and return the result.
|
15
|
+
#
|
16
|
+
def perform( left, right )
|
17
|
+
return left != right.to_s if left.is_a? String
|
18
|
+
|
19
|
+
return left != right.to_i if left.is_a? Integer
|
20
|
+
|
21
|
+
return left != right.to_f if left.is_a? Numeric
|
22
|
+
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2025 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# Less than operator.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Gloo
|
8
|
+
module Expr
|
9
|
+
class OpLt < Gloo::Core::Op
|
10
|
+
|
11
|
+
SYMBOL = '<'.freeze
|
12
|
+
|
13
|
+
#
|
14
|
+
# Perform the operation and return the result.
|
15
|
+
#
|
16
|
+
def perform( left, right )
|
17
|
+
return left < right.to_i if left.is_a? Integer
|
18
|
+
|
19
|
+
return left < right.to_f if left.is_a? Numeric
|
20
|
+
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Author:: Eric Crane (mailto:eric.crane@mac.com)
|
2
|
+
# Copyright:: Copyright (c) 2025 Eric Crane. All rights reserved.
|
3
|
+
#
|
4
|
+
# Less than or equal operator.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Gloo
|
8
|
+
module Expr
|
9
|
+
class OpLteq < Gloo::Core::Op
|
10
|
+
|
11
|
+
SYMBOL = '<='.freeze
|
12
|
+
|
13
|
+
#
|
14
|
+
# Perform the operation and return the result.
|
15
|
+
#
|
16
|
+
def perform( left, right )
|
17
|
+
return left <= right.to_i if left.is_a? Integer
|
18
|
+
|
19
|
+
return left <= right.to_f if left.is_a? Numeric
|
20
|
+
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/gloo/expr/op_minus.rb
CHANGED
data/lib/gloo/expr/op_mult.rb
CHANGED
data/lib/gloo/expr/op_plus.rb
CHANGED
@@ -12,6 +12,7 @@ module Gloo
|
|
12
12
|
|
13
13
|
KEYWORD = 'string'.freeze
|
14
14
|
KEYWORD_SHORT = 'str'.freeze
|
15
|
+
MISSING_PARAM_MSG = 'Missing parameter!'.freeze
|
15
16
|
|
16
17
|
#
|
17
18
|
# The name of the object type.
|
@@ -42,10 +43,95 @@ module Gloo
|
|
42
43
|
# Get a list of message names that this object receives.
|
43
44
|
#
|
44
45
|
def self.messages
|
45
|
-
return super + %w[up down size
|
46
|
+
return super + %w[up down size starts_with? ends_with? contains?
|
47
|
+
format_for_html encode64 decode64 escape unescape
|
46
48
|
gen_alphanumeric gen_uuid gen_hex gen_base64]
|
47
49
|
end
|
48
50
|
|
51
|
+
#
|
52
|
+
# Convert whitespace to HTML friendly spaces.
|
53
|
+
#
|
54
|
+
def msg_format_for_html
|
55
|
+
text = self.value
|
56
|
+
out = ""
|
57
|
+
return out unless text
|
58
|
+
|
59
|
+
# indentation
|
60
|
+
text.each_line do |line|
|
61
|
+
i = 0
|
62
|
+
while line[i] == ' '
|
63
|
+
i += 1
|
64
|
+
out << " "
|
65
|
+
end
|
66
|
+
|
67
|
+
i = 0
|
68
|
+
while line[i] == "\t"
|
69
|
+
i += 1
|
70
|
+
out << " "
|
71
|
+
end
|
72
|
+
out << line
|
73
|
+
end
|
74
|
+
|
75
|
+
self.value = out.gsub( "\n", "<br/>" )
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Does the string start with the given string?
|
80
|
+
#
|
81
|
+
def msg_starts_with?
|
82
|
+
if @params&.token_count&.positive?
|
83
|
+
expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
|
84
|
+
data = expr.evaluate
|
85
|
+
|
86
|
+
result = self.value.start_with?( data )
|
87
|
+
@engine.heap.it.set_to result
|
88
|
+
return result
|
89
|
+
else
|
90
|
+
# Error
|
91
|
+
@engine.log.error MISSING_PARAM_MSG
|
92
|
+
@engine.heap.it.set_to false
|
93
|
+
return false
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Does the string end with the given string?
|
99
|
+
#
|
100
|
+
def msg_ends_with?
|
101
|
+
if @params&.token_count&.positive?
|
102
|
+
expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
|
103
|
+
data = expr.evaluate
|
104
|
+
|
105
|
+
result = value.end_with?( data )
|
106
|
+
@engine.heap.it.set_to result
|
107
|
+
return result
|
108
|
+
else
|
109
|
+
# Error
|
110
|
+
@engine.log.error MISSING_PARAM_MSG
|
111
|
+
@engine.heap.it.set_to false
|
112
|
+
return false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# Does the string contain the given string?
|
118
|
+
#
|
119
|
+
def msg_contains?
|
120
|
+
if @params&.token_count&.positive?
|
121
|
+
expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
|
122
|
+
data = expr.evaluate
|
123
|
+
|
124
|
+
result = value.include?( data )
|
125
|
+
@engine.heap.it.set_to result
|
126
|
+
return result
|
127
|
+
else
|
128
|
+
# Error
|
129
|
+
@engine.log.error MISSING_PARAM_MSG
|
130
|
+
@engine.heap.it.set_to false
|
131
|
+
return false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
49
135
|
#
|
50
136
|
# Get the size of the string.
|
51
137
|
#
|
@@ -10,6 +10,11 @@ module Gloo
|
|
10
10
|
|
11
11
|
CHILD = 'child'.freeze
|
12
12
|
IN = 'IN'.freeze
|
13
|
+
|
14
|
+
GROUP_BY = 'group_by'.freeze
|
15
|
+
ON_GROUP_START = 'on_group_start'.freeze
|
16
|
+
ON_GROUP_END = 'on_group_end'.freeze
|
17
|
+
|
13
18
|
|
14
19
|
# ---------------------------------------------------------------------
|
15
20
|
# Create Iterator
|
@@ -34,6 +39,61 @@ module Gloo
|
|
34
39
|
return false
|
35
40
|
end
|
36
41
|
|
42
|
+
|
43
|
+
# ---------------------------------------------------------------------
|
44
|
+
# Group By
|
45
|
+
# ---------------------------------------------------------------------
|
46
|
+
|
47
|
+
#
|
48
|
+
# If the iterator has a group by,
|
49
|
+
# then we need to group by that value.
|
50
|
+
# Otherwise, we just loop for each child.
|
51
|
+
#
|
52
|
+
def has_group_by?
|
53
|
+
child = @iterator_obj.find_child GROUP_BY
|
54
|
+
return false unless child
|
55
|
+
|
56
|
+
return true
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Get the child that is the group by.
|
61
|
+
# Return nil if there is no group by.
|
62
|
+
#
|
63
|
+
def group_by_value obj_can
|
64
|
+
return nil unless obj_can
|
65
|
+
|
66
|
+
child = @iterator_obj.find_child GROUP_BY
|
67
|
+
return nil unless child
|
68
|
+
|
69
|
+
group_by_child_name = child.value
|
70
|
+
|
71
|
+
obj = obj_can.find_child( group_by_child_name )
|
72
|
+
return nil unless obj
|
73
|
+
|
74
|
+
return obj.value
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Run the on group start script.
|
79
|
+
#
|
80
|
+
def run_on_group_start
|
81
|
+
o = @iterator_obj.find_child ON_GROUP_START
|
82
|
+
return unless o
|
83
|
+
|
84
|
+
Gloo::Exec::Dispatch.message( @engine, 'run', o )
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Run the on group end script.
|
89
|
+
#
|
90
|
+
def run_on_group_end
|
91
|
+
o = @iterator_obj.find_child ON_GROUP_END
|
92
|
+
return unless o
|
93
|
+
|
94
|
+
Gloo::Exec::Dispatch.message( @engine, 'run', o )
|
95
|
+
end
|
96
|
+
|
37
97
|
|
38
98
|
# ---------------------------------------------------------------------
|
39
99
|
# Iterate
|
@@ -46,11 +106,38 @@ module Gloo
|
|
46
106
|
o = @iterator_obj.find_child IN
|
47
107
|
return unless o
|
48
108
|
|
109
|
+
# Set up for optional groups.
|
110
|
+
group_mode = false
|
111
|
+
if has_group_by?
|
112
|
+
group_mode = true
|
113
|
+
last_group = nil
|
114
|
+
first_time = true
|
115
|
+
end
|
116
|
+
|
49
117
|
o = Gloo::Objs::Alias.resolve_alias( @engine, o )
|
50
118
|
o.children.each do |child|
|
119
|
+
if group_mode
|
120
|
+
group_value = group_by_value( child )
|
121
|
+
# puts "last group = #{last_group}, group_value = #{group_value}"
|
122
|
+
if last_group != group_value
|
123
|
+
last_group = group_value
|
124
|
+
# puts "New group: #{group_value}"
|
125
|
+
if first_time
|
126
|
+
first_time = false
|
127
|
+
else
|
128
|
+
run_on_group_end
|
129
|
+
end
|
130
|
+
run_on_group_start
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
51
134
|
set_child child
|
52
135
|
@iterator_obj.run_do
|
53
136
|
end
|
137
|
+
|
138
|
+
if group_mode && !first_time
|
139
|
+
run_on_group_end
|
140
|
+
end
|
54
141
|
end
|
55
142
|
|
56
143
|
#
|
@@ -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
|
@@ -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
|
@@ -407,6 +408,7 @@ module Gloo
|
|
407
408
|
def self.messages
|
408
409
|
return super + [ 'start', 'stop',
|
409
410
|
'list_routes', 'list_assets',
|
411
|
+
'add_session_to_response', 'clear_session_data',
|
410
412
|
'list_asset_img', 'list_asset_css', 'list_asset_js' ]
|
411
413
|
end
|
412
414
|
|
@@ -494,6 +496,22 @@ module Gloo
|
|
494
496
|
end
|
495
497
|
end
|
496
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
|
+
|
497
515
|
|
498
516
|
# ---------------------------------------------------------------------
|
499
517
|
# Start and Stop Events
|
@@ -533,7 +551,7 @@ module Gloo
|
|
533
551
|
@engine.log.info "Stopping web server…"
|
534
552
|
|
535
553
|
# Last chance to clear out session data.
|
536
|
-
|
554
|
+
reset_session_data
|
537
555
|
|
538
556
|
@web_server.stop
|
539
557
|
@web_server = nil
|
@@ -570,13 +588,18 @@ module Gloo
|
|
570
588
|
|
571
589
|
#
|
572
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.
|
573
593
|
#
|
574
|
-
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
|
575
598
|
o = find_child ON_REQUEST
|
576
599
|
return unless o
|
577
600
|
o = Gloo::Objs::Alias.resolve_alias( @engine, o )
|
578
601
|
|
579
|
-
Gloo::Exec::Dispatch.message( @engine, 'run', o )
|
602
|
+
Gloo::Exec::Dispatch.message( @engine, 'run', o, CURRENT_PAGE => current_page )
|
580
603
|
end
|
581
604
|
|
582
605
|
#
|
@@ -595,6 +618,10 @@ module Gloo
|
|
595
618
|
# This is done before the on_request event is fired.
|
596
619
|
#
|
597
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
|
+
|
598
625
|
data = find_child RESQUEST_DATA
|
599
626
|
return unless data
|
600
627
|
data = Gloo::Objs::Alias.resolve_alias( @engine, data )
|
data/lib/gloo/verbs/load.rb
CHANGED
data/lib/gloo/verbs/save.rb
CHANGED
data/lib/gloo/verbs/show.rb
CHANGED
@@ -72,6 +72,14 @@ module Gloo
|
|
72
72
|
return "<link rel='stylesheet' media='all' href='#{published_name}' />"
|
73
73
|
end
|
74
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
|
+
|
75
83
|
|
76
84
|
# ---------------------------------------------------------------------
|
77
85
|
# Obj Helper Functions
|
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
|
|
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
|
@@ -73,8 +73,8 @@ module Gloo
|
|
73
73
|
end
|
74
74
|
|
75
75
|
str += "<tr class='#{styles[ ROW ]}'>"
|
76
|
-
str += "<th
|
77
|
-
str += "<td
|
76
|
+
str += "<th class='#{styles[ HEAD_CELL ]}'>#{head[ :title ]}</th>"
|
77
|
+
str += "<td class='#{styles[ CELL ]}'>#{cell_value}</td>"
|
78
78
|
str += "</tr>"
|
79
79
|
end
|
80
80
|
|
@@ -113,7 +113,7 @@ module Gloo
|
|
113
113
|
else
|
114
114
|
cell_value = cell
|
115
115
|
end
|
116
|
-
str += "<td
|
116
|
+
str += "<td class='#{styles[ CELL ]}'>#{cell_value}</td>"
|
117
117
|
end
|
118
118
|
str += "</tr>"
|
119
119
|
end
|
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.9.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: 2025-
|
11
|
+
date: 2025-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -419,6 +419,12 @@ files:
|
|
419
419
|
- lib/gloo/expr/l_integer.rb
|
420
420
|
- lib/gloo/expr/l_string.rb
|
421
421
|
- lib/gloo/expr/op_div.rb
|
422
|
+
- lib/gloo/expr/op_eq.rb
|
423
|
+
- lib/gloo/expr/op_gt.rb
|
424
|
+
- lib/gloo/expr/op_gteq.rb
|
425
|
+
- lib/gloo/expr/op_ineq.rb
|
426
|
+
- lib/gloo/expr/op_lt.rb
|
427
|
+
- lib/gloo/expr/op_lteq.rb
|
422
428
|
- lib/gloo/expr/op_minus.rb
|
423
429
|
- lib/gloo/expr/op_mult.rb
|
424
430
|
- lib/gloo/expr/op_plus.rb
|
@@ -462,6 +468,7 @@ files:
|
|
462
468
|
- lib/gloo/objs/ror/erb.rb
|
463
469
|
- lib/gloo/objs/ror/eval.rb
|
464
470
|
- lib/gloo/objs/security/cipher.rb
|
471
|
+
- lib/gloo/objs/security/csrf_token.rb
|
465
472
|
- lib/gloo/objs/security/password.rb
|
466
473
|
- lib/gloo/objs/system/file_handle.rb
|
467
474
|
- lib/gloo/objs/system/ssh_exec.rb
|