gloo 3.3.0 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/gloo.gemspec +8 -3
  4. data/lib/VERSION +1 -1
  5. data/lib/VERSION_NOTES +7 -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 -90
  9. data/lib/gloo/app/prompt.rb +90 -0
  10. data/lib/gloo/app/table.rb +51 -0
  11. data/lib/gloo/core/gloo_system.rb +7 -14
  12. data/lib/gloo/objs/basic/container.rb +1 -2
  13. data/lib/gloo/objs/basic/integer.rb +23 -1
  14. data/lib/gloo/objs/basic/string.rb +116 -1
  15. data/lib/gloo/objs/basic/string_generator.rb +49 -0
  16. data/lib/gloo/objs/basic/text.rb +1 -17
  17. data/lib/gloo/objs/cli/menu.rb +5 -4
  18. data/lib/gloo/objs/cli/select.rb +3 -2
  19. data/lib/gloo/objs/data/markdown.rb +25 -30
  20. data/lib/gloo/objs/data/mysql.rb +39 -27
  21. data/lib/gloo/objs/data/pg.rb +1 -1
  22. data/lib/gloo/objs/data/query_result.rb +4 -9
  23. data/lib/gloo/objs/data/table.rb +1 -1
  24. data/lib/gloo/objs/security/cipher.rb +193 -0
  25. data/lib/gloo/objs/security/password.rb +167 -0
  26. data/lib/gloo/objs/system/file_handle.rb +1 -3
  27. data/lib/gloo/objs/web/json.rb +3 -0
  28. data/lib/gloo/objs/web_svr/page.rb +24 -8
  29. data/lib/gloo/objs/web_svr/partial.rb +7 -6
  30. data/lib/gloo/objs/web_svr/svr.rb +267 -14
  31. data/lib/gloo/verbs/version.rb +1 -1
  32. data/lib/gloo/web_svr/asset.rb +34 -13
  33. data/lib/gloo/web_svr/config.rb +1 -1
  34. data/lib/gloo/web_svr/embedded_renderer.rb +1 -1
  35. data/lib/gloo/web_svr/handler.rb +6 -4
  36. data/lib/gloo/web_svr/request.rb +34 -8
  37. data/lib/gloo/web_svr/response.rb +14 -2
  38. data/lib/gloo/web_svr/response_code.rb +1 -1
  39. data/lib/gloo/web_svr/routing/router.rb +1 -2
  40. data/lib/gloo/web_svr/routing/show_routes.rb +4 -7
  41. data/lib/gloo/web_svr/server.rb +1 -1
  42. data/lib/gloo/web_svr/session.rb +161 -0
  43. data/lib/gloo/web_svr/table_renderer.rb +1 -1
  44. metadata +58 -25
  45. data/lib/gloo/objs/cli/banner.rb +0 -118
  46. data/lib/gloo/objs/cli/bar.rb +0 -133
  47. data/lib/gloo/objs/cli/pastel.rb +0 -104
@@ -3,6 +3,8 @@
3
3
  #
4
4
  # A String.
5
5
  #
6
+ require 'base64'
7
+ require 'uri'
6
8
 
7
9
  module Gloo
8
10
  module Objs
@@ -40,7 +42,8 @@ module Gloo
40
42
  # Get a list of message names that this object receives.
41
43
  #
42
44
  def self.messages
43
- return super + %w[up down size]
45
+ return super + %w[up down size encode64 decode64 escape unescape
46
+ gen_alphanumeric gen_uuid gen_hex gen_base64]
44
47
  end
45
48
 
46
49
  #
@@ -52,6 +55,118 @@ module Gloo
52
55
  return s
53
56
  end
54
57
 
