gloo 3.2.0 → 3.4.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/gloo.gemspec +9 -3
  4. data/lib/VERSION +1 -1
  5. data/lib/VERSION_NOTES +14 -0
  6. data/lib/gloo/app/engine.rb +1 -1
  7. data/lib/gloo/app/log.rb +15 -16
  8. data/lib/gloo/app/platform.rb +11 -84
  9. data/lib/gloo/app/prompt.rb +90 -0
  10. data/lib/gloo/app/table.rb +51 -0
  11. data/lib/gloo/convert/falseclass_to_integer.rb +20 -0
  12. data/lib/gloo/convert/nilclass_to_date.rb +21 -0
  13. data/lib/gloo/convert/nilclass_to_datetime.rb +21 -0
  14. data/lib/gloo/convert/nilclass_to_integer.rb +21 -0
  15. data/lib/gloo/convert/nilclass_to_string.rb +21 -0
  16. data/lib/gloo/convert/nilclass_to_time.rb +21 -0
  17. data/lib/gloo/convert/trueclass_to_integer.rb +20 -0
  18. data/lib/gloo/core/error.rb +7 -0
  19. data/lib/gloo/core/gloo_system.rb +7 -14
  20. data/lib/gloo/core/it.rb +7 -0
  21. data/lib/gloo/core/obj.rb +7 -0
  22. data/lib/gloo/core/parser.rb +6 -3
  23. data/lib/gloo/objs/basic/container.rb +1 -2
  24. data/lib/gloo/objs/basic/integer.rb +24 -1
  25. data/lib/gloo/objs/basic/string.rb +116 -1
  26. data/lib/gloo/objs/basic/string_generator.rb +49 -0
  27. data/lib/gloo/objs/basic/text.rb +1 -17
  28. data/lib/gloo/objs/cli/menu.rb +5 -4
  29. data/lib/gloo/objs/cli/select.rb +3 -2
  30. data/lib/gloo/objs/{basic → ctrl}/function.rb +12 -0
  31. data/lib/gloo/objs/data/markdown.rb +59 -6
  32. data/lib/gloo/objs/data/mysql.rb +39 -27
  33. data/lib/gloo/objs/data/pg.rb +1 -1
  34. data/lib/gloo/objs/data/query_result.rb +4 -9
  35. data/lib/gloo/objs/data/table.rb +1 -1
  36. data/lib/gloo/objs/security/cipher.rb +193 -0
  37. data/lib/gloo/objs/security/password.rb +167 -0
  38. data/lib/gloo/objs/system/file_handle.rb +1 -3
  39. data/lib/gloo/objs/web/json.rb +3 -0
  40. data/lib/gloo/objs/web_svr/page.rb +26 -6
  41. data/lib/gloo/objs/web_svr/partial.rb +7 -6
  42. data/lib/gloo/objs/web_svr/svr.rb +267 -14
  43. data/lib/gloo/verbs/invoke.rb +80 -0
  44. data/lib/gloo/verbs/version.rb +1 -1
  45. data/lib/gloo/web_svr/asset.rb +54 -33
  46. data/lib/gloo/web_svr/config.rb +1 -1
  47. data/lib/gloo/web_svr/embedded_renderer.rb +1 -1
  48. data/lib/gloo/web_svr/handler.rb +6 -4
  49. data/lib/gloo/web_svr/request.rb +34 -8
  50. data/lib/gloo/web_svr/response.rb +14 -2
  51. data/lib/gloo/web_svr/response_code.rb +1 -1
  52. data/lib/gloo/web_svr/routing/router.rb +1 -2
  53. data/lib/gloo/web_svr/routing/show_routes.rb +4 -7
  54. data/lib/gloo/web_svr/server.rb +1 -1
  55. data/lib/gloo/web_svr/session.rb +161 -0
  56. data/lib/gloo/web_svr/table_renderer.rb +1 -1
  57. metadata +81 -26
  58. data/lib/gloo/objs/cli/banner.rb +0 -118
  59. data/lib/gloo/objs/cli/bar.rb +0 -133
  60. data/lib/gloo/objs/cli/pastel.rb +0 -104
@@ -3,7 +3,6 @@
3
3
  #
4
4
  # The result of a SQL database query.
5
5
  #
6
- require 'tty-table'
7
6
 
8
7
  module Gloo
9
8
  module Objs
@@ -15,16 +14,16 @@ module Gloo
15
14
  PARAMS = 'params'.freeze
