securial 1.0.0 → 1.0.2

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/.yardopts +4 -0
  3. data/README.md +14 -9
  4. data/app/controllers/concerns/securial/identity.rb +91 -2
  5. data/app/controllers/securial/accounts_controller.rb +68 -5
  6. data/app/controllers/securial/application_controller.rb +34 -2
  7. data/app/controllers/securial/passwords_controller.rb +44 -4
  8. data/app/controllers/securial/role_assignments_controller.rb +55 -4
  9. data/app/controllers/securial/roles_controller.rb +54 -0
  10. data/app/controllers/securial/sessions_controller.rb +77 -3
  11. data/app/controllers/securial/status_controller.rb +24 -0
  12. data/app/controllers/securial/users_controller.rb +54 -0
  13. data/app/jobs/securial/application_job.rb +9 -0
  14. data/app/mailers/securial/application_mailer.rb +12 -0
  15. data/app/mailers/securial/securial_mailer.rb +30 -0
  16. data/app/models/concerns/securial/password_resettable.rb +70 -0
  17. data/app/models/securial/application_record.rb +19 -0
  18. data/app/models/securial/current.rb +13 -0
  19. data/app/models/securial/role.rb +17 -0
  20. data/app/models/securial/role_assignment.rb +16 -0
  21. data/app/models/securial/session.rb +79 -1
  22. data/app/models/securial/user.rb +34 -0
  23. data/bin/securial +6 -23
  24. data/lib/generators/factory_bot/model/model_generator.rb +1 -0
  25. data/lib/generators/securial/install/install_generator.rb +2 -2
  26. data/lib/generators/securial/install/views_generator.rb +2 -1
  27. data/lib/generators/securial/jbuilder/jbuilder_generator.rb +2 -0
  28. data/lib/generators/securial/scaffold/scaffold_generator.rb +2 -0
  29. data/lib/securial/auth/auth_encoder.rb +3 -3
  30. data/lib/securial/auth/session_creator.rb +1 -1
  31. data/lib/securial/auth/token_generator.rb +13 -13
  32. data/lib/securial/auth.rb +44 -6
  33. data/lib/securial/cli.rb +282 -0
  34. data/lib/securial/config/signature.rb +1 -1
  35. data/lib/securial/config/validation.rb +44 -45
  36. data/lib/securial/config.rb +63 -17
  37. data/lib/securial/engine.rb +41 -0
  38. data/lib/securial/error/auth.rb +52 -0
  39. data/lib/securial/error/base_securial_error.rb +56 -3
  40. data/lib/securial/error/config.rb +33 -0
  41. data/lib/securial/error.rb +33 -3
  42. data/lib/securial/helpers/key_transformer.rb +1 -1
  43. data/lib/securial/helpers/normalizing_helper.rb +1 -1
  44. data/lib/securial/helpers/regex_helper.rb +6 -7
  45. data/lib/securial/helpers/roles_helper.rb +6 -7
  46. data/lib/securial/helpers.rb +48 -4
  47. data/lib/securial/logger/broadcaster.rb +89 -1
  48. data/lib/securial/logger/builder.rb +54 -1
  49. data/lib/securial/logger/formatter.rb +73 -0
  50. data/lib/securial/logger.rb +48 -8
  51. data/lib/securial/middleware.rb +40 -9
  52. data/lib/securial/security/request_rate_limiter.rb +48 -2
  53. data/lib/securial/security.rb +37 -6
  54. data/lib/securial/version.rb +8 -1
  55. data/lib/securial.rb +40 -4
  56. metadata +15 -11
  57. data/lib/securial/cli/run.rb +0 -11
  58. data/lib/securial/cli/securial_new.rb +0 -53
  59. data/lib/securial/cli/show_help.rb +0 -26
  60. data/lib/securial/cli/show_version.rb +0 -9
@@ -1,4 +1,34 @@
1
1
  module Securial
