securial 0.7.0 → 0.8.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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -5
  3. data/app/controllers/concerns/securial/identity.rb +17 -16
  4. data/app/controllers/securial/accounts_controller.rb +2 -2
  5. data/app/controllers/securial/passwords_controller.rb +2 -2
  6. data/app/controllers/securial/role_assignments_controller.rb +5 -7
  7. data/app/controllers/securial/roles_controller.rb +1 -0
  8. data/app/controllers/securial/sessions_controller.rb +6 -8
  9. data/app/controllers/securial/users_controller.rb +8 -7
  10. data/app/mailers/securial/securial_mailer.rb +17 -6
  11. data/app/models/concerns/securial/password_resettable.rb +1 -1
  12. data/app/models/securial/application_record.rb +1 -1
  13. data/app/models/securial/session.rb +16 -5
  14. data/app/models/securial/user.rb +1 -3
  15. data/app/views/securial/securial_mailer/forgot_password.html.erb +20 -0
  16. data/app/views/securial/securial_mailer/forgot_password.text.erb +14 -0
  17. data/app/views/securial/securial_mailer/sign_in.html.erb +31 -0
  18. data/app/views/securial/securial_mailer/sign_in.text.erb +17 -0
  19. data/app/views/securial/securial_mailer/update_account.html.erb +15 -0
  20. data/app/views/securial/securial_mailer/update_account.text.erb +11 -0
  21. data/app/views/securial/securial_mailer/welcome.html.erb +11 -0
  22. data/app/views/securial/securial_mailer/welcome.text.erb +8 -0
  23. data/app/views/securial/users/_securial_user.json.jbuilder +9 -3
  24. data/config/routes.rb +5 -1
  25. data/db/migrate/{20250515104930_create_securial_roles.rb → 20250603130214_create_securial_roles.rb} +0 -2
  26. data/db/migrate/{20250517155521_create_securial_users.rb → 20250604110520_create_securial_users.rb} +8 -3
  27. data/db/migrate/{20250519075407_create_securial_sessions.rb → 20250604184841_create_securial_sessions.rb} +4 -0
  28. data/lib/generators/securial/install/templates/securial_initializer.erb +1 -1
  29. data/lib/generators/securial/scaffold/templates/controller.erb +1 -0
  30. data/lib/generators/securial/scaffold/templates/routes.erb +1 -1
  31. data/lib/securial/auth/auth_encoder.rb +8 -6
  32. data/lib/securial/auth/session_creator.rb +6 -3
  33. data/lib/securial/auth/token_generator.rb +26 -0
  34. data/lib/securial/auth.rb +7 -5
  35. data/lib/securial/config/configuration.rb +31 -13
  36. data/lib/securial/config/validation/logger_validation.rb +29 -0
  37. data/lib/securial/config/validation/mailer_validation.rb +24 -0
  38. data/lib/securial/config/validation/password_validation.rb +91 -0
  39. data/lib/securial/config/validation/response_validation.rb +37 -0
  40. data/lib/securial/config/validation/roles_validation.rb +32 -0
  41. data/lib/securial/config/validation/security_validation.rb +56 -0
  42. data/lib/securial/config/validation/session_validation.rb +87 -0
  43. data/lib/securial/config/validation.rb +16 -239
  44. data/lib/securial/config.rb +20 -4
  45. data/lib/securial/engine.rb +5 -79
  46. data/lib/securial/engine_initializers.rb +33 -0
  47. data/lib/securial/error/auth.rb +21 -0
  48. data/lib/securial/error/base_securial_error.rb +16 -0
  49. data/lib/securial/error/config.rb +37 -0
  50. data/lib/securial/error.rb +9 -0
  51. data/lib/securial/helpers/roles_helper.rb +17 -0
  52. data/lib/securial/helpers.rb +1 -0
  53. data/lib/securial/logger/broadcaster.rb +36 -24
  54. data/lib/securial/logger/builder.rb +29 -44
  55. data/lib/securial/logger/formatter.rb +35 -0
  56. data/lib/securial/logger.rb +10 -3
  57. data/lib/securial/middleware/request_tag_logger.rb +39 -0
  58. data/lib/securial/middleware.rb +13 -0
  59. data/lib/securial/version.rb +1 -1
  60. data/lib/securial.rb +2 -26
  61. metadata +39 -149
  62. data/app/views/securial/securial_mailer/reset_password.html.erb +0 -5
  63. data/app/views/securial/securial_mailer/reset_password.text.erb +0 -4
  64. data/lib/securial/auth/errors.rb +0 -15
  65. data/lib/securial/config/errors.rb +0 -20
  66. data/lib/securial/inspectors/route_inspector.rb +0 -52
  67. data/lib/securial/inspectors.rb +0 -8
  68. data/lib/securial/key_transformer.rb +0 -32
  69. data/lib/securial/logger/colors.rb +0 -14
  70. data/lib/securial/middlewares/request_logger_tag.rb +0 -19
  71. data/lib/securial/middlewares/transform_request_keys.rb +0 -33
  72. data/lib/securial/middlewares/transform_response_keys.rb +0 -52
  73. data/lib/securial/middlewares.rb +0 -10
  74. data/lib/securial/security/request_rate_limiter.rb +0 -68
  75. data/lib/securial/security.rb +0 -8
  76. data/lib/securial/version_checker.rb +0 -31
  77. /data/db/migrate/{20250518122749_create_securial_role_assignments.rb → 20250604123805_create_securial_role_assignments.rb} +0 -0