16
15
 
17
16
 
18
-
19
17
  # ---------------------------------------------------------------------
20
18
  # Set up the Result
21
19
  # ---------------------------------------------------------------------
22
20
 
23
21
  #
24
22
  # Create the Result object
25
- def initialize( heads, data )
23
+ def initialize( heads, data, engine=nil )
26
24
  @heads = heads
27
25
  @data = data
26
+ @engine = engine
28
27
  end
29
28
 
30
29
 
@@ -72,18 +71,14 @@ module Gloo
72
71
  @heads.each_with_index do |h, i|
73
72
  arr << [ h, row[i] ]
74
73
  end
75
- table = TTY::Table.new( [ 'Field', 'Value' ], arr )
76
- renderer = TTY::Table::Renderer::Unicode.new( table, padding: [0,1] )
77
- puts renderer.render
74
+ @engine.platform.table.show [ 'Field', 'Value' ], arr
78
75
  end
79
76
 
80
77
  #
81
78
  # Show multiple rows in a table view.
82
79
  #
83
80
  def show_rows
84
- table = TTY::Table.new( @heads, @data )
85
- renderer = TTY::Table::Renderer::Unicode.new( table, padding: [0,1] )
86
- puts renderer.render
81
+ @engine.platform.table.show @heads, @data
87
82
  end
88
83
 
89
84
  # ---------------------------------------------------------------------
@@ -159,7 +159,7 @@ module Gloo
159
159
  #
160
160
  def msg_show
161
161
  title = self.value
162
- @engine.platform.show_table headers, data, title
162
+ @engine.platform.table.show headers, data[1], title
163
163
  end
164
164
 
165
165
  def msg_render