58
+ #
59
+ # Escape the string.
60
+ # Make it URL safe.
61
+ # The value of the string is changed.
62
+ #
63
+ def msg_escape
64
+ s = URI::DEFAULT_PARSER.escape( value )
65
+ set_value s
66
+ @engine.heap.it.set_to s
67
+ return s
68
+ end
69
+
70
+ #
71
+ # Unescape the string.
72
+ # The value of the string is changed.
73
+ #
74
+ def msg_unescape
75
+ s = URI::DEFAULT_PARSER.unescape( value )
76
+ set_value s
77
+ @engine.heap.it.set_to s
78
+ return s
79
+ end
80
+
81
+ #
82
+ # Encode the string as base64.
83
+ # Changes the value of the string.
84
+ #
85
+ def msg_encode64
86
+ s = Base64.encode64( value )
87
+ set_value s
88
+ @engine.heap.it.set_to s
89
+ return s
90
+ end
91
+
92
+ #
93
+ # Decode the string from base64.
94
+ # Changes the value of the string.
95
+ #
96
+ def msg_decode64
97
+ s = Base64.decode64( value )
98
+ set_value s
99
+ @engine.heap.it.set_to s
100
+ return s
101
+ end
102
+
103
+ #
104
+ # Generate a new UUID in the string.
105
+ #
106
+ def msg_gen_uuid
107
+ s = StringGenerator.uuid
108
+ set_value s
109
+ @engine.heap.it.set_to s
110
+ return s
111
+ end
112
+
113
+ #
114
+ # Generate a random alphanumeric string.
115
+ # By default the length is 10 characters.
116
+ # Set the length with an optional parameter.
117
+ #
118
+ def msg_gen_alphanumeric
119
+ len = 10
120
+ if @params&.token_count&.positive?
121
+ expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
122
+ data = expr.evaluate
123
+ len = data.to_i
124
+ end
125
+
126
+ s = StringGenerator.alphanumeric( len )
127
+ set_value s
128
+ @engine.heap.it.set_to s
129
+ return s
130
+ end
131
+
132
+ #
133
+ # Generate a random hex string.
134
+ # By default the length is 10 hex characters.
135
+ # Set the length with an optional parameter.
136
+ #
137
+ def msg_gen_hex
138
+ len = 10
139
+ if @params&.token_count&.positive?
140
+ expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
141
+ data = expr.evaluate
142
+ len = data.to_i
143
+ end
144
+
145
+ s = StringGenerator.hex( len )
146
+ set_value s
147
+ @engine.heap.it.set_to s
148
+ return s
149
+ end
150
+
151
+ #
152
+ # Generate a random base64 string.
153
+ # By default the length is 12 characters.
154
+ # Set the length with an optional parameter.
155
+ #
156
+ def msg_gen_base64
157
+ len = 12
158
+ if @params&.token_count&.positive?
159
+ expr = Gloo::Expr::Expression.new( @engine, @params.tokens )
160
+ data = expr.evaluate
161
+ len = data.to_i
162
+ end
163
+
164
+ s = StringGenerator.base64( len )
165
+ set_value s
166
+ @engine.heap.it.set_to s
167
+ return s
168
+ end
169
+
55
170
  #
56
171
  # Convert string to upper case
57
172
  #
@@ -0,0 +1,49 @@
1
+ # Author:: Eric Crane (mailto:eric.crane@mac.com)
2
+ # Copyright:: Copyright (c) 2024 Eric Crane. All rights reserved.
3
+ #
4
+ # String generation utilities.
5
+ # This is a static class.
6
+ #
7
+
8
+ module Gloo
9
+ module Objs
10
+ class StringGenerator
11
+
12
+ # TO DO: Consider adding in Faker generators as well.
13
+
14
+
15
+ # ---------------------------------------------------------------------
16
+ # Generators
17
+ # ---------------------------------------------------------------------
18
+
19
+ #
20
+ # Generate a new UUID.
21
+ #
22
+ def self.uuid
23
+ return SecureRandom.uuid
24
+ end
25
+
26
+ #
27
+ # Generate a random alphanumeric string.
28
+ #
29
+ def self.alphanumeric len=10
30
+ return SecureRandom.alphanumeric( len )
31
+ end
32
+
33
+ #
34
+ # Generate a random hex string.
35
+ #
36
+ def self.hex len=10
37
+ s = SecureRandom.hex( len )
38
+ end
39
+
40
+ #
41
+ # Generate a random base64 string.
42
+ #
43
+ def self.base64 len=12
44
+ return SecureRandom.base64( len )
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -55,23 +55,7 @@ module Gloo
55
55
  # Get a list of message names that this object receives.