@@ -1,247 +1,24 @@
1
1
  require "securial/logger"
2
+ require "securial/config/validation/logger_validation"
3
+ require "securial/config/validation/roles_validation"
4
+ require "securial/config/validation/session_validation"
5
+ require "securial/config/validation/mailer_validation"
6
+ require "securial/config/validation/password_validation"
7
+ require "securial/config/validation/response_validation"
8
+ require "securial/config/validation/security_validation"
2
9
 
3
10
  module Securial
4
11
  module Config
5
12
  module Validation
6
- class << self # rubocop:disable Metrics/ClassLength
7
- def validate_all!(config)
8
- validate_admin_role!(config)
9
- validate_session_config!(config)
10
- validate_mailer_sender!(config)
11
- validate_password_config!(config)
12
- validate_response_config!(config)
13
- validate_security_config!(config)
14
- end
15
-
16
- private
17
-
18
- def validate_admin_role!(config)
19
- if config.admin_role.nil? || config.admin_role.to_s.strip.empty?
20
- error_message = "Admin role is not set."
21
- Securial.logger.fatal(error_message)
22
- raise Securial::Config::Errors::ConfigAdminRoleError, error_message
23
- end
24
-
25
- unless config.admin_role.is_a?(Symbol) || config.admin_role.is_a?(String)
26
- error_message = "Admin role must be a Symbol or String."
27
- Securial.logger.fatal(error_message)
28
- raise Securial::Config::Errors::ConfigAdminRoleError, error_message
29
- end
30
-
31
- if config.admin_role.to_s.pluralize.downcase == "accounts"
32
- error_message = "The admin role cannot be 'account' or 'accounts' as it conflicts with the default routes."
33
- Securial.logger.fatal(error_message)
34
- raise Securial::Config::Errors::ConfigAdminRoleError, error_message
35
- end
36
- end
37
-
38
- def validate_session_config!(config)
39
- validate_session_expiry_duration!(config)
40
- validate_session_algorithm!(config)
41
- validate_session_secret!(config)
42
- end
43
-
44
- def validate_session_expiry_duration!(config)
45
- if config.session_expiration_duration.nil?
46
- error_message = "Session expiration duration is not set."
47
- Securial.logger.fatal(error_message)
48
- raise Securial::Config::Errors::ConfigSessionExpirationDurationError, error_message
49
- end
50
- if config.session_expiration_duration.class != ActiveSupport::Duration
51
- error_message = "Session expiration duration must be an ActiveSupport::Duration."
52
- Securial.logger.fatal(error_message)
53
- raise Securial::Config::Errors::ConfigSessionExpirationDurationError, error_message
54
- end
55
- if config.session_expiration_duration <= 0
56
- Securial.logger.fatal("Session expiration duration must be greater than 0.")
57
- raise Securial::Config::Errors::ConfigSessionExpirationDurationError, "Session expiration duration must be greater than 0."
58
- end
59
- end
60
-
61
- def validate_session_algorithm!(config)
62
- if config.session_algorithm.blank?
63
- error_message = "Session algorithm is not set."
64
- Securial.logger.fatal(error_message)
65
- raise Securial::Config::Errors::ConfigSessionAlgorithmError, error_message
66
- end
67
- unless config.session_algorithm.is_a?(Symbol)
68
- error_message = "Session algorithm must be a Symbol."
69
- Securial.logger.fatal(error_message)
70
- raise Securial::Config::Errors::ConfigSessionAlgorithmError, error_message
71
- end
72
- valid_algorithms = Securial::Config::VALID_SESSION_ENCRYPTION_ALGORITHMS
73
- unless valid_algorithms.include?(config.session_algorithm)
74
- error_message = "Invalid session algorithm. Valid options are: #{valid_algorithms.map(&:inspect).join(', ')}."
75
- Securial.logger.fatal(error_message)
76
- raise Securial::Config::Errors::ConfigSessionAlgorithmError, error_message
77
- end
78
- end
79
-
80
- def validate_session_secret!(config)
81
- if config.session_secret.blank?
82
- error_message = "Session secret is not set."
83
- Securial.logger.fatal(error_message)
84
- raise Securial::Config::Errors::ConfigSessionSecretError, error_message
85
- end
86
- unless config.session_secret.is_a?(String)
87
- error_message = "Session secret must be a String."
88
- Securial.logger.fatal(error_message)
89
- raise Securial::Config::Errors::ConfigSessionSecretError, error_message
90
- end
91
- end
92
-
93
- def validate_mailer_sender!(config)
94
- if config.mailer_sender.blank?
95
- error_message = "Mailer sender is not set."
96
- Securial.logger.fatal(error_message)
97
- raise Securial::Config::Errors::ConfigMailerSenderError, error_message
98
- end
99
- if config.mailer_sender !~ URI::MailTo::EMAIL_REGEXP
100
- error_message = "Mailer sender is not a valid email address."
101
- Securial.logger.fatal(error_message)
102
- raise Securial::Config::Errors::ConfigMailerSenderError, error_message
103
- end
104
- end
105
-
106
- def validate_password_config!(config)
107
- validate_password_reset_subject!(config)
108
- validate_password_min_max_length!(config)
109
- validate_password_complexity!(config)
110
- validate_password_expiration!(config)
111
- validate_password_reset_token!(config)
112
- end
113
-
114
- def validate_password_reset_token!(config)
115
- if config.reset_password_token_secret.blank?
116
- error_message = "Reset password token secret is not set."
117
- Securial.logger.fatal(error_message)
118
- raise Securial::Config::Errors::ConfigPasswordError, error_message
119
- end
120
- unless config.reset_password_token_secret.is_a?(String)
121
- error_message = "Reset password token secret must be a String."
122
- Securial.logger.fatal(error_message)
123
- raise Securial::Config::Errors::ConfigPasswordError, error_message
124
- end
125
- end
126
-
127
- def validate_password_reset_subject!(config)
128
- if config.password_reset_email_subject.blank?
129
- error_message = "Password reset email subject is not set."
130
- Securial.logger.fatal(error_message)
131
- raise Securial::Config::Errors::ConfigPasswordError, error_message
132
- end
133
- unless config.password_reset_email_subject.is_a?(String)
134
- error_message = "Password reset email subject must be a String."
135
- Securial.logger.fatal(error_message)
136
- raise Securial::Config::Errors::ConfigPasswordError, error_message
137
- end
138
- end
139
-
140
- def validate_password_min_max_length!(config)
141
- unless config.password_min_length.is_a?(Integer) && config.password_min_length > 0
142
- error_message = "Password minimum length must be a positive integer."
143
- Securial.logger.fatal(error_message)
144
- raise Securial::Config::Errors::ConfigPasswordError, error_message
145
- end
146
- unless config.password_max_length.is_a?(Integer) && config.password_max_length >= config.password_min_length
147
- error_message = "Password maximum length must be an integer greater than or equal to the minimum length."
148
- Securial.logger.fatal(error_message)
149
- raise Securial::Config::Errors::ConfigPasswordError, error_message
150
- end
151
- end
152
-
153
- def validate_password_complexity!(config)
154
- if config.password_complexity.nil? || !config.password_complexity.is_a?(Regexp)
155
- error_message = "Password complexity regex is not set or is not a valid Regexp."
156
- Securial.logger.fatal(error_message)
157
- raise Securial::Config::Errors::ConfigPasswordError, error_message
158
- end
159
- end
160
-
161
- def validate_password_expiration!(config)
162
- unless config.password_expires.is_a?(TrueClass) || config.password_expires.is_a?(FalseClass)
163
- error_message = "Password expiration must be a boolean value."
164
- Securial.logger.fatal(error_message)
165
- raise Securial::Config::Errors::ConfigPasswordError, error_message
166
- end
167
-
168
- if config.password_expires == true && (
169
- config.password_expires_in.nil? ||
170
- !config.password_expires_in.is_a?(ActiveSupport::Duration) ||
171
- config.password_expires_in <= 0
172
- )
173
- error_message = "Password expiration duration is not set or is not a valid ActiveSupport::Duration."
174
- Securial.logger.fatal(error_message)
175
- raise Securial::Config::Errors::ConfigPasswordError, error_message
176
- end
177
- end
178
-
179
- def validate_response_config!(config)
180
- validate_response_keys_format!(config)
181
- validate_timestamps_in_response!(config)
182
- end
183
-
184
- def validate_response_keys_format!(config)
185
- valid_formats = Securial::Config::VALID_RESPONSE_KEYS_FORMATS
186
- unless valid_formats.include?(config.response_keys_format)
187
- error_message = "Invalid response_keys_format option. Valid options are: #{valid_formats.map(&:inspect).join(', ')}."
188
- Securial.logger.fatal(error_message)
189
- raise Securial::Config::Errors::ConfigResponseError, error_message
190
- end
191
- end
192
-
193
- def validate_timestamps_in_response!(config)
194
- valid_options = Securial::Config::VALID_TIMESTAMP_OPTIONS
195
- unless valid_options.include?(config.timestamps_in_response)
196
- error_message = "Invalid timestamps_in_response option. Valid options are: #{valid_options.map(&:inspect).join(', ')}."
197
- Securial.logger.fatal(error_message)
198
- raise Securial::Config::Errors::ConfigResponseError, error_message
199
- end
200
- end
201
-
202
- def validate_security_config!(config)
203
- validate_security_headers!(config)
204
- validate_rate_limiting!(config)
205
- end
206
-
207
- def validate_security_headers!(config)
208
- valid_options = Securial::Config::VALID_SECURITY_HEADERS
209
- unless valid_options.include?(config.security_headers)
210
- error_message = "Invalid security_headers option. Valid options are: #{valid_options.map(&:inspect).join(', ')}."
211
- Securial.logger.fatal(error_message)
212
- raise Securial::Config::Errors::ConfigSecurityError, error_message
213
- end
214
- end
215
-
216
- def validate_rate_limiting!(config) # rubocop:disable Metrics/MethodLength
217
- unless config.rate_limiting_enabled.is_a?(TrueClass) || config.rate_limiting_enabled.is_a?(FalseClass)
218
- error_message = "rate_limiting_enabled must be a boolean value."
219
- Securial.logger.fatal(error_message)
220
- raise Securial::Config::Errors::ConfigSecurityError, error_message
221
- end
222
-
223
- return unless config.rate_limiting_enabled
224
-
225
- unless
226
- config.rate_limit_requests_per_minute.is_a?(Integer) &&
227
- config.rate_limit_requests_per_minute > 0
228
-
229
- error_message = "rate_limit_requests_per_minute must be a positive integer when rate limiting is enabled."
230
- Securial.logger.fatal(error_message)
231
- raise Securial::Config::Errors::ConfigSecurityError, error_message
232
- end
233
-
234
- unless config.rate_limit_response_status.is_a?(Integer) && config.rate_limit_response_status.between?(400, 599)
235
- error_message = "rate_limit_response_status must be an HTTP status code between 4xx and 5xx."
236
- Securial.logger.fatal(error_message)
237
- raise Securial::Config::Errors::ConfigSecurityError, error_message
238
- end
239
-
240
- unless config.rate_limit_response_message.is_a?(String) && !config.rate_limit_response_message.strip.empty?
241
- error_message = "rate_limit_response_message must be a non-empty String."
242
- Securial.logger.fatal(error_message)
243
- raise Securial::Config::Errors::ConfigSecurityError, error_message
244
- end
13
+ class << self
14
+ def validate_all!(securial_config)
15
+ Securial::Config::Validation::LoggerValidation.validate!(securial_config)
16
+ Securial::Config::Validation::RolesValidation.validate!(securial_config)
17
+ Securial::Config::Validation::SessionValidation.validate!(securial_config)
18
+ Securial::Config::Validation::MailerValidation.validate!(securial_config)
19
+ Securial::Config::Validation::PasswordValidation.validate!(securial_config)
20
+ Securial::Config::Validation::ResponseValidation.validate!(securial_config)
21
+ Securial::Config::Validation::SecurityValidation.validate!(securial_config)
245
22
  end
