gloo 3.7.0 → 3.9.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 +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
|