2
+ #
3
+ # User
4
+ #
5
+ # This class represents a user in the Securial authentication and authorization system.
6
+ #
7
+ # Users can have multiple roles assigned to them, which define their permissions
8
+ # and access levels within the application.
9
+ #
10
+ # The User model includes functionality for password reset, email normalization,
11
+ # and various validations to ensure data integrity.
12
+ #
13
+ # ## Attributes
14
+ # - `email_address`: The user's email address, which is normalized
15
+ # - `username`: A unique username for the user, with specific format requirements
16
+ # - `first_name`: The user's first name, required and limited in length
17
+ # - `last_name`: The user's last name, required and limited in length
18
+ # - `phone`: An optional phone number, limited in length
19
+ # - `bio`: An optional biography, limited in length
20
+ #
21
+ # ## Validations
22
+ # - Email address must be present, unique, and formatted correctly
23
+ # - Username must be present, unique (case insensitive), and formatted correctly
24
+ # - First and last names must be present and limited in length
25
+ # - Phone and bio fields are optional but have length restrictions
26
+ #
27
+ # ## Associations
28
+ # - Has many role assignments, allowing users to have multiple roles
29
+ # - Has many roles through role assignments, enabling flexible permission management
30
+ # - Has many sessions, allowing for session management and tracking
31
+ #
2
32
  class User < ApplicationRecord
3
33
  include Securial::PasswordResettable
4
34
 
@@ -45,6 +75,10 @@ module Securial
45
75
  has_many :sessions, dependent: :destroy
46
76
 
47
77
 
78
+ # Checks if the user has the specified role.
79
+ #
80
+ # @param [String] role_name The name of the role to check
81
+ # @return [Boolean] Returns true if the user has the specified role, false otherwise.
48
82
  def is_admin?
49
83
  roles.exists?(role_name: Securial.titleized_admin_role)
50
84
  end