246
23
  end
247
24
  end
@@ -1,10 +1,26 @@
1
1
  require "securial/config/configuration"
2
2
  require "securial/config/validation"
3
- require "securial/config/errors"
4
3
 
5
4
  module Securial
6
- module Config
7
- # This module acts as a namespace for configuration-related components.
8
- # It requires all key config files: Configuration, Validation, Errors.
5
+ class << self
6
+ attr_accessor :configuration
7
+
8
+ def configuration
9
+ @configuration ||= Config::Configuration.new
10
+ end
11
+
12
+ def configuration=(config)
13
+ if config.is_a?(Config::Configuration)
14
+ @configuration = config
15
+ Securial::Config::Validation.validate_all!(configuration)
16
+ else
17
+ raise ArgumentError, "Expected an instance of Securial::Config::Configuration"
18
+ end
19
+ end
20
+
21
+ def configure
22
+ yield(configuration) if block_given?
23
+ Securial::Config::Validation.validate_all!(configuration)
24
+ end
9
25
  end
10
26
  end
@@ -1,84 +1,14 @@
1
- require "jwt"
2
-
3
- require "securial/logger"
4
- require "securial/key_transformer"
1
+ require "securial/auth"
5
2
  require "securial/config"
6
3
  require "securial/helpers"
7
- require "securial/auth"
8
- require "securial/inspectors"
9
- require "securial/middlewares"
10
- require "securial/security"
11
- require "securial/version_checker"
4
+ require "securial/logger"
5
+ require "securial/middleware"
12
6
 
