gloo 3.2.0 → 3.4.0

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