@@ -0,0 +1,193 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
3
+ #
4
+ # A object to encrypt and decrypt text.
5
+ #
6
+ require 'openssl'
7
+ require 'base64'
8
+
9
+ module Gloo
10
+ module Objs
11
+ class Cipher < Gloo::Core::Obj
12
+
13
+ KEYWORD = 'cipher'.freeze
14
+ KEYWORD_SHORT = 'crypt'.freeze
15
+
16
+ CIPHER_TYPE = 'AES-256-CBC'.freeze
17
+ KEY = 'key'.freeze
18
+ INIT_VECTOR = 'init_vector'.freeze
19
+ DATA = 'data'.freeze
20
+
21
+ #
22
+ # The name of the object type.
23
+ #
24
+ def self.typename
25
+ return KEYWORD
26
+ end
27
+
28
+ #
29
+ # The short name of the object type.
30
+ #
31
+ def self.short_typename
32
+ return KEYWORD_SHORT
33
+ end
34
+
35
+ #
36
+ # Get the Cipher Key.
37
+ # Returns nil if there is none.
38
+ #
39
+ def key
40
+ o = find_child KEY
41
+ return o&.value
42
+ end
43
+
44
+ #
45
+ # Get the Initialization Vector.
46
+ # Returns nil if there is none.
47
+ #
48
+ def init_vector
49
+ o = find_child INIT_VECTOR
50
+ return o&.value
51
+ end
52
+
53
+ #
54
+ # Get the data value of the object.
55
+ # This might be encrypted or decrypted based on
56
+ # what action was last taken.
57
+ #
58
+ def data
59
+ o = find_child DATA
60
+ return o&.value
61
+ end
62
+
63
+ #
64
+ # Update the key value.
65
+ #
66
+ def update_key( new_val )
67
+ o = find_child KEY
68
+ return unless o
69
+
70
+ o.set_value new_val
71
+ end
72
+
73
+ #
74
+ # Update the initialization vector value.
75
+ #
76
+ def update_init_vector( new_val )
77
+ o = find_child INIT_VECTOR
78
+ return unless o
79
+
80
+ o.set_value new_val
81
+ end
82
+
83
+ #
84
+ # Update the data value of the object.
85
+ #
86
+ def update_data( new_val )
87
+ o = find_child DATA
88
+ return unless o
89
+
90
+ o.set_value new_val
91
+ end
92
+
93
+
94
+ # ---------------------------------------------------------------------
95
+ # Children
96
+ # ---------------------------------------------------------------------
97
+
98
+ #
99
+ # Does this object have children to add when an object
100
+ # is created in interactive mode?
101
+ # This does not apply during obj load, etc.
102
+ #
103
+ def add_children_on_create?
104
+ return true
105
+ end
106
+
107
+ #
108
+ # Add children to this object.
109
+ # This is used by containers to add children needed
110
+ # for default configurations.
111
+ #
112
+ def add_default_children
113
+ fac = @engine.factory
114
+ fac.create_string KEY, '', self
115
+ fac.create_string INIT_VECTOR, '', self
116
+ fac.create_string DATA, '', self
117
+ end
118
+
119
+ # ---------------------------------------------------------------------
120
+ # Messages
121
+ # ---------------------------------------------------------------------
122
+
123
+ #
124
+ # Get a list of message names that this object receives.
125
+ #
126
+ def self.messages
127
+ return super + %w[generate_keys encrypt decrypt]
128
+ end
129
+
130
+ #
131
+ # Generate random Key and Initialization Vector.
132
+ #
133
+ def msg_generate_keys
134
+ cipher = OpenSSL::Cipher.new( CIPHER_TYPE )
135
+
136
+ key = cipher.random_key
137
+ key = Base64.encode64 key
138
+ update_key key
139
+
140
+ iv = update_init_vector cipher.random_iv
141
+ iv = Base64.encode64 iv
142
+ update_init_vector iv
143
+ end
144
+
145
+ #
146
+ # Decrypt the encrypted child object.
147
+ #
148
+ def msg_decrypt
149
+ update_data Cipher.decrypt( data, key, init_vector )
150
+ end
151
+
152
+ #
153
+ # Encrypt the decrypted child object.
154
+ #
155
+ def msg_encrypt
156
+ update_data Cipher.encrypt( data, key, init_vector )
157
+ end
158
+
159
+ # ---------------------------------------------------------------------
160
+ # Static Methods
161
+ # ---------------------------------------------------------------------
162
+
163
+ #
164
+ # Encrypt the data using the key and initialization vector.
165
+ # Returns the encrypted data (base64 encoded).
166
+ #
167
+ def self.encrypt( data, key, iv )
168
+ cipher = OpenSSL::Cipher.new( CIPHER_TYPE )
169
+ cipher.encrypt
170
+ cipher.key = Base64.decode64( key )
171
+ cipher.iv = Base64.decode64( iv ) unless iv.blank?
172
+
173
+ encrypted_msg = cipher.update( data ) + cipher.final
174
+ return Base64.encode64( encrypted_msg )
175
+ end
176
+
177
+ #
178
+ # Decrypt the data using the key and initialization vector.
179
+ # Returns the decrypted data.
180
+ #
181
+ def self.decrypt( data, key, iv )
182
+ cipher = OpenSSL::Cipher.new( CIPHER_TYPE )
183
+ data = Base64.decode64( data )
184
+ cipher.decrypt
185
+ cipher.key = Base64.decode64( key )
186
+ cipher.iv = Base64.decode64( iv ) unless iv.blank?
187
+
188
+ return cipher.update( data ) + cipher.final
189
+ end
190
+
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,167 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
3
+ #
4
+ # A hashed password (with salt).
5
+ #
6
+ # BCrypt is used to hash the password.
7
+ # https://www.rubydoc.info/gems/bcrypt-ruby
8
+ # https://github.com/bcrypt-ruby/bcrypt-ruby/blob/master/lib/bcrypt/password.rb
9
+ #
10
+ require 'bcrypt'
11
+
12
+ module Gloo
13
+ module Objs
14
+ class Password < Gloo::Core::Obj
15
+
16
+ KEYWORD = 'password'.freeze
17
+ KEYWORD_SHORT = 'hash'.freeze
18
+
19
+ SALT = 'salt'.freeze
20
+ PASSWORD = 'password'.freeze
21
+ HASH = 'hash'.freeze
22
+
23
+ #
24
+ # The name of the object type.
25
+ #
26
+ def self.typename
27
+ return KEYWORD
28
+ end
29
+
30
+ #
31
+ # The short name of the object type.
32
+ #
33
+ def self.short_typename
34
+ return KEYWORD_SHORT
35
+ end
36
+
37
+ #
38
+ # Get the password salt.
39
+ # Returns nil if there is none.
40
+ #
41
+ def salt
42
+ o = find_child SALT
43
+ return o&.value
44
+ end
45
+
46
+ #
47
+ # Get the password value.
48
+ # Returns nil if there is none.
49
+ #
50
+ def password
51
+ o = find_child PASSWORD
52
+ return o&.value
53
+ end
54
+
55
+ #
56
+ # Update the password value.
57
+ #
58
+ def update_password( new_pwd )
59
+ o = find_child PASSWORD
60
+ return unless o
61
+
62
+ o.set_value new_pwd
63
+ end
64
+
65
+ #
66
+ # Get the salted password.
67
+ #
68
+ def salt_pwd
69
+ return "#{salt}#{password}"
70
+ end
71
+
72
+ #
73
+ # Get the hashed password value.
74
+ # Returns nil if there is none.
75
+ #
76
+ def hash
77
+ o = find_child HASH
78
+ return o&.value
79
+ end
80
+
81
+ #
82
+ # Update the hashed password value.
83
+ #
84
+ def update_hash( new_hash )
85
+ o = find_child HASH
86
+ return unless o
87
+
88
+ o.set_value new_hash
89
+ end
90
+
91
+ # ---------------------------------------------------------------------
92
+ # Children
93
+ # ---------------------------------------------------------------------
94
+
95
+ #
96
+ # Does this object have children to add when an object
97
+ # is created in interactive mode?
98
+ # This does not apply during obj load, etc.
99
+ #
100
+ def add_children_on_create?
101
+ return true
102
+ end
103
+
104
+ #
105
+ # Add children to this object.
106
+ # This is used by containers to add children needed
107
+ # for default configurations.
108
+ #
109
+ def add_default_children
110
+ fac = @engine.factory
111
+ fac.create_string SALT, '', self
112
+ fac.create_string PASSWORD, '', self
113
+ fac.create_string HASH, '', self
114
+ end
115
+
116
+ # ---------------------------------------------------------------------
117
+ # Messages
118
+ # ---------------------------------------------------------------------
119
+
120
+ #
121
+ # Get a list of message names that this object receives.
122
+ #
123
+ def self.messages
124
+ return super + %w[hash check generate]
125
+ end
126
+
127
+ #
128
+ # Generate a random alphanumeric password.
129
+ # By default the length is 7 characters.
130
+ # Set the length with an optional parameter.
131
+ #
132
+ def msg_generate
133
+ len = 7
134
+ if @params&.token_count&.positive?
135
+ expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
136
+ data = expr.evaluate
137
+ len = data.to_i
138
+ end
139
+
140
+ s = StringGenerator.alphanumeric( len )
141
+ update_password s
142
+ @engine.heap.it.set_to s
143
+ return s
144
+ end
145
+
146
+ #
147
+ # Hash the password with the salt.
148
+ # Uses the salt and the password to create a hash.
149
+ #
150
+ def msg_hash
151
+ hashed_pwd = BCrypt::Password.create( salt_pwd )
152
+ update_hash hashed_pwd
153
+ end
154
+
155
+ #
156
+ # Check the password against the hash.
157
+ # Uses the salt and the hash to check the password.
158
+ #
159
+ def msg_check
160
+ hashed_pwd = BCrypt::Password.new( hash )
161
+ result = ( hashed_pwd == salt_pwd )
162
+ @engine.heap.it.set_to result
163
+ end
164
+
165
+ end
166
+ end
167
+ end
@@ -3,7 +3,6 @@
3
3
  #