13
7
  module Securial
14
8
  class Engine < ::Rails::Engine
15
9
  isolate_namespace Securial
16
10
 
17
- # Set API-only mode and autoload custom generator paths
18
- config.api_only = true
19
11
  config.generators.api_only = true
20
- config.autoload_paths += Dir["#{config.root}/lib/generators"]
21
-
22
- initializer "securial.filter_parameters" do |app|
23
- app.config.filter_parameters += [
24
- :password,
25
- :password_confirmation,
26
- :password_reset_token,
27
- :reset_password_token
28
- ]
29
- end
30
-
31
- initializer "securial.logger" do
32
- Securial.const_set(:ENGINE_LOGGER, Securial::Logger.build)
33
- end
34
-
35
- initializer "securial.log_initialization" do |app|
36
- log "[Initializing Engine] Host app: #{app.class.name}"
37
- end
38
-
39
- initializer "securial.validate_config" do
40
- log "[Validating configuration] from `config/initializers/securial.rb`..."
41
- Securial::Config::Validation.validate_all!(Securial.configuration)
42
- end
43
-
44
- initializer "securial.extend_application_controller" do
45
- ActiveSupport.on_load(:action_controller_base) { include Securial::Identity }
46
- ActiveSupport.on_load(:action_controller_api) { include Securial::Identity }
47
- end
48
-
49
- initializer "securial.factory_bot", after: "factory_bot.set_factory_paths" do
50
- FactoryBot.definition_file_paths << Engine.root.join("lib", "securial", "factories") if defined?(FactoryBot)
51
- end
52
-
53
- initializer "securial.factory_bot_generator" do
54
- require_relative "../generators/factory_bot/model/model_generator"
55
- end
56
-
57
- initializer "securial.middleware" do |app|
58
- middleware.use Securial::Middlewares::RequestLoggerTag
59
- middleware.use Securial::Middlewares::TransformRequestKeys
60
- middleware.use Securial::Middlewares::TransformResponseKeys
61
- end
62
-
63
- initializer "securial.security.request_rate_limiter" do |app|
64
- if Securial.configuration.rate_limiting_enabled
65
- Securial::Security::RequestRateLimiter.apply!
66
- Rails.application.config.middleware.use Rack::Attack
67
- end
68
- end
69
-
70
-
71
- initializer "securial.version_check" do
72
- config.after_initialize do
73
- Securial::VersionChecker.check_latest_version
74
- end
75
- end
76
-
77
- initializer "securial.log_ready", after: :load_config_initializers do
78
- Rails.application.config.after_initialize do
79
- log "[Engine fully initialized] Environment: #{Rails.env}"
80
- end
81
- end
82
12
 
