securial 0.4.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 (80) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +90 -0
  4. data/Rakefile +8 -0
  5. data/app/controllers/concerns/securial/identity.rb +67 -0
  6. data/app/controllers/securial/accounts_controller.rb +60 -0
  7. data/app/controllers/securial/application_controller.rb +18 -0
  8. data/app/controllers/securial/passwords_controller.rb +35 -0
  9. data/app/controllers/securial/role_assignments_controller.rb +49 -0
  10. data/app/controllers/securial/roles_controller.rb +44 -0
  11. data/app/controllers/securial/sessions_controller.rb +76 -0
  12. data/app/controllers/securial/status_controller.rb +9 -0
  13. data/app/controllers/securial/users_controller.rb +53 -0
  14. data/app/jobs/securial/application_job.rb +4 -0
  15. data/app/mailers/securial/application_mailer.rb +6 -0
  16. data/app/mailers/securial/securial_mailer.rb +17 -0
  17. data/app/models/concerns/securial/password_resettable.rb +47 -0
  18. data/app/models/securial/application_record.rb +18 -0
  19. data/app/models/securial/current.rb +6 -0
  20. data/app/models/securial/role.rb +10 -0
  21. data/app/models/securial/role_assignment.rb +6 -0
  22. data/app/models/securial/session.rb +27 -0
  23. data/app/models/securial/user.rb +54 -0
  24. data/app/views/layouts/securial/mailer.html.erb +13 -0
  25. data/app/views/layouts/securial/mailer.text.erb +1 -0
  26. data/app/views/securial/accounts/show.json.jbuilder +1 -0
  27. data/app/views/securial/passwords/_password.json.jbuilder +2 -0
  28. data/app/views/securial/passwords/index.json.jbuilder +1 -0
  29. data/app/views/securial/passwords/show.json.jbuilder +1 -0
  30. data/app/views/securial/role_assignments/show.json.jbuilder +1 -0
  31. data/app/views/securial/roles/_securial_role.json.jbuilder +9 -0
  32. data/app/views/securial/roles/index.json.jbuilder +6 -0
  33. data/app/views/securial/roles/show.json.jbuilder +1 -0
  34. data/app/views/securial/securial_mailer/reset_password.html.erb +5 -0
  35. data/app/views/securial/securial_mailer/reset_password.text.erb +4 -0
  36. data/app/views/securial/sessions/_session.json.jbuilder +15 -0
  37. data/app/views/securial/sessions/index.json.jbuilder +6 -0
  38. data/app/views/securial/sessions/show.json.jbuilder +1 -0
  39. data/app/views/securial/status/show.json.jbuilder +3 -0
  40. data/app/views/securial/users/_securial_user.json.jbuilder +14 -0
  41. data/app/views/securial/users/index.json.jbuilder +6 -0
  42. data/app/views/securial/users/show.json.jbuilder +1 -0
  43. data/bin/securial +58 -0
  44. data/config/routes.rb +41 -0
  45. data/db/migrate/20250515104930_create_securial_roles.rb +12 -0
  46. data/db/migrate/20250517155521_create_securial_users.rb +18 -0
  47. data/db/migrate/20250518122749_create_securial_role_assignments.rb +10 -0
  48. data/db/migrate/20250519075407_create_securial_sessions.rb +15 -0
  49. data/db/migrate/20250524210207_add_password_reset_fields_to_securial_users.rb +6 -0
  50. data/lib/generators/factory_bot/model/model_generator.rb +31 -0
  51. data/lib/generators/factory_bot/templates/factory.erb +7 -0
  52. data/lib/generators/securial/install/install_generator.rb +37 -0
  53. data/lib/generators/securial/install/templates/securial_initializer.erb +109 -0
  54. data/lib/generators/securial/jbuilder/jbuilder_generator.rb +52 -0
  55. data/lib/generators/securial/jbuilder/templates/_resource.json.erb +10 -0
  56. data/lib/generators/securial/jbuilder/templates/index.json.erb +7 -0
  57. data/lib/generators/securial/jbuilder/templates/show.json.erb +1 -0
  58. data/lib/generators/securial/scaffold/scaffold_generator.rb +146 -0
  59. data/lib/generators/securial/scaffold/templates/controller.erb +44 -0
  60. data/lib/generators/securial/scaffold/templates/request_spec.erb +61 -0
  61. data/lib/generators/securial/scaffold/templates/routes.erb +11 -0
  62. data/lib/generators/securial/scaffold/templates/routing_spec.erb +31 -0
  63. data/lib/securial/configuration.rb +35 -0
  64. data/lib/securial/engine.rb +89 -0
  65. data/lib/securial/errors/config_errors.rb +12 -0
  66. data/lib/securial/errors/session_errors.rb +6 -0
  67. data/lib/securial/factories/securial/role_assignments.rb +6 -0
  68. data/lib/securial/factories/securial/roles.rb +18 -0
  69. data/lib/securial/factories/securial/sessions.rb +12 -0
  70. data/lib/securial/factories/securial/users.rb +17 -0
  71. data/lib/securial/helpers/auth_helper.rb +46 -0
  72. data/lib/securial/helpers/normalizing_helper.rb +17 -0
  73. data/lib/securial/helpers/regex_helper.rb +17 -0
  74. data/lib/securial/logger.rb +71 -0
  75. data/lib/securial/middleware/request_logger_tag.rb +18 -0
  76. data/lib/securial/route_inspector.rb +50 -0
  77. data/lib/securial/version.rb +3 -0
  78. data/lib/securial.rb +94 -0
  79. data/lib/tasks/securial_tasks.rake +4 -0
  80. metadata +435 -0