56
56
  #
57
57
  def self.messages
58
- return super + %w[edit page]
59
- end
60
-
61
- #
62
- # Show the contents of the file, paginated.
63
- #
64
- def msg_page
65
- return unless value
66
-
67
- @engine.platform.show( value, false, true )
68
- end
69
-
70
- #
71
- # Edit the text in the default editor.
72
- #
73
- def msg_edit
74
- self.value = @engine.platform.edit( self.value )
58
+ return super
75
59
  end
76
60
 
77
61
  end
@@ -19,8 +19,7 @@ module Gloo
19
19
  BEFORE_MENU = 'before_menu'.freeze
20
20
  DEFAULT = 'default'.freeze
21
21
  TITLE = 'title'.freeze
22
- TITLE_STYLE = 'straight'.freeze
23
- TITLE_COLOR = 'bright_cyan'.freeze
22
+ TITLE_COLOR = 'green'.freeze
24
23
  QUIT_ITEM_NAME = 'q'.freeze
25
24
 
26
25
  @@menu_stack = []
@@ -234,7 +233,7 @@ module Gloo
234
233
  dt = DateTime.now
235
234
  d = dt.strftime( '%Y.%m.%d' )
236
235
  t = dt.strftime( '%I:%M:%S' )
237
- cmd = @engine.platform.prompt.ask( "\n#{d.yellow} #{t.white} >" )
236
+ cmd = @engine.platform.prompt.ask( "#{d.yellow} #{t.white} >" )
238
237
  else
239
238
  cmd = @engine.platform.prompt.ask( prompt_value )
240
239
  end
@@ -320,7 +319,9 @@ module Gloo
320
319
  def run_default_title
321
320
  @engine.platform&.clear_screen
322
321
  show_menu_stack
323
- Banner.show_banner( title, TITLE_STYLE, TITLE_COLOR )
322
+
323
+ title_text = @engine.platform.table.box( title )
324
+ puts title_text.colorize( :color => :white, :background => :black )
324
325
  end
325
326
 
326
327
  #
@@ -116,8 +116,9 @@ module Gloo
116
116
  prompt = prompt_value
117
117
  return unless prompt
118
118
 
119
- per = Gloo::App::Settings.page_size( @engine )
120
- result = @engine.platform.prompt.select( prompt, options, :per_page => per )
119
+ # Page size was part of the tty-prompt but not used now.
120
+ # per = Gloo::App::Settings.page_size( @engine )
121
+ result = @engine.platform.prompt.select( prompt, options )
121
122
  set_result self.key_for_option( result )
122
123
  end
123
124
 
@@ -56,23 +56,14 @@ module Gloo
56
56
  # Get a list of message names that this object receives.
57
57
  #
58
58
  def self.messages
59
- return super + %w[show page render]
59
+ return super + %w[show render update_asset_path]
60
60
  end
61
61
 
62
62
  #
63
63
  # Show the markdown data in the terminal.
64
64
  #
65
65
  def msg_show
66
- @engine.platform.show( self.value, true, false )
67
- end
68
-
69
- #
70
- # Show the markdown data in the terminal, paginated.
71
- #
72
- def msg_page
73
- return unless self.value
74
-
75
- @engine.platform.show( self.value, true, true )
66
+ @engine.platform.show self.value
76
67
  end
77
68
 
78
69
  #
@@ -94,6 +85,29 @@ module Gloo
94
85
  @engine.heap.it.set_to html
95
86
  end
96
87
 
88
+ #
89
+ # Update the asset path in the markdown.
90
+ # Take out leading relative path so that path starts
91
+ # at the asset root.
92
+ #
93
+ def msg_update_asset_path
94
+ data = self.value
95
+ out_data = ""
96
+
97
+ data.lines.each do |line|
98
+ if line.include?( '![' ) && line.include?( '](') && line.include?( '/asset/')
99
+ prefix = line[ 0, ( line.index( '](' ) + 2 ) ]
100
+ suffix = line[ (line.index( '/asset/' )) .. -1 ]
101
+ out_data << "#{prefix}#{suffix}"
102
+ else
103
+ out_data << line
104
+ end
105
+ end
106
+
107
+ self.value = out_data
108
+ end
109
+
110
+
97
111
  # ---------------------------------------------------------------------