83
13
  config.generators do |g|
84
14
  g.orm :active_record, primary_key_type: :string
@@ -93,11 +23,7 @@ module Securial
93
23
  g.fixture_replacement :factory_bot, dir: "lib/securial/factories"
94
24
  g.template_engine :jbuilder
95
25
  end
96
-
97
- private
98
-
99
- def log(message)
100
- Securial.logger.info("[Securial] #{message}")
101
- end
102
26
  end
103
27
  end
28
+
29
+ require_relative "engine_initializers"
@@ -0,0 +1,33 @@
1
+ module Securial
2
+ class Engine < ::Rails::Engine
3
+ initializer "securial.filter_parameters" do |app|
4
+ app.config.filter_parameters += [
5
+ :password,
6
+ :password_confirmation,
7
+ :password_reset_token,
8
+ :reset_password_token
9
+ ]
10
+ end
11
+
12
+ initializer "securial.factory_bot", after: "factory_bot.set_factory_paths" do
13
+ if defined?(FactoryBot)
14
+ FactoryBot.definition_file_paths << Engine.root.join("lib", "securial", "factories")
15
+ require_relative "../generators/factory_bot/model/model_generator"
16
+ end
17
+ end
18
+
19
+ initializer "securial.logger_middleware" do |app|
20
+ app.middleware.use Securial::Middleware::RequestTagLogger
21
+ end
22
+
23
+ initializer "securial.extend_application_controller" do
24
+ ActiveSupport.on_load(:action_controller_base) { include Securial::Identity }
25
+ ActiveSupport.on_load(:action_controller_api) { include Securial::Identity }
26
+ end
27
+
28
+ initializer "securial.action_mailer.preview_path", after: "action_mailer.set_configs" do |app|
29
+ app.config.action_mailer.preview_paths ||= []
30
+ app.config.action_mailer.preview_paths |= [root.join("spec/mailers/previews").to_s]
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ module Securial
2
+ module Error
3
+ module Auth
4
+ class TokenEncodeError < BaseError
5
+ default_message "Error while encoding session token"
6
+ end
7
+
8
+ class TokenDecodeError < BaseError
9
+ default_message "Error while decoding session token"
10
+ end
11
+
12
+ class TokenRevokedError < BaseError
13
+ default_message "Session token is revoked"
14
+ end
15
+
16
+ class TokenExpiredError < BaseError
17
+ default_message "Session token is expired"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ module Securial
2
+ module Error
3
+ class BaseError < StandardError
4
+ def self.default_message(message = nil)
5
+ @default_message = message if message
6
+ @default_message
7
+ end
8
+
9
+ def initialize(message = nil)
10
+ super(message || self.class.default_message || "An error occurred in Securial")
11
+ end
12
+
13
+ def backtrace; []; end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,37 @@
1
+ module Securial
2
+ module Error
3
+ module Config
4
+ class InvalidConfigurationError < Securial::Error::BaseError
5
+ default_message "Invalid configuration for Securial"
6
+ end
7
+
8
+ class LoggerValidationError < InvalidConfigurationError
9
+ default_message "Logger configuration validation failed"
10
+ end
11
+
12
+ class RolesValidationError < InvalidConfigurationError
13
+ default_message "Roles configuration validation failed"
14
+ end
15
+
16
+ class SessionValidationError < InvalidConfigurationError
17
+ default_message "Session configuration validation failed"
18
+ end
19
+
20
+ class MailerValidationError < InvalidConfigurationError
21
+ default_message "Mailer configuration validation failed"
22
+ end
23
+
24
+ class PasswordValidationError < InvalidConfigurationError
25
+ default_message "Password configuration validation failed"
26
+ end
27
+
28
+ class ResponseValidationError < InvalidConfigurationError
29
+ default_message "Response configuration validation failed"
30
+ end
31
+
32
+ class SecurityValidationError < InvalidConfigurationError
33
+ default_message "Security configuration validation failed"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,9 @@
1
+ require "securial/error/base_securial_error"
2
+ require "securial/error/config"
3
+ require "securial/error/auth"
4
+
5
+ module Securial
6
+ module Error
7
+ # This serves as a namespace for all Securial errors.
8
+ end
9
+ end
@@ -0,0 +1,17 @@
1
+ module Securial
2
+ module Helpers
3
+ module RolesHelper
4
+ # This module provides helper methods related to roles.
5
+ # It can be extended with additional role-related functionality as needed.
6
+ class << self
7
+ def protected_namespace
8
+ Securial.configuration.admin_role.to_s.strip.underscore.pluralize
9
+ end
10
+
11
+ def titleized_admin_role
12
+ Securial.configuration.admin_role.to_s.strip.titleize
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,6 @@
1
1
  require "securial/helpers/normalizing_helper"