4
4
  # An object that points to a file in the system.
5
5
  #
6
- require 'tty-pager'
7
6
 
8
7
  module Gloo
9
8
  module Objs
@@ -58,8 +57,7 @@ module Gloo
58
57
  def msg_page
59
58
  return unless value && File.file?( value )
60
59
 
61
- pager = TTY::Pager.new
62
- pager.page( path: value )
60
+ system "less #{value}"
63
61
  end
64
62
 
65
63
  #
@@ -66,6 +66,9 @@ module Gloo
66
66
  return unless self.value
67
67
 
68
68
  json = JSON.parse( self.value )
69
+ if self.value.start_with?( '"{' )
70
+ json = JSON.parse( json )
71
+ end
69
72
  pretty = JSON.pretty_generate( json )
70
73
  set_value pretty
71
74
  end
@@ -13,7 +13,8 @@ module Gloo
13
13
 
14
14
  # Events
15
15
  ON_RENDER = 'on_render'.freeze
16
- ON_RENDERED = 'on_rendered'.freeze
16
+ ON_PRERENDER = 'on_prerender'.freeze
17
+ AFTER_RENDER = 'after_render'.freeze
17
18
 
18
19
  # Parameters used during render.
19
20
  PARAMS = 'params'.freeze
@@ -189,6 +190,18 @@ module Gloo
189
190
  # Events