data/bin/securial CHANGED
@@ -1,26 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "fileutils"
4
- require_relative "../lib/securial/cli/show_version"
5
- require_relative "../lib/securial/cli/show_help"
6
- require_relative "../lib/securial/cli/run"
7
- require_relative "../lib/securial/cli/securial_new"
3
+ # Set up the load path for local development or gem installation
4
+ lib = File.expand_path("../../lib", __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
8
6
 
9
- case ARGV[0]
10
- when "-v", "--version"
11
- show_version
12
- when "-h", "--help"
13
- show_help
14
- when "new"
15
- if ARGV[1]
16
- app_name = ARGV[1]
17
- rails_options = ARGV[2..] || []
18
- securial_new(app_name, rails_options)
19
- else
20
- show_help
21
- exit(1)
22
- end
23
- else
24
- show_help
25
- exit(1)
26
- end
7
+ require "securial/cli"
8
+
9
+ Securial::CLI.start(ARGV)
@@ -1,6 +1,7 @@
1
1
  require "rails/generators"
2
2
  require "rails/generators/named_base"
3
3
 
4
+ # @!ignore
4
5
  module FactoryBot
5
6
  module Generators
6
7
  class ModelGenerator < Rails::Generators::NamedBase
@@ -4,10 +4,10 @@ require "rake"
4
4
  module Securial
5
5
  module Generators
6
6
  class InstallGenerator < Rails::Generators::Base
7
- source_root File.expand_path("templates", __dir__)
8
-
9
7
  desc "initializes Securial in your application."
10
8
 
9
+ source_root File.expand_path("templates", __dir__)
10
+
11
11
  def copy_initializer
12
12
  say_status("copying", "Securial Initializers", :green)
13
13
  template "securial_initializer.erb", "config/initializers/securial.rb"
@@ -5,9 +5,10 @@ module Securial
5
5
  module Generators
6
6
  module Install
7
7
  class ViewsGenerator < Rails::Generators::Base
8
- source_root Securial::Engine.root.join("app", "views", "securial").to_s
9
8
  desc "Copies Securial model-related views to your application for customization."
10
9
 
10
+ source_root Securial::Engine.root.join("app", "views", "securial").to_s
11
+
11
12
  def copy_model_views
12
13
  Dir.glob(File.join(self.class.source_root, "**/*")).each do |path|
13
14
  relative_path = Pathname.new(path).relative_path_from(Pathname.new(self.class.source_root))
@@ -1,6 +1,8 @@
1
1
  module Securial
2
2
  module Generators
3
3
  class JbuilderGenerator < Rails::Generators::NamedBase
4
+ desc "Generates Jbuilder view files for a given resource."
5
+
4
6
  source_root File.expand_path("templates", __dir__)
5
7
 
6
8
  argument :attributes, type: :array, default: [], banner: "field:type field:type"
@@ -5,6 +5,8 @@ require "rails/generators/named_base"
5
5
  module Securial
6
6
  module Generators
7
7
  class ScaffoldGenerator < Rails::Generators::NamedBase
8
+ desc "Creates a scaffold for a given resource, including model, controller, views, routes, and tests."
9
+
8
10
  include Rails::Generators::ResourceHelpers
9
11
 
10
12
  allow_incompatible_default_type!
@@ -3,7 +3,7 @@ require "jwt"
3
3
  module Securial
4
4
  module Auth
5
5
  module AuthEncoder
6
- module_function
6
+ extend self
7
7
 
8
8
  def encode(session)
9
9
  return nil unless session && session.class == Securial::Session
@@ -37,6 +37,8 @@ module Securial
37
37
  decoded.first
38
38
  end
39
39
 
40
+ private
41
+
40
42
  def secret
41
43
  Securial.configuration.session_secret
42
44
  end
@@ -48,8 +50,6 @@ module Securial
48
50
  def expiry_duration
49
51
  Securial.configuration.session_expiration_duration
50
52
  end
51
-
52
- private_class_method :secret, :algorithm, :expiry_duration
53
53
  end
54
54
  end
55
55
  end
@@ -1,7 +1,7 @@
1
1
  module Securial
2
2
  module Auth
3
3
  module SessionCreator
4
- module_function
4
+ extend self
5
5
 
6
6
  def create_session!(user, request)
7
7
  valid_user = user && user.is_a?(Securial::User) && user.persisted?
@@ -4,22 +4,22 @@ require "securerandom"
4
4
  module Securial
5
5
  module Auth
6
6
  module TokenGenerator
7
- class << self
8
- def generate_refresh_token
9
- secret = Securial.configuration.session_secret
10
- algo = "SHA256"
7
+ extend self
11
8
 
12
- random_data = SecureRandom.hex(32)
13
- digest = OpenSSL::Digest.new(algo)
14
- hmac = OpenSSL::HMAC.hexdigest(digest, secret, random_data)
9
+ def generate_refresh_token
10
+ secret = Securial.configuration.session_secret
11
+ algo = "SHA256"
15
12
 
16
- "#{hmac}#{random_data}"
17
- end
13
+ random_data = SecureRandom.hex(32)
14
+ digest = OpenSSL::Digest.new(algo)
15
+ hmac = OpenSSL::HMAC.hexdigest(digest, secret, random_data)
18
16
 
19
- def generate_password_reset_token
20
- token = SecureRandom.alphanumeric(12)
21
- "#{token[0, 6]}-#{token[6, 6]}"
22
- end
17
+ "#{hmac}#{random_data}"
18
+ end
19
+
20
+ def generate_password_reset_token
21
+ token = SecureRandom.alphanumeric(12)
22
+ "#{token[0, 6]}-#{token[6, 6]}"
23
23
  end
24
24
  end
25
25
  end
data/lib/securial/auth.rb CHANGED
@@ -1,12 +1,50 @@
1
+ # @title Securial Authentication System
2
+ #
3
+ # Core authentication components for the Securial framework.
4
+ #
5
+ # This file serves as the entry point for authentication-related functionality in Securial,
6
+ # loading specialized modules that handle token generation, encoding/decoding, and session management.
7
+ # These components work together to provide a secure, flexible authentication system supporting
8
+ # token-based and session-based authentication patterns.
9
+ #
10
+ # @example Encoding a session token
11
+ # # Create an encoded JWT representing a user session
12
+ # token = Securial::Auth::AuthEncoder.encode(user_session)
13
+ # # => "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMjM0NTY3ODkwIiwic3ViIjoiM..."
14
+ #
15
+ # @example Creating a new user session
16
+ # # Authenticate user and create a new session with tokens
17
+ # Securial::Auth::SessionCreator.create_session!(user, request)
18
+ #
19
+ # # Access the newly created session
20
+ # current_session = Current.session
21
+ #
22
+ # @example Generating secure tokens
23
+ # # Generate a password reset token
24
+ # reset_token = Securial::Auth::TokenGenerator.friendly_token
25
+ # # => "aBc123DeF456gHi789"
26
+ #
1
27
  require "securial/auth/auth_encoder"
2
28
  require "securial/auth/session_creator"
3
29
  require "securial/auth/token_generator"
4
30
 
5
31
  module Securial
6
- module Auth
7
- # This is a placeholder for the Auth module.
8
- # It can be used to include authentication-related methods or constants
9
- # that are not specific to encoding or session creation.
10
- # Currently, it serves as a namespace for the AuthEncoder and SessionCreator modules.
11
- end
32
+ # Namespace for authentication-related functionality in the Securial framework.
33
+ #
34
+ # The Auth module contains components that work together to provide a complete
35
+ # authentication system for Securial-powered applications:
36
+ #
37
+ # - {AuthEncoder} - Handles JWT token encoding and decoding with security measures
38
+ # - {SessionCreator} - Creates and manages authenticated user sessions
39
+ # - {TokenGenerator} - Generates secure random tokens for various authentication needs
40
+ #
41
+ # These components handle the cryptographic and security aspects of user authentication,
42
+ # ensuring that best practices are followed for token generation, validation, and session
43
+ # management throughout the application lifecycle.
44
+ #
45
+ # @see Securial::Auth::AuthEncoder
46
+ # @see Securial::Auth::SessionCreator
47
+ # @see Securial::Auth::TokenGenerator
48
+ #
49
+ module Auth; end
12
50
  end
@@ -0,0 +1,282 @@
1
+ # @title Securial Command Line Interface
2
+ #
3
+ # Command line interface for the Securial framework.
4
+ #
5
+ # This file implements the CLI tool for Securial, providing command-line utilities
6
+ # for creating new Rails applications with Securial pre-installed. It handles
7
+ # command parsing, option flags, and orchestrates the application setup process.
8
+ #
9
+ # @example Creating a new Rails application with Securial
10
+ # # Create a basic Securial application
11
+ # $ securial new myapp
12
+ #
13
+ # # Create an API-only Securial application with PostgreSQL
14
+ # $ securial new myapi --api --database=postgresql
15
+ #
16
+ require "optparse"
17
+
18
+ # rubocop:disable Rails/Exit, Rails/Output
19
+
20
+ module Securial
21
+ # Command-line interface for the Securial gem.
22
+ #
23
+ # This class provides the command-line functionality for Securial, enabling users
24
+ # to create new Rails applications with Securial pre-installed and configured.
25
+ # It handles command parsing, flag processing, and orchestrates the setup of
26
+ # new applications.
27
+ #
28
+ class CLI
29
+ # Entry point for the CLI application.
30
+ #
31
+ # Creates a new CLI instance and delegates to its start method.
32
+ #
33
+ # @param argv [Array<String>] command line arguments
34
+ # @return [Integer] exit status code (0 for success, non-zero for errors)
35
+ #
36
+ def self.start(argv)
37
+ new.start(argv)
38
+ end
39
+
40
+ # Processes command line arguments and executes the appropriate action.
41
+ #
42
+ # This method handles both option flags (like --version) and commands
43
+ # (like 'new'), delegating to specialized handlers and returning
44
+ # the appropriate exit code.
45
+ #
46
+ # @param argv [Array<String>] command line arguments
47
+ # @return [Integer] exit status code (0 for success, non-zero for errors)
48
+ #
49
+ def start(argv)
50
+ # Process options and exit if a flag was handled
51
+ result = handle_flags(argv)
52
+ exit(result) if result
53
+
54
+ # Otherwise handle commands
55
+ exit(handle_commands(argv))
56
+ end
57
+
58
+ private
59
+
60
+ # Processes option flags from the command line arguments.
61
+ #
62
+ # Parses options like --version and --help, executing their actions
63
+ # if present and removing them from the argument list.
64
+ #
65
+ # @param argv [Array<String>] command line arguments
66
+ # @return [nil, Integer] nil to continue processing, or exit code
67
+ #
68
+ def handle_flags(argv)
69
+ parser = create_option_parser
70
+
71
+ begin
72
+ parser.order!(argv)
73
+ nil # Continue to command handling
74
+ rescue OptionParser::InvalidOption => e
75
+ warn "ERROR: Illegal option(s): #{e.args.join(' ')}"
76
+ puts parser
77
+ 1
78
+ end
79
+ end
80
+
81
+ # Processes commands from the command line arguments.
82
+ #
83
+ # Identifies the command (e.g., 'new') and delegates to the appropriate
84
+ # handler method for that command.
85
+ #
86
+ # @param argv [Array<String>] command line arguments
87
+ # @return [Integer] exit status code (0 for success, non-zero for errors)
88
+ #
89
+ def handle_commands(argv)
90
+ cmd = argv.shift
91
+
92
+ case cmd
93
+ when "new"
94
+ handle_new_command(argv)
95
+ else
96
+ puts create_option_parser
97
+ 1
98
+ end
99
+ end
100
+
101
+ # Handles the 'new' command for creating Rails applications.
102
+ #
103
+ # Validates that an application name is provided, then delegates to
104
+ # securial_new to create the application with Securial.
105
+ #
106
+ # @param argv [Array<String>] remaining command line arguments
107
+ # @return [Integer] exit status code (0 for success, non-zero for errors)
108
+ #
109
+ def handle_new_command(argv)
110
+ app_name = argv.shift
111
+
112
+ if app_name.nil?
113
+ puts "ERROR: Please provide an app name."
114
+ puts create_option_parser
115
+ return 1
116
+ end
117
+
118
+ securial_new(app_name, argv)
119
+ 0
120
+ end
121
+
122
+ # Creates and configures the option parser.
123
+ #
124
+ # Sets up the command-line options and their handlers.
125
+ #
126
+ # @return [OptionParser] configured option parser instance
127
+ #
128
+ def create_option_parser
129
+ OptionParser.new do |opts|
130
+ opts.banner = "Usage: securial [options] <command> [command options]\n\n"
131
+
132
+ opts.separator ""
133
+ opts.separator "Commands:"
134
+ opts.separator " new APP_NAME [rails_options...] # Create a new Rails app with Securial pre-installed"
135
+ opts.separator ""
136
+ opts.separator "Options:"
137
+
138
+ opts.on("-v", "--version", "Show Securial version") do
139
+ show_version
140
+ exit(0)
141
+ end
142
+
143
+ opts.on("-h", "--help", "Show this help message") do
144
+ puts opts
145
+ exit(0)
146
+ end
147
+ end
148
+ end
149
+
150
+ # Displays the current Securial version.
151
+ #
152
+ # @return [void]
153
+ #
154
+ def show_version
155
+ require "securial/version"
156
+ puts "Securial v#{Securial::VERSION}"
157
+ rescue LoadError
158
+ puts "Securial version information not available."
159
+ end
160
+
161
+ # Creates a new Rails application with Securial pre-installed.
162
+ #
163
+ # Orchestrates the process of creating a Rails application, adding the
164
+ # Securial gem, installing dependencies, and configuring the application.
165
+ #
166
+ # @param app_name [String] name of the Rails application to create
167
+ # @param rails_options [Array<String>] options to pass to 'rails new'
168
+ # @return [void]
169
+ #
170
+ def securial_new(app_name, rails_options)
171
+ puts "🏗️ Creating new Rails app: #{app_name}"
172
+
173
+ create_rails_app(app_name, rails_options)
174
+ add_securial_gem(app_name)
175
+ install_gems(app_name)
176
+ install_securial(app_name)
177
+ mount_securial_engine(app_name)
178
+ print_final_instructions(app_name)
179
+ end
180
+
181
+ # Creates a new Rails application.
182
+ #
183
+ # @param app_name [String] name of the Rails application to create
184
+ # @param rails_options [Array<String>] options to pass to 'rails new'
185
+ # @return [Integer] command exit status
186
+ #
187
+ def create_rails_app(app_name, rails_options)
188
+ rails_command = ["rails", "new", app_name, *rails_options]
189
+ run(rails_command)
190
+ end
191
+
192
+ # Adds the Securial gem to the application's Gemfile.
193
+ #
194
+ # @param app_name [String] name of the Rails application
195
+ # @return [void]
196
+ #
197
+ def add_securial_gem(app_name)
198
+ puts "📦 Adding Securial gem to Gemfile"
199
+ gemfile_path = File.join(app_name, "Gemfile")
200
+ File.open(gemfile_path, "a") { |f| f.puts "\ngem 'securial'" }
201
+ end
202
+
203
+ # Installs gems for the application using Bundler.
204
+ #
205
+ # @param app_name [String] name of the Rails application
206
+ # @return [Integer] command exit status
207
+ #
208
+ def install_gems(app_name)
209
+ run("bundle install", chdir: app_name)
210
+ end
211
+
212
+ # Installs and configures Securial in the application.
213
+ #
214
+ # @param app_name [String] name of the Rails application
215
+ # @return [Integer] command exit status
216
+ #
217
+ def install_securial(app_name)
218
+ puts "🔧 Installing Securial"
219
+ run("bin/rails generate securial:install", chdir: app_name)
220
+ run("bin/rails db:migrate", chdir: app_name)
221
+ end
222
+
223
+ # Mounts the Securial engine in the application's routes.
224
+ #
225
+ # @param app_name [String] name of the Rails application
226
+ # @return [void]
227
+ #
228
+ def mount_securial_engine(app_name)
229
+ puts "🔗 Mounting Securial engine in routes"
230
+ routes_path = File.join(app_name, "config/routes.rb")
231
+ routes = File.read(routes_path)
232
+ updated = routes.sub("Rails.application.routes.draw do") do |match|
233
+ "#{match}\n mount Securial::Engine => '/securial'"
234
+ end
235
+ File.write(routes_path, updated)
236
+ end
237
+
238
+ # Prints final setup instructions after successful installation.
239
+ #
240
+ # @param app_name [String] name of the Rails application
241
+ # @return [void]
242
+ #
243
+ def print_final_instructions(app_name)
244
+ puts <<~INSTRUCTIONS
245
+ 🎉 Securial has been successfully installed in your Rails app!
246
+ ✅ Your app is ready at: ./#{app_name}
247
+
248
+ ➡️ Next steps:
249
+ cd #{app_name}
250
+ ⚙️ Optional: Configure Securial in config/initializers/securial.rb
251
+ rails server
252
+ INSTRUCTIONS
253
+ end
254
+
255
+ # Runs a system command with optional directory change.
256
+ #
257
+ # Executes the provided command, optionally in a different directory,
258
+ # and handles success/failure conditions.
259
+ #
260
+ # @param command [String, Array<String>] command to run
261
+ # @param chdir [String, nil] directory to change to before running command
262
+ # @return [Integer] command exit status code (0 for success)
263
+ # @raise [SystemExit] if the command fails
264
+ #
265
+ def run(command, chdir: nil)
266
+ puts "→ #{command.inspect}"
267
+ result =
268
+ if chdir
269
+ Dir.chdir(chdir) { system(*command) }
270
+ else
271
+ system(*command)
272
+ end
273
+
274
+ unless result
275
+ abort("❌ Command failed: #{command}")
276
+ end
277
+ 0
278
+ end
279
+ end
280
+ end
281
+
282
+ # rubocop:enable Rails/Exit, Rails/Output
@@ -47,7 +47,7 @@ module Securial
47
47
 
48
48
  def roles_signature
49
49
  {
50
- admin_role: { type: String, required: true, default: "admin" },
50
+ admin_role: { type: Symbol, required: true, default: :admin },
51
51
  }
52
52
  end
53
53
 
@@ -3,68 +3,67 @@ require "securial/logger"
3
3
  module Securial
4
4
  module Config
5
5
  module Validation
6
- class << self
7
- def validate_all!(securial_config)
8
- signature = Securial::Config::Signature.config_signature
6
+ extend self
7
+ def validate_all!(securial_config)
8
+ signature = Securial::Config::Signature.config_signature
9
9
 
10
- validate_required_fields!(signature, securial_config)
11
- validate_types_and_values!(signature, securial_config)
12
- validate_password_lengths!(securial_config)
13
- end
10
+ validate_required_fields!(signature, securial_config)
11
+ validate_types_and_values!(signature, securial_config)
12
+ validate_password_lengths!(securial_config)
13
+ end
14
14
 
15
- private
15
+ private
16
16
 
17
- def validate_required_fields!(signature, config)
18
- signature.each do |key, options|
19
- value = config.send(key)
20
- required = options[:required]
21
- if required == true && value.nil?
22
- raise_error("#{key} is required but not provided.")
23
- elsif required.is_a?(String)
24
- dynamic_required = config.send(required)
25
- signature[key][:required] = dynamic_required
26
- if dynamic_required && value.nil?
27
- raise_error("#{key} is required but not provided when #{required} is true.")
28
- end
17
+ def validate_required_fields!(signature, config)
18
+ signature.each do |key, options|
19
+ value = config.send(key)
20
+ required = options[:required]
21
+ if required == true && value.nil?
22
+ raise_error("#{key} is required but not provided.")
23
+ elsif required.is_a?(String)
24
+ dynamic_required = config.send(required)
25
+ signature[key][:required] = dynamic_required
26
+ if dynamic_required && value.nil?
27
+ raise_error("#{key} is required but not provided when #{required} is true.")
29
28
  end
30
29
  end
31
30
  end
31
+ end
32
32
 
33
- def validate_types_and_values!(signature, config)
34
- signature.each do |key, options|
35
- next unless signature[key][:required]
36
- value = config.send(key)
37
- types = Array(options[:type])
33
+ def validate_types_and_values!(signature, config)
34
+ signature.each do |key, options|
35
+ next unless signature[key][:required]
36
+ value = config.send(key)
37
+ types = Array(options[:type])
38
38
 
39
- unless types.any? { |type| value.is_a?(type) }
40
- raise_error("#{key} must be of type(s) #{types.join(', ')}, but got #{value.class}.")
41
- end
42
-
43
- if options[:type] == ActiveSupport::Duration && value <= 0
44
- raise_error("#{key} must be a positive duration, but got #{value}.")
45
- end
39
+ unless types.any? { |type| value.is_a?(type) }
40
+ raise_error("#{key} must be of type(s) #{types.join(', ')}, but got #{value.class}.")
41
+ end
46
42
 
47
- if options[:type] == Numeric && value < 0
48
- raise_error("#{key} must be a non-negative numeric value, but got #{value}.")
49
- end
43
+ if options[:type] == ActiveSupport::Duration && value <= 0
44
+ raise_error("#{key} must be a positive duration, but got #{value}.")
45
+ end
50
46
 
51
- if options[:allowed_values] && options[:allowed_values].exclude?(value)
52
- raise_error("#{key} must be one of #{options[:allowed_values].join(', ')}, but got #{value}.")
53
- end
47
+ if options[:type] == Numeric && value < 0
48
+ raise_error("#{key} must be a non-negative numeric value, but got #{value}.")
54
49
  end
55
- end
56
50
 
57
- def validate_password_lengths!(config)
58
- if config.password_min_length > config.password_max_length
59
- raise_error("password_min_length cannot be greater than password_max_length.")
51
+ if options[:allowed_values] && options[:allowed_values].exclude?(value)
52
+ raise_error("#{key} must be one of #{options[:allowed_values].join(', ')}, but got #{value}.")
60
53
  end
61
54
  end
55
+ end
62
56
 
63
- def raise_error(msg)
64
- Securial.logger.fatal msg
65
- raise Securial::Error::Config::InvalidConfigurationError, msg
57
+ def validate_password_lengths!(config)
58
+ if config.password_min_length > config.password_max_length
59
+ raise_error("password_min_length cannot be greater than password_max_length.")
66
60
  end
67
61
  end
62
+
63
+ def raise_error(msg)
64
+ Securial.logger.fatal msg
65
+ raise Securial::Error::Config::InvalidConfigurationError, msg
66
+ end
68
67
  end
69
68
  end
70
69
  end