2
2
  require "securial/helpers/regex_helper"
3
+ require "securial/helpers/roles_helper"
3
4
 
4
5
  module Securial
5
6
  module Helpers
@@ -1,47 +1,59 @@
1
1
  module Securial
2
2
  module Logger
3
3
  class Broadcaster
4
- def initialize(*targets)
5
- @targets = targets
4
+ def initialize(loggers)
5
+ @loggers = loggers
6
6
  end
7
7
 
8
8
  ::Logger::Severity.constants.each do |severity|
9
- method = severity.downcase
10
- define_method(method) do |*args, &block|
11
- @targets.each do |logger|
12
- if logger.level <= ::Logger::Severity.const_get(severity)
13
- logger.send(method, *args, &block)
14
- end
15
- end
16
- end
17
- end
18
-
19
- def add(severity, message = nil, progname = nil, &block)
20
- @targets.each do |logger|
21
- if logger.level <= severity.to_i
22
- logger.add(severity, message, progname, &block)
23
- end
9
+ define_method(severity.downcase) do |*args, &block|
10
+ @loggers.each { |logger| logger.public_send(severity.downcase, *args, &block) }
24
11
  end
25
12
  end
26
13
 
27
14
  def <<(msg)
28
- @targets.each { |logger| logger << msg if logger.respond_to?(:<<) }
15
+ @loggers.each { |logger| logger << msg }
29
16
  end