98
112
  # Static Helpers
99
113
  # ---------------------------------------------------------------------
@@ -113,25 +127,6 @@ module Gloo
113
127
  return markdown.render( md )
114
128
  end
115
129
 
116
- #
117
- # Does not work.
118
- # See note in the platform.rb file.
119
- #
120
- # #
121
- # # Convert markdown to manpage using the
122
- # # Redcarpet markdown processor.
123
- # #
124
- # def self.md_2_manpage( md )
125
- # markdown = Redcarpet::Markdown.new(
126
- # Redcarpet::Render::ManPage,
127
- # autolink: true,
128
- # fenced_code_blocks: true,
129
- # tables: true,
130
- # strikethrough: true )
131
-
132
- # return markdown.render( md )
133
- # end
134
-
135
130
  end
136
131
  end
137
132
  end
@@ -105,17 +105,24 @@ module Gloo
105
105
 
106
106
  client = app.db_client_for_obj( self ) if app
107
107
 
108
- unless client
109
- h = {
110
- host: host_value,
111
- database: db_value,
112
- username: user_value,
113
- password: passwd_value
114
- }
115
- client = Mysql2::Client.new( h )
116
-
117
- app.cache_db_client( self, client ) if app
108
+ if client && client.ping
109
+ @engine.log.debug "Connection is established and active."
110
+ return client
111
+ elsif client
112
+ @engine.log.debug "Connection is established but NOT active. Reconnecting."
113
+ else
114
+ @engine.log.debug "Opening a new Connection."
118
115
  end
116
+
117
+ h = {
118
+ host: host_value,
119
+ database: db_value,
120
+ username: user_value,
121
+ password: passwd_value
122
+ }
123
+ client = Mysql2::Client.new( h )
124
+
125
+ app.cache_db_client( self, client ) if app
119
126
 
120
127
  return client
121
128
  end
@@ -129,28 +136,33 @@ module Gloo
129
136
 
130
137
  heads = []
131
138
  data = []
132
- if params
133
- pst = client.prepare( sql )
134
- rs = pst.execute( *params, :as => :array )
135
- if rs
136
- rs.each do |row|
137
- arr = []
138
- row.each do |o|
139
- arr << o
139
+ begin
140
+ if params
141
+ pst = client.prepare( sql )
142
+ rs = pst.execute( *params, :as => :array )
143
+ if rs
144
+ rs.each do |row|
145
+ arr = []
146
+ row.each do |o|
147
+ arr << o
148
+ end
149
+ data << arr
140
150
  end
141
- data << arr
142
151
  end
143
- end
144
- else
145
- rs = client.query( sql, :as => :array )
146
- if rs
147
- rs.each do |row|
148
- data << row
152
+ else
153
+ rs = client.query( sql, :as => :array )
154
+ if rs
155
+ rs.each do |row|
156
+ data << row
157
+ end
149
158
  end
150
159
  end
160
+
161
+ heads = rs.fields if rs
162
+ rescue => e
163
+ @engine.err e.message
151
164
  end
152
165
 
153
- heads = rs.fields if rs
154
166
  return [ heads, data ]
155
167
  end
156
168
 
@@ -158,7 +170,7 @@ module Gloo
158
170
  # Based on the result set, build a QueryResult object.
159
171
  #
160
172
  def get_query_result( result )
161
- return QueryResult.new result[0], result[1]
173
+ return QueryResult.new result[0], result[1], @engine
162
174
  end
163
175
 
164
176
 
@@ -123,7 +123,7 @@ module Gloo
123
123
  # Based on the result set, build a QueryResult object.
124
124
  #
125
125
  def get_query_result( result )
126
- return QueryResult.new result[0], result[1]
126
+ return QueryResult.new result[0], result[1], @engine
127
127
  end
128
128
 
129
129
 
@@ -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