190
191
  # ---------------------------------------------------------------------
191
192
 
193
+ #
194
+ # Run the on prerender script if there is one.
195
+ #
196
+ def run_on_prerender
197
+ o = find_child ON_PRERENDER
198
+ return unless o
199
+
200
+ @engine.log.debug "running on_prerender for page"
201
+
202
+ Gloo::Exec::Dispatch.message( @engine, 'run', o )
203
+ end
204
+
192
205
  #
193
206
  # Run the on render script if there is one.
194
207
  #
@@ -196,16 +209,20 @@ module Gloo
196
209
  o = find_child ON_RENDER
197
210
  return unless o
198
211
 
212
+ @engine.log.debug "running on_render for page"
213
+
199
214
  Gloo::Exec::Dispatch.message( @engine, 'run', o )
200
215
  end
201
216
 
202
217
  #
203
218
  # Run the on rendered script if there is one.
204
219
  #
205
- def run_on_rendered
206
- o = find_child ON_RENDERED
220
+ def run_after_render
221
+ o = find_child AFTER_RENDER
207
222
  return unless o
208
223
 
224
+ @engine.log.debug "running after_render for page"
225
+
209
226
  Gloo::Exec::Dispatch.message( @engine, 'run', o )
210
227
  end
211
228
 
@@ -232,7 +249,7 @@ module Gloo
232
249
  fac = @engine.factory
233
250
 
234
251
  fac.create_script ON_RENDER, '', self
235
- fac.create_script ON_RENDERED, '', self
252
+ fac.create_script AFTER_RENDER, '', self
236
253
  fac.create_can PARAMS, self
237
254
 
238
255
  params = { :name => HEAD,
@@ -321,6 +338,9 @@ module Gloo
321
338
  @request = request
322
339
  set_id if @request
323
340
 
341
+ # Run the on prerender script
342
+ run_on_prerender
343
+
324
344
  # Set Params before running on render
325
345
  params = params_hash
326
346
 
@@ -337,8 +357,8 @@ module Gloo
337
357
  @engine.log.error "Unknown content type: #{content_type}"
338
358
  return nil
339
359
  end
340
-
341
- run_on_rendered
360
+
361
+ run_after_render
342
362
  @request = nil
343
363
  return nil if redirect_set?
344
364
 
@@ -13,7 +13,7 @@ module Gloo
13
13
 
14
14
  # Events
15
15
  ON_RENDER = 'on_render'.freeze
16
- ON_RENDERED = 'on_rendered'.freeze
16
+ AFTER_RENDER = 'after_render'.freeze
17
17
 
18
18
  # Parameters used during render.
19
19
  PARAMS = 'params'.freeze
@@ -92,8 +92,8 @@ module Gloo
92
92
  #
93
93
  # Run the on rendered script if there is one.
94
94
  #
95
- def run_on_rendered
96
- o = find_child ON_RENDERED
95
+ def run_after_render
96
+ o = find_child AFTER_RENDER
97
97
  return unless o
98
98
 
99
99
  Gloo::Exec::Dispatch.message( @engine, 'run', o )
@@ -122,7 +122,7 @@ module Gloo
122
122
  fac = @engine.factory
123
123
 
124
124
  fac.create_script ON_RENDER, '', self
125
- fac.create_script ON_RENDERED, '', self
125
+ fac.create_script AFTER_RENDER, '', self
126
126
 
127
127
  fac.create_can PARAMS, self
128
128
  fac.create_can CONTENT, self
@@ -149,6 +149,7 @@ module Gloo
149
149
  return part_content
150
150
  end
151
151
 
152
+
152
153
  # ---------------------------------------------------------------------
153
154
  # Render
154
155
  # ---------------------------------------------------------------------
@@ -173,7 +174,7 @@ module Gloo
173
174
  # part_content = Page.render_params part_content, params_hash
174
175
  part_content = @engine.running_app.obj.embedded_renderer.render part_content, params_hash
175
176
 
176
- run_on_rendered
177
+ run_after_render
177
178
  return part_content
178
179
  end
179
180
 
@@ -200,7 +201,7 @@ module Gloo
200
201
  # part_content = Page.render_params part_content, params
201
202
  part_content = @engine.running_app.obj.embedded_renderer.render part_content, params
202
203
 
203
- run_on_rendered
204
+ run_after_render
204
205
  return part_content
205
206
  end
206
207