@@ -0,0 +1,27 @@
1
+ module Securial
2
+ class Session < ApplicationRecord
3
+ belongs_to :user
4
+
5
+ validates :ip_address, presence: true
6
+ validates :user_agent, presence: true
7
+ validates :refresh_token, presence: true
8
+
9
+ def revoke!
10
+ update!(revoked: true)
11
+ end
12
+
13
+ def is_valid_session?
14
+ !revoked && refresh_token_expires_at > Time.current
15
+ end
16
+
17
+ def refresh!
18
+ raise Securial::SessionErrors::SessionRevokedError, "Session is revoked" if revoked
19
+ raise Securial::SessionErrors::SessionExpiredError, "Session is expired" if refresh_token_expires_at < Time.current
20
+
21
+ update!(refresh_token: SecureRandom.hex(64),
22
+ refresh_count: self.refresh_count + 1,
23
+ last_refreshed_at: Time.current,
24
+ refresh_token_expires_at: 1.week.from_now)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,54 @@
1
+ module Securial
2
+ class User < ApplicationRecord
3
+ include Securial::PasswordResettable
4
+
5
+ normalizes :email_address, with: ->(e) { Securial::NormalizingHelper.normalize_email_address(e) }
6
+
7
+ validates :email_address,
8
+ presence: true,
9
+ uniqueness: true,
10
+ length: {
11
+ minimum: 5,
12
+ maximum: 255,
13
+ },
14
+ format: {
15
+ with: Securial::RegexHelper::EMAIL_REGEX,
16
+ message: "must be a valid email address",
17
+ }
18
+
19
+ validates :username,
20
+ presence: true,
21
+ uniqueness: { case_sensitive: false },
22
+ length: { maximum: 20 },
23
+ format: {
24
+ with: Securial::RegexHelper::USERNAME_REGEX,
25
+ message: "can only contain letters, numbers, underscores, and periods, but cannot start with a number or contain consecutive underscores or periods",
26
+ }
27
+
28
+ validates :first_name,
29
+ presence: true,
30
+ length: { maximum: 50 }
31
+ validates :last_name,
32
+ presence: true,
33
+ length: { maximum: 50 }
34
+
35
+ validates :phone,
36
+ length: { maximum: 15 },
37
+ allow_blank: true
38
+ validates :bio,
39
+ length: { maximum: 1000 },
40
+ allow_blank: true
41
+
42
+ has_many :role_assignments, dependent: :destroy
43
+ has_many :roles, through: :role_assignments
44
+
45
+ has_many :sessions, dependent: :destroy
46
+
47
+
48
+ def is_admin?
49
+ titleized_role_name = Securial.configuration.admin_role.to_s.strip.titleize
50
+
51
+ roles.exists?(role_name: titleized_role_name)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <style>
6
+ /* Email styles need to be inline */
7
+ </style>
8
+ </head>
9
+
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -0,0 +1 @@
1
+ json.partial! "securial/users/securial_user", securial_user: @securial_user
@@ -0,0 +1,2 @@
1
+ json.extract! password, :id, :forgot_password, :reset_password, :created_at, :updated_at
2
+ json.url password_url(password, format: :json)
@@ -0,0 +1 @@
1
+ json.array! @passwords, partial: "securial/passwords/password", as: :password
@@ -0,0 +1 @@
1
+ json.partial! "securial/passwords/password", password: @password
@@ -0,0 +1 @@
1
+ json.partial! "securial/users/securial_user", securial_user: @securial_user
@@ -0,0 +1,9 @@
1
+ json.id securial_role.id
2
+
3
+ json.role_name securial_role.role_name
4
+ json.hide_from_profile securial_role.hide_from_profile
5
+
6
+ json.created_at securial_role.created_at
7
+ json.updated_at securial_role.updated_at
8
+
9
+ json.url securial.roles_url(securial_role, format: :json)
@@ -0,0 +1,6 @@
1
+ json.records @securial_roles do |securial_role|
2
+ json.partial! "securial/roles/securial_role", securial_role: securial_role
3
+ end
4
+
5
+ json.count @securial_roles.count
6
+ json.url securial.roles_url(format: :json)
@@ -0,0 +1 @@
1
+ json.partial! "securial/roles/securial_role", securial_role: @securial_role
@@ -0,0 +1,5 @@
1
+ <p>
2
+ You can reset your password within the next <%= Securial.configuration.reset_password_token_expires_in.inspect %>.
3
+ </p>
4
+
5
+ <p>Your password reset token is: <%= @user.reset_password_token %></p>
@@ -0,0 +1,4 @@
1
+ You can reset your password within the next <%= Securial.configuration.reset_password_token_expires_in.inspect %>.
2
+
3
+
4
+ Your password reset token is: <%= @user.reset_password_token %>
@@ -0,0 +1,15 @@
1
+ json.id securial_session.id
2
+
3
+ json.ip_address securial_session.ip_address
4
+ json.user_agent securial_session.user_agent
5
+ json.refresh_count securial_session.refresh_count
6
+ json.refresh_token securial_session.refresh_token
7
+ json.last_refreshed_at securial_session.last_refreshed_at
8
+ json.refresh_token_expires_at securial_session.refresh_token_expires_at
9
+ json.revoked securial_session.revoked
10
+ json.user_id securial_session.user_id
11
+
12
+ json.created_at securial_session.created_at
13
+ json.updated_at securial_session.updated_at
14
+
15
+ json.url "No URL available for this action"
@@ -0,0 +1,6 @@
1
+ json.records @securial_sessions do |securial_session|
2
+ json.partial! "securial/sessions/session", securial_session: securial_session
3
+ end
4
+
5
+ json.count @securial_sessions.count
6
+ json.url "No URL available for this action"
@@ -0,0 +1 @@
1
+ json.partial! "securial/sessions/session", securial_session: @securial_session
@@ -0,0 +1,3 @@
1
+ json.status "ok"
2
+ json.timestamp Time.current
3
+ json.version Securial::VERSION
@@ -0,0 +1,14 @@
1
+ json.id securial_user.id
2
+
3
+ json.first_name securial_user.first_name
4
+ json.last_name securial_user.last_name
5
+ json.phone securial_user.phone
6
+ json.username securial_user.username
7
+ json.bio securial_user.bio
8
+
9
+ json.roles securial_user.roles, partial: "securial/roles/securial_role", as: :securial_role
10
+
11
+ json.created_at securial_user.created_at
12
+ json.updated_at securial_user.updated_at
13
+
14
+ json.url securial.user_url(securial_user, format: :json)
@@ -0,0 +1,6 @@
1
+ json.records @securial_users do |securial_user|
2
+ json.partial! "securial/users/securial_user", securial_user: securial_user
3
+ end
4
+
5
+ json.count @securial_users.count
6
+ json.url securial.users_url(format: :json)
@@ -0,0 +1 @@
1
+ json.partial! "securial/users/securial_user", securial_user: @securial_user
data/bin/securial ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "fileutils"
4
+
5
+ def run(command, chdir: nil)
6
+ puts "→ #{command}"
7
+ if chdir
8
+ Dir.chdir(chdir) do
9
+ system(command) || abort("❌ Command failed: #{command}")
10
+ end
11
+ else
12
+ system(command) || abort("❌ Command failed: #{command}")
13
+ end
14
+ end
15
+
16
+
17
+ def securial_new(app_name, rails_options)
18
+ puts "🛠 Creating new Rails app: #{app_name}"
19
+
20
+ # Step 1: Forward options to `rails new`
21
+ rails_command = ["rails", "new", app_name, *rails_options].join(" ")
22
+ run(rails_command)
23
+
24
+ # Step 2: Append securial gem to the Gemfile
25
+ gemfile_path = File.join(app_name, "Gemfile")
26
+ File.open(gemfile_path, "a") do |f|
27
+ f.puts "\ngem 'securial'"
28
+ end
29
+
30
+ # Step 3: Install gems
31
+ run("bundle install", chdir: app_name)
32
+
33
+ # Step 4: Install securial
34
+ run("bin/rails generate securial:install", chdir: app_name)
35
+ run("bin/rails db:migrate", chdir: app_name)
36
+
37
+ # Step 5: Mount the engine
38
+ routes_path = File.join(app_name, "config/routes.rb")
39
+ routes = File.read(routes_path)
40
+ updated = routes.sub("Rails.application.routes.draw do") do |match|
41
+ "#{match}\n mount Securial::Engine => '/securial'"
42
+ end
43
+ File.write(routes_path, updated)
44
+
45
+ puts "\n✅ Done! Your app is ready at: ./#{app_name}"
46
+ puts "➡️ Next steps:"
47
+ puts " cd #{app_name}"
48
+ puts " rails server"
49
+ end
50
+
51
+ if ARGV[0] == "new" && ARGV[1]
52
+ app_name = ARGV[1]
53
+ rails_options = ARGV[2..] || []
54
+ securial_new(app_name, rails_options)
55
+ else
56
+ puts "Usage: securial new app_name [rails_options...]"
57
+ puts "Example: securial new myapp --api --database=postgresql"
58
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,41 @@
1
+ Securial::Engine.routes.draw do
2
+ defaults format: :json do
3
+ get "/status", to: "status#show", as: :status
4
+
5
+ scope Securial.admin_namespace do
6
+ resources :roles
7
+ resources :users
8
+ namespace :role_assignments, as: "role_assignments" do
9
+ post "assign", action: :create, as: "assign"
10
+ delete "revoke", action: :destroy, as: "revoke"
11
+ end
12
+ end
13
+
14
+ scope "accounts" do
15
+ get "me", to: "accounts#me", as: :me
16
+ get "account/:username", to: "accounts#show", as: :account_by_username
17
+ post "register", to: "accounts#register", as: :register
18
+ put "update", to: "accounts#update_profile", as: :update_profile
19
+ # post "update_avatar", to: "accounts#update_avatar"
20
+ # post "update_notification_settings", to: "accounts#update_notification_settings"
21
+ delete "delete_account", to: "accounts#delete_account", as: :delete_account
22
+ end
23
+
24
+ scope "sessions" do
25
+ get "", to: "sessions#index", as: :index_sessions
26
+ get "current", to: "sessions#show", as: :current_session
27
+ get "id/:id", to: "sessions#show", as: :session
28
+ post "login", to: "sessions#login", as: :login
29
+ delete "logout", to: "sessions#logout", as: :logout
30
+ put "refresh", to: "sessions#refresh", as: :refresh_session
31
+ delete "revoke", to: "sessions#revoke", as: :revoke_current_session
32
+ delete "id/:id/revoke", to: "sessions#revoke", as: :revoke_session_by_id
33
+ delete "revoke_all", to: "sessions#revoke_all", as: :revoke_all_sessions
34
+ end
35
+
36
+ scope "password" do
37
+ post "forgot", to: "passwords#forgot_password", as: :forgot_password
38
+ put "reset", to: "passwords#reset_password", as: :reset_password
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,12 @@
1
+ class CreateSecurialRoles < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :securial_roles, id: :string do |t|
4
+ t.string :role_name
5
+ t.boolean :hide_from_profile, default: false, null: false
6
+
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :securial_roles, :role_name, unique: true
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ class CreateSecurialUsers < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :securial_users, id: :string do |t|
4
+ t.string :email_address
5
+ t.string :password_digest
6
+ t.string :first_name
7
+ t.string :last_name
8
+ t.string :phone
9
+ t.string :username
10
+ t.string :bio
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ add_index :securial_users, :email_address, unique: true
16
+ add_index :securial_users, :username, unique: true
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ class CreateSecurialRoleAssignments < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :securial_role_assignments, id: :string do |t|
4
+ t.references :user, null: false, type: :string, foreign_key: { to_table: :securial_users }
5
+ t.references :role, null: false, type: :string, foreign_key: { to_table: :securial_roles }
6
+
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ class CreateSecurialSessions < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :securial_sessions, id: :string do |t|
4
+ t.references :user, null: false, type: :string, foreign_key: { to_table: :securial_users }
5
+ t.string :ip_address, null: false
6
+ t.string :user_agent, null: false
7
+ t.string :refresh_token, null: false
8
+ t.integer :refresh_count, default: 0
9
+ t.datetime :last_refreshed_at
10
+ t.datetime :refresh_token_expires_at
11
+ t.boolean :revoked, default: false, null: false
12
+ t.timestamps
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ class AddPasswordResetFieldsToSecurialUsers < ActiveRecord::Migration[8.0]
2
+ def change
3
+ add_column :securial_users, :reset_password_token, :string
4
+ add_column :securial_users, :reset_password_token_created_at, :datetime
5
+ end
6
+ end
@@ -0,0 +1,31 @@
1
+ require "rails/generators"
2
+ require "rails/generators/named_base"
3
+
4
+ module FactoryBot
5
+ module Generators
6
+ class ModelGenerator < Rails::Generators::NamedBase
7
+ source_root File.expand_path("../templates", __dir__)
8
+
9
+ argument :attributes, type: :array, default: [], banner: "field[:type] field[:type]"
10
+
11
+ def create_factory_file
12
+ template "factory.erb", File.join("lib/securial/factories/securial", "#{file_name.pluralize}.rb")
13
+ end
14
+
15
+ # Helper method accessible in the template
16
+ def securial_attribute_defaults
17
+ {
18
+ string: '"MyString"',
19
+ text: '"MyText"',
20
+ integer: "1",
21
+ float: "1.5",
22
+ decimal: '"9.99"',
23
+ datetime: "Time.zone.now",
24
+ time: "Time.zone.now",
25
+ date: "Time.zone.now",
26
+ boolean: "false",
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ FactoryBot.define do
2
+ factory :<%= "securial_#{file_name}" %>, class: "Securial::<%= class_name %>" do
3
+ <% attributes.each do |attribute| -%>
4
+ <%= attribute.name %> { <%= securial_attribute_defaults[attribute.type.to_sym] || 'nil' %> }
5
+ <% end -%>
6
+ end
7
+ end
@@ -0,0 +1,37 @@
1
+ require "rails/generators"
2
+ require "rake"
3
+
4
+ module Securial
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ source_root File.expand_path("templates", __dir__)
8
+
9
+ desc "initializes Securial in your application."
10
+
11
+ def copy_initializer
12
+ say_status("copying", "Securial Initializers", :green)
13
+ template "securial_initializer.erb", "config/initializers/securial.rb"
14
+ end
15
+
16
+ def create_log_file
17
+ say_status("creating", "Securial Log file", :green)
18
+ log_dir = Rails.root.join("log")
19
+ securial_log = log_dir.join("securial.log")
20
+
21
+ FileUtils.mkdir_p(log_dir) unless File.directory?(log_dir)
22
+ FileUtils.touch(securial_log) unless File.exist?(securial_log)
23
+ end
24
+
25
+ def install_migrations
26
+ say_status("copying", "Securial migrations", :green)
27
+ Rails.application.load_tasks unless Rake::Task.task_defined?("securial:install:migrations")
28
+
29
+ should_not_invoke = Rails.root.to_s.include?("spec/dummy") ||
30
+ Rails.root.to_s.include?("tmp") ||
31
+ Rails.env.test?
32
+
33
+ Rake::Task["securial:install:migrations"].invoke unless should_not_invoke
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,109 @@
1
+ # This file was generated by the Securial engine.
2
+
3
+ Securial.configure do |config|
4
+ ##### Logging Configuration
5
+ ## Enable or disable logging to file
6
+ # Set to true to log to a file, false to disable file logging
7
+ config.log_to_file = true
8
+
9
+ ## Enable or disable logging to STDOUT
10
+ # Set to true to log to STDOUT, false to disable STDOUT logging
11
+ config.log_to_stdout = true # Enable or disable logging to STDOUT
12
+
13
+ # Set log level for file logger: :debug, :info, :warn, :error, :fatal, or :unknown
14
+ config.log_file_level = :info
15
+
16
+ # Set log level for stdout logger
17
+ config.log_stdout_level = :info
18
+
19
+ ##### User Roles
20
+ ## Set the role for admin users
21
+ # This role is used to determine access levels and permissions
22
+ # for different user types in the application. including access
23
+ # to specific features and actions.
24
+ # e.g. if the admin role is set to :superuser, then users with this role
25
+ # will have access to the admin dashboard and other admin features.
26
+ # in the `/securial/superusers` namespace.
27
+ config.admin_role = :admin
28
+
29
+ #### Session Configuration
30
+ ## Set the session expiration duration
31
+ # This is the time after which a session will be considered expired.
32
+ # After this time, the session will be invalidated and the user
33
+ # will need to log in again to refresh the session.
34
+ # The expiration time is set in seconds, minutes, or hours.
35
+ # The default is 3 minutes.
36
+ config.session_expiration_duration = 3.minutes
37
+
38
+ ## Set the session renewal duration
39
+ # This is the time after which a session will be renewed.
40
+ # After this time, the session will be renewed and the expiration
41
+ # time will be extended. This is useful for keeping users logged in
42
+ # without requiring them to log in again. The renewal time is set
43
+ # in seconds, minutes, or hours. The default is 3 days.
44
+ config.session_renewal_duration = 3.days
45
+
46
+ ## Set the session secret
47
+ # This secret is used to sign the session tokens and ensure
48
+ # that they cannot be tampered with. It is important to keep this
49
+ # secret secure and not share it with anyone.
50
+ # The default is "secret".
51
+ config.session_secret = "secret"
52
+
53
+ ## Set the session algorithm
54
+ # This is the algorithm used to sign the session tokens.
55
+ # The default is :hs256, which is a HMAC SHA-256 algorithm.
56
+ # Other options include :hs256, :hs384, and :hs512
57
+ config.session_algorithm = :hs256
58
+
59
+ #### Securial Mailer Configuration
60
+ ## Set the mailer sender address
61
+ # This is the email address that will be used as the sender
62
+ # for all emails sent by the Securial engine. This includes
63
+ # emails for password resets, account verification, and other
64
+ # notifications.
65
+ config.mailer_sender = "no-reply@example.com"
66
+
67
+ #### Password configuration
68
+ ## Set the password reset email subject
69
+ # This is the subject line that will be used for the password reset
70
+ # email. The default is "Password Reset Instructions".
71
+ config.password_reset_email_subject = "Password Reset Instructions"
72
+
73
+ ## Set the minimum password length
74
+ # This is the minimum length that a password must have
75
+ # in order to be considered valid. The default is 8 characters.
76
+ config.password_min_length = 8
77
+
78
+ ## Set the maximum password length
79
+ # This is the maximum length that a password can have
80
+ # in order to be considered valid. The default is 128 characters.
81
+ config.password_max_length = 128
82
+
83
+ ## Set the password complexity requirements
84
+ # This is a regular expression that defines the complexity
85
+ # requirements for a password. The default is a regex that
86
+ # requires at least one uppercase letter, one lowercase letter,
87
+ # one digit, and one special character.
88
+ config.password_complexity = Securial::RegexHelper::PASSWORD_REGEX
89
+
90
+ ## Set the password expiration duration
91
+ # This is the time after which a password will be considered expired.
92
+ # After this time, the user will need to change their password
93
+ # in order to log in again. The expiration time is set in seconds,
94
+ # minutes, or hours. The default is 90 days.
95
+ config.password_expires_in = 90.days
96
+
97
+ ## Set the password reset token expiration duration
98
+ # This is the time after which a password reset token will be considered expired.
99
+ # After this time, the token will no longer be valid and the user
100
+ # will need to request a new password reset token. The expiration time
101
+ # is set in seconds, minutes, or hours. The default is 2 hours.
102
+ config.reset_password_token_expires_in = 2.hours
103
+
104
+ ## Set the password reset token secret
105
+ # This secret is used to sign the password reset tokens and ensure
106
+ # that they cannot be tampered with. It is important to keep this
107
+ # secret secure and not share it with anyone.
108
+ config.reset_password_token_secret = "reset_secret"
109
+ end
@@ -0,0 +1,52 @@
1
+ module Securial
2
+ module Generators
3
+ class JbuilderGenerator < Rails::Generators::NamedBase
4
+ source_root File.expand_path("templates", __dir__)
5
+
6
+ argument :attributes, type: :array, default: [], banner: "field:type field:type"
7
+
8
+ def create_view_files
9
+ create_resource_file
10
+ create_index_file
11
+ create_show_file
12
+ end
13
+
14
+ private
15
+
16
+ def attributes_names
17
+ attributes.map(&:name)
18
+ end
19
+
20
+ def create_resource_file
21
+ @resource_path_name = File.join(view_path, "_#{singular_table_name}.json.jbuilder")
22
+ say_status(status_behavior, " #{@resource_path_name}", status_color) unless Rails.env.test?
23
+ template "_resource.json.erb", @resource_path_name, verbose: false
24
+ end
25
+
26
+ def create_index_file
27
+ @index_path_name = File.join(view_path, "index.json.jbuilder")
28
+ say_status(status_behavior, " #{@index_path_name}", status_color) unless Rails.env.test?
29
+ template "index.json.erb", @index_path_name, verbose: false
30
+ end
31
+
32
+ def create_show_file
33
+ @show_path_name = File.join(view_path, "show.json.jbuilder")
34
+ say_status(status_behavior, " #{@show_path_name}", status_color) unless Rails.env.test?
35
+ template "show.json.erb", @show_path_name, verbose: false
36
+ end
37
+
38
+ def view_path
39
+ base_path = Rails.env.test? ? Rails.root.join("tmp/app/views/securial").to_s : "app/views/securial"
40
+ @view_path ||= File.join(base_path, name.pluralize.downcase)
41
+ end
42
+
43
+ def status_behavior
44
+ behavior == :invoke ? :create : :remove
45
+ end
46
+
47
+ def status_color
48
+ behavior == :invoke ? :green : :red
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,10 @@
1
+ json.id <%= singular_table_name %>.id
2
+
3
+ <% attributes_names.each do |attr| -%>
4
+ json.<%= attr %> <%= singular_table_name %>.<%= attr %>
5
+ <% end -%>
6
+
7
+ json.created_at <%= singular_table_name %>.created_at
8
+ json.updated_at <%= singular_table_name %>.updated_at
9
+
10
+ json.url securial.<%= name.pluralize.downcase %>_url(<%= singular_table_name %>, format: :json)
@@ -0,0 +1,7 @@
1
+ json.records @<%= plural_table_name %> do |<%= singular_table_name %>|
2
+ json.partial! "securial/<%= name.pluralize.downcase %>/<%= singular_table_name %>", <%= singular_table_name %>: <%= singular_table_name %>
3
+ end
4
+
5
+ json.count @<%= plural_table_name %>.count
6
+ json.url securial.<%= name.pluralize.downcase %>_url(format: :json)
7
+
@@ -0,0 +1 @@
1
+ json.partial! "securial/<%= name.pluralize.downcase %>/<%= singular_table_name %>", <%= singular_table_name %>: @<%= singular_table_name %>