30
17
 
31
18
  def close
32
- @targets.each { |logger| logger.close if logger.respond_to?(:close) }
19
+ @loggers.each(&:close)
33
20
  end
34
21
 
35
- def flush
36
- @targets.each { |logger| logger.flush if logger.respond_to?(:flush) }
22
+ def formatter=(_formatter)
23
+ # Do nothing
37
24
  end
38
25
 
39
26
  def formatter
40
- @targets.first.formatter if @targets.any?
27
+ nil
41
28
  end
42
29
 
43
- def formatter=(formatter)
44
- @targets.each { |logger| logger.formatter = formatter }
30
+ def loggers
31
+ @loggers
32
+ end
33
+
34
+ def tagged(*tags, &block)
35
+ # If all loggers support tagged, nest the calls, otherwise just yield.
36
+ taggable_loggers = @loggers.select { |logger| logger.respond_to?(:tagged) }
37
+ if taggable_loggers.any?
38
+ # Nest tags for all taggable loggers
39
+ taggable_loggers.reverse.inject(block) do |blk, logger|
40
+ proc { logger.tagged(*tags, &blk) }
41
+ end.call
42
+ else
43
+ yield
44
+ end
45
+ end
46
+
47
+ def respond_to_missing?(method, include_private = false)
48
+ @loggers.any? { |logger| logger.respond_to?(method, include_private) } || super
49
+ end
50
+
51
+ def method_missing(method, *args, &block)
52
+ if @loggers.all? { |logger| logger.respond_to?(method) }
53
+ @loggers.map { |logger| logger.send(method, *args, &block) }
54
+ else
55
+ super
56
+ end
45
57
  end
46
58
  end
47
59
  end