securial 0.8.1 → 1.0.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.
- checksums.yaml +4 -4
- data/README.md +14 -16
- data/app/controllers/concerns/securial/identity.rb +18 -9
- data/app/controllers/securial/status_controller.rb +2 -0
- data/app/controllers/securial/users_controller.rb +1 -1
- data/app/views/securial/status/show.json.jbuilder +1 -1
- data/bin/securial +20 -52
- data/db/migrate/20250606182648_seed_roles_and_users.rb +69 -0
- data/lib/generators/securial/install/templates/securial_initializer.erb +115 -18
- data/lib/securial/cli/run.rb +11 -0
- data/lib/securial/cli/securial_new.rb +53 -0
- data/lib/securial/cli/show_help.rb +26 -0
- data/lib/securial/cli/show_version.rb +9 -0
- data/lib/securial/config/configuration.rb +3 -53
- data/lib/securial/config/signature.rb +107 -0
- data/lib/securial/config/validation.rb +58 -14
- data/lib/securial/config.rb +2 -0
- data/lib/securial/engine.rb +2 -0
- data/lib/securial/engine_initializers.rb +21 -2
- data/lib/securial/error/config.rb +0 -28
- data/lib/securial/helpers/key_transformer.rb +33 -0
- data/lib/securial/helpers.rb +1 -0
- data/lib/securial/middleware/response_headers.rb +19 -0
- data/lib/securial/middleware/transform_request_keys.rb +35 -0
- data/lib/securial/middleware/transform_response_keys.rb +47 -0
- data/lib/securial/middleware.rb +3 -0
- data/lib/securial/security/request_rate_limiter.rb +45 -0
- data/lib/securial/security.rb +8 -0
- data/lib/securial/version.rb +1 -1
- data/lib/tasks/securial_routes.rake +26 -0
- metadata +44 -19
- data/lib/securial/config/validation/logger_validation.rb +0 -29
- data/lib/securial/config/validation/mailer_validation.rb +0 -24
- data/lib/securial/config/validation/password_validation.rb +0 -91
- data/lib/securial/config/validation/response_validation.rb +0 -37
- data/lib/securial/config/validation/roles_validation.rb +0 -32
- data/lib/securial/config/validation/security_validation.rb +0 -56
- data/lib/securial/config/validation/session_validation.rb +0 -87
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d6f0817d44bf16fef31a683152d11e38a0671a92f966df31257f8ab9b867c92
|
4
|
+
data.tar.gz: ec7aa78f714a20598db55ecf92d69dc17d7dd38a137cce3964d8677ec622a46a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9435fcba0cb665df4992f193f0a8c0012f3dc676619a20b8824cdd085803337290c2453bf10494ef348d46259d0f1f9da48224abb1e70783c0f67e5e33deff2c
|
7
|
+
data.tar.gz: 658cca7386b481757396384957d203f35abfb2f72ea56e7c538ea3f355014068e4921f7b4ba03967caa9563b5d3d4d32a1d4bf0257a0676e413bb2a1a394fbfd
|
data/README.md
CHANGED
@@ -8,26 +8,21 @@
|
|
8
8
|
[
|
9
9
|
](https://coveralls.io/github/AlyBadawy/Securial?branch=main)
|
10
10
|
|
11
|
-
> [!WARNING]
|
12
|
-
>
|
13
|
-
> **Securial is currently in active development (major version zero).**
|
14
|
-
>
|
15
|
-
> While the gem is functional and versioned, it is not yet considered stable. Until v1.0.0 is released, any updates may introduce breaking changes as the API and features continue to evolve. If you plan to use Securial in production, please do so with caution and pin a specific version.
|
16
|
-
>
|
17
|
-
> You can track the roadmap and remaining tasks for the v1.0.0 release in [this GitHub issue](https://github.com/AlyBadawy/Securial/issues/64).
|
18
|
-
|
19
11
|
---
|
20
12
|
|
13
|
+
### 🛡️ What is Securial?
|
14
|
+
|
21
15
|
**Securial** is a mountable Rails engine that provides robust, extensible authentication and access control for Rails applications. It supports:
|
22
16
|
|
23
|
-
-
|
24
|
-
-
|
25
|
-
-
|
26
|
-
-
|
27
|
-
-
|
28
|
-
-
|
17
|
+
- 🟦 JWT-based authentication
|
18
|
+
- 🟦 API tokens
|
19
|
+
- 🟦 Session-based auth
|
20
|
+
- 🟦 Simple integration with web and mobile apps
|
21
|
+
- 🟦 Clean, JSON-based API responses
|
22
|
+
- 🟦 Simple user management with roles
|
23
|
+
- 🟦 Database-agnostic support
|
29
24
|
|
30
|
-
###
|
25
|
+
### 👀 Why Securial?
|
31
26
|
|
32
27
|
Securial was built to offer a clean, modular, and API-first authentication system for Rails developers who want full control without the black-box complexity. Whether you're building for the web, mobile, or both, Securial gives you the flexibility to implement exactly what you need — from simple JWT authentication to more advanced setups involving sessions, API tokens, and role-based access.
|
33
28
|
|
@@ -48,6 +43,8 @@ To add Securial to an existing Rails app:
|
|
48
43
|
```ruby
|
49
44
|
Rails.application.routes.draw do
|
50
45
|
mount Securial::Engine => "/securial"
|
46
|
+
|
47
|
+
# The rest of your routes
|
51
48
|
end
|
52
49
|
```
|
53
50
|
- Run the migrations by running the command: `rails db:migrate`
|
@@ -120,4 +117,5 @@ The gem is available as open source under the terms of the [MIT license](https:/
|
|
120
117
|
|
121
118
|
---
|
122
119
|
|
123
|
-
|
120
|
+
\
|
121
|
+

|
@@ -3,6 +3,7 @@ module Securial
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
+
before_action :identify_user
|
6
7
|
before_action :authenticate_user!
|
7
8
|
helper_method :current_user if respond_to?(:helper_method)
|
8
9
|
end
|
@@ -13,20 +14,24 @@ module Securial
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
|
-
def authenticate_admin!
|
17
|
-
authenticate_user!
|
18
|
-
return if current_user.blank? || current_user.is_admin?
|
19
|
-
|
20
|
-
render status: :forbidden, json: { error: "You are not authorized to perform this action" }
|
21
|
-
end
|
22
17
|
|
23
18
|
def current_user
|
24
19
|
Current.session&.user
|
25
20
|
end
|
26
21
|
|
22
|
+
def authenticate_admin!
|
23
|
+
if current_user
|
24
|
+
return if current_user.is_admin?
|
25
|
+
|
26
|
+
render status: :forbidden, json: { error: "You are not authorized to perform this action" }
|
27
|
+
else
|
28
|
+
authenticate_user!
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
27
32
|
private
|
28
33
|
|
29
|
-
def
|
34
|
+
def identify_user
|
30
35
|
return if internal_rails_request?
|
31
36
|
|
32
37
|
Current.session = nil
|
@@ -41,13 +46,17 @@ module Securial
|
|
41
46
|
session.ip_address == request.remote_ip &&
|
42
47
|
session.user_agent == request.user_agent
|
43
48
|
Current.session = session
|
44
|
-
return # Authenticated
|
45
49
|
end
|
46
50
|
rescue Securial::Error::Auth::TokenDecodeError, ActiveRecord::RecordNotFound => e
|
47
51
|
Securial.logger.debug "Authentication failed: #{e.message}"
|
48
52
|
end
|
49
53
|
end
|
50
|
-
|
54
|
+
end
|
55
|
+
|
56
|
+
def authenticate_user!
|
57
|
+
return if internal_rails_request?
|
58
|
+
return if Current.session&.user
|
59
|
+
|
51
60
|
render status: :unauthorized, json: { error: "You are not signed in" } and return
|
52
61
|
end
|
53
62
|
|
data/bin/securial
CHANGED
@@ -1,58 +1,26 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "fileutils"
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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"
|
8
|
+
|
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)
|
11
19
|
else
|
12
|
-
|
13
|
-
|
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'"
|
20
|
+
show_help
|
21
|
+
exit(1)
|
28
22
|
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
23
|
else
|
56
|
-
|
57
|
-
|
58
|
-
end
|
24
|
+
show_help
|
25
|
+
exit(1)
|
26
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class SeedRolesAndUsers < ActiveRecord::Migration[8.0]
|
2
|
+
def up
|
3
|
+
default_email = "user@example.com"
|
4
|
+
default_password = "Password123!"
|
5
|
+
|
6
|
+
default_admin_role = Securial.configuration.admin_role
|
7
|
+
|
8
|
+
# Create a default user (no roles assigned)
|
9
|
+
Securial::User.find_or_create_by!(email_address: default_email) do |user|
|
10
|
+
user.password = default_password
|
11
|
+
user.password_confirmation = default_password
|
12
|
+
user.username = "default_user"
|
13
|
+
user.first_name = "Default"
|
14
|
+
user.last_name = "User"
|
15
|
+
end
|
16
|
+
Securial.logger.debug "Created user: #{default_email} with password: #{default_password}"
|
17
|
+
|
18
|
+
# Default roles
|
19
|
+
roles = %w[admin moderator support locked]
|
20
|
+
roles << default_admin_role
|
21
|
+
roles.uniq!
|
22
|
+
|
23
|
+
roles.each do |role_name|
|
24
|
+
# Create roles if they do not exist
|
25
|
+
Securial::Role.find_or_create_by!(role_name: role_name)
|
26
|
+
Securial.logger.debug "Created role: #{role_name}"
|
27
|
+
|
28
|
+
# Create a user for each role
|
29
|
+
user = Securial::User.find_or_create_by!(email_address: "#{role_name}@example.com") do |u|
|
30
|
+
u.password = "Password123!"
|
31
|
+
u.password_confirmation = "Password123!"
|
32
|
+
u.username = role_name
|
33
|
+
u.first_name = role_name.capitalize
|
34
|
+
u.last_name = "User"
|
35
|
+
end
|
36
|
+
|
37
|
+
Securial.logger.debug "Created user: #{user.email_address} with password: #{default_password}"
|
38
|
+
|
39
|
+
# Assign the role to the user
|
40
|
+
user.roles = Securial::Role.where(role_name: role_name)
|
41
|
+
Securial.logger.debug "Assigned role: #{role_name} to user: #{user.email_address}"
|
42
|
+
user.save!
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def down
|
47
|
+
default_admin_role = Securial.configuration.admin_role
|
48
|
+
roles = %w[admin moderator support locked]
|
49
|
+
roles << default_admin_role
|
50
|
+
roles.uniq!
|
51
|
+
|
52
|
+
# Remove role-specific users
|
53
|
+
roles.each do |role_name|
|
54
|
+
user = Securial::User.find_by(email_address: "#{role_name}@example.com")
|
55
|
+
user.destroy if user
|
56
|
+
Securial.logger.debug "Removed user: #{role_name}@example.com"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Remove the default user with no roles
|
60
|
+
user = Securial::User.find_by(email_address: "user@example.com")
|
61
|
+
user.destroy if user
|
62
|
+
Securial.logger.debug "Removed user: user@example.com"
|
63
|
+
|
64
|
+
|
65
|
+
# Remove the roles themselves
|
66
|
+
Securial::Role.where(role_name: roles).destroy_all
|
67
|
+
Securial.logger.debug "Removed roles: #{roles.join(', ')}"
|
68
|
+
end
|
69
|
+
end
|
@@ -1,6 +1,11 @@
|
|
1
1
|
# This file was generated by the Securial engine.
|
2
2
|
|
3
3
|
Securial.configure do |config|
|
4
|
+
##### General Configuration
|
5
|
+
## The name of your application (used in notifications, etc.)
|
6
|
+
# Default: "Securial"
|
7
|
+
config.app_name = "Securial"
|
8
|
+
|
4
9
|
##### Logging Configuration
|
5
10
|
## Enable or disable logging to file
|
6
11
|
# Set to true to log to a file, false to disable file logging
|
@@ -28,9 +33,9 @@ Securial.configure do |config|
|
|
28
33
|
|
29
34
|
##### Session Configuration
|
30
35
|
## Set the session expiration duration
|
31
|
-
# This is the time after which
|
32
|
-
# After this time, the
|
33
|
-
#
|
36
|
+
# This is the time after which an access session will be considered expired.
|
37
|
+
# After this time, the user must use the refresh token to obtain a new session.
|
38
|
+
# The user only needs to log in again if the refresh token has also expired.
|
34
39
|
# The expiration time is set in seconds, minutes, or hours.
|
35
40
|
# The default is 3 minutes.
|
36
41
|
config.session_expiration_duration = 3.minutes
|
@@ -39,6 +44,17 @@ Securial.configure do |config|
|
|
39
44
|
# This secret is used to sign the session tokens and ensure
|
40
45
|
# that they cannot be tampered with. It is important to keep this
|
41
46
|
# secret secure and not share it with anyone.
|
47
|
+
# It should be a long, random string to ensure security.
|
48
|
+
# You can generate a secure secret using a tool like `SecureRandom.hex(64)`
|
49
|
+
# or `SecureRandom.base64(64)`.
|
50
|
+
# It is recommended to change this secret periodically for security reasons.
|
51
|
+
# If you change this secret, all existing sessions will be invalidated,
|
52
|
+
# and users will need to log in again.
|
53
|
+
# Make sure to keep this secret safe and do not expose it in your codebase.
|
54
|
+
# You can use environment variables to store this secret securely.
|
55
|
+
# For example, you can set an environment variable `SECURIAL_SESSION_SECRET`
|
56
|
+
# and then use it in your configuration like this:
|
57
|
+
# config.session_secret = ENV['SECURIAL_SESSION_SECRET']
|
42
58
|
# The default is "secret".
|
43
59
|
config.session_secret = "secret"
|
44
60
|
|
@@ -48,6 +64,20 @@ Securial.configure do |config|
|
|
48
64
|
# Other options include :hs256, :hs384, and :hs512
|
49
65
|
config.session_algorithm = :hs256
|
50
66
|
|
67
|
+
## Set the session refresh token expiration duration
|
68
|
+
# This is the duration after which a refresh token will expire.
|
69
|
+
# Once the refresh token expires, the user must log in again.
|
70
|
+
# The refresh token is used to obtain a new access token without
|
71
|
+
# requiring the user to log in again. It is typically used to keep
|
72
|
+
# the user logged in for a longer period without requiring frequent logins.
|
73
|
+
# The expiration time is set in seconds, minutes, or hours.
|
74
|
+
# The refresh token expiration duration should be longer than the access session
|
75
|
+
# expiration duration to allow the user to obtain a new access token
|
76
|
+
# without having to log in again. This allows for a better user experience
|
77
|
+
# by reducing the frequency of logins while still maintaining security.
|
78
|
+
# The default is 1 week.
|
79
|
+
config.session_refresh_token_expires_in = 1.week
|
80
|
+
|
51
81
|
##### Securial Mailer Configuration
|
52
82
|
## Set the mailer sender address
|
53
83
|
# This is the email address that will be used as the sender
|
@@ -56,12 +86,36 @@ Securial.configure do |config|
|
|
56
86
|
# notifications.
|
57
87
|
config.mailer_sender = "no-reply@example.com"
|
58
88
|
|
59
|
-
|
89
|
+
## Enable or disable sending sign up emails
|
90
|
+
# Set to true to send a welcome email on sign up, false to disable.
|
91
|
+
config.mailer_sign_up_enabled = true
|
92
|
+
|
93
|
+
## Set the subject for sign up emails
|
94
|
+
# The default is "SECURIAL: Welcome to Our Service".
|
95
|
+
config.mailer_sign_up_subject = "SECURIAL: Welcome to Our Service"
|
96
|
+
|
97
|
+
## Enable or disable sending sign in emails
|
98
|
+
# Set to true to send a notification on sign in, false to disable.
|
99
|
+
config.mailer_sign_in_enabled = true
|
100
|
+
|
101
|
+
## Set the subject for sign in emails
|
102
|
+
# The default is "SECURIAL: Sign In Notification".
|
103
|
+
config.mailer_sign_in_subject = "SECURIAL: Sign In Notification"
|
104
|
+
|
105
|
+
## Enable or disable sending update account emails
|
106
|
+
# Set to true to send a notification when an account is updated, false to disable.
|
107
|
+
config.mailer_update_account_enabled = true
|
108
|
+
|
109
|
+
## Set the subject for update account emails
|
110
|
+
# The default is "SECURIAL: Account Update Notification".
|
111
|
+
config.mailer_update_account_subject = "SECURIAL: Account Update Notification"
|
112
|
+
|
60
113
|
## Set the password reset email subject
|
61
114
|
# This is the subject line that will be used for the password reset
|
62
|
-
# email. The default is "Password Reset Instructions".
|
63
|
-
config.mailer_forgot_password_subject = "Password Reset Instructions"
|
115
|
+
# email. The default is "SECURIAL: Password Reset Instructions".
|
116
|
+
config.mailer_forgot_password_subject = "SECURIAL: Password Reset Instructions"
|
64
117
|
|
118
|
+
##### Password configuration
|
65
119
|
## Set the minimum password length
|
66
120
|
# This is the minimum length that a password must have
|
67
121
|
# in order to be considered valid. The default is 8 characters.
|
@@ -73,30 +127,71 @@ Securial.configure do |config|
|
|
73
127
|
config.password_max_length = 128
|
74
128
|
|
75
129
|
## Set the password complexity requirements
|
76
|
-
# This is a regular expression that defines the complexity
|
77
|
-
# requirements for a password.
|
78
|
-
#
|
79
|
-
#
|
130
|
+
# This is a regular expression (RegEx) that defines the complexity
|
131
|
+
# requirements for a password.
|
132
|
+
# The password must match this regex in order to be considered valid.
|
133
|
+
# The regex can include requirements such as:
|
134
|
+
# - At least one uppercase letter
|
135
|
+
# - At least one lowercase letter
|
136
|
+
# - At least one digit
|
137
|
+
# - At least one special character (e.g. !@#$%^&*)
|
138
|
+
# - No whitespace characters
|
139
|
+
# - No common passwords (e.g. "password", "123456", etc.)
|
140
|
+
# You can customize this regex to fit your application's security requirements.
|
141
|
+
# The default is a regex that requires at least one uppercase letter,
|
142
|
+
# one lowercase letter, one digit, and one special character.
|
80
143
|
config.password_complexity = Securial::Helpers::RegexHelper::PASSWORD_REGEX
|
81
144
|
|
145
|
+
## Set whether passwords expire
|
146
|
+
# Set to true if passwords should expire after a period, false to disable expiration.
|
147
|
+
# If password expiration is enabled, users will be required to change
|
148
|
+
# their password after a certain period of time. This is useful for
|
149
|
+
# maintaining security and ensuring that users do not use the same password
|
150
|
+
# for an extended period of time. It is recommended to enable password expiration
|
151
|
+
# to enhance security, especially for applications that handle sensitive data.
|
152
|
+
# The default is true.
|
153
|
+
config.password_expires = true
|
154
|
+
|
82
155
|
## Set the password expiration duration
|
83
|
-
# This is the time after which a password will be considered expired
|
156
|
+
# This is the time after which a password will be considered expired,
|
157
|
+
# but only if password expiration is enabled (`password_expires = true`).
|
84
158
|
# After this time, the user will need to change their password
|
85
159
|
# in order to log in again. The expiration time is set in seconds,
|
86
160
|
# minutes, or hours. The default is 90 days.
|
87
161
|
config.password_expires_in = 90.days
|
88
|
-
|
162
|
+
|
89
163
|
## Set the password reset token expiration duration
|
90
164
|
# This is the time after which a password reset token will be considered expired.
|
91
165
|
# After this time, the token will no longer be valid and the user
|
92
166
|
# will need to request a new password reset token. The expiration time
|
93
|
-
# is set in seconds, minutes, or hours.
|
167
|
+
# is set in seconds, minutes, or hours.
|
168
|
+
# This is useful for ensuring that password reset tokens are not valid indefinitely,
|
169
|
+
# which helps to prevent unauthorized access to user accounts.
|
170
|
+
# It is recommended to set a reasonable expiration time for password reset tokens
|
171
|
+
# to balance security and user experience. A shorter expiration time
|
172
|
+
# can enhance security by reducing the window of opportunity for an attacker
|
173
|
+
# to use a stolen or intercepted token, while a longer expiration time
|
174
|
+
# can improve user experience by allowing users to reset their passwords
|
175
|
+
# without having to request a new token frequently.
|
176
|
+
# The expiration time is set in seconds, minutes, or hours.
|
177
|
+
# The default is 2 hours.
|
94
178
|
config.reset_password_token_expires_in = 2.hours
|
95
179
|
|
96
180
|
## Set the password reset token secret
|
97
181
|
# This secret is used to sign the password reset tokens and ensure
|
98
182
|
# that they cannot be tampered with. It is important to keep this
|
99
183
|
# secret secure and not share it with anyone.
|
184
|
+
# It should be a long, random string to ensure security.
|
185
|
+
# You can generate a secure secret using a tool like `SecureRandom.hex(64)`
|
186
|
+
# or `SecureRandom.base64(64)`.
|
187
|
+
# It is recommended to change this secret periodically for security reasons.
|
188
|
+
# If you change this secret, all existing sessions will be invalidated,
|
189
|
+
# and users will need to log in again.
|
190
|
+
# Make sure to keep this secret safe and do not expose it in your codebase.
|
191
|
+
# You can use environment variables to store this secret securely.
|
192
|
+
# For example, you can set an environment variable `SECURIAL_RESET_PASSWORD_SECRET`
|
193
|
+
# and then use it in your configuration like this:
|
194
|
+
# config.reset_password_token_secret = ENV['SECURIAL_RESET_PASSWORD_SECRET']
|
100
195
|
config.reset_password_token_secret = "reset_secret"
|
101
196
|
|
102
197
|
##### Timestamp Configuration
|
@@ -108,14 +203,14 @@ Securial.configure do |config|
|
|
108
203
|
# for regular users while still providing timestamps for admin users.
|
109
204
|
# :all - the created_at and updated_at timestamps will be included
|
110
205
|
# for all users. This is useful for debugging and development purposes.
|
111
|
-
config.timestamps_in_response =
|
206
|
+
config.timestamps_in_response = :all
|
112
207
|
|
113
208
|
##### Response Configuration
|
114
209
|
## Set the format of the JSON keys in the responses.
|
115
210
|
# The options are:
|
116
211
|
# :snake_case - the keys will be in snake_case format.
|
117
212
|
# :lowerCamelCase - the keys will be in lowerCamelCase format.
|
118
|
-
# :
|
213
|
+
# :UpperCamelCase - the keys will be in UpperCamelCase format.
|
119
214
|
config.response_keys_format = :snake_case
|
120
215
|
|
121
216
|
##### Security Configuration
|
@@ -125,14 +220,17 @@ Securial.configure do |config|
|
|
125
220
|
# :default - the default security headers will be included.
|
126
221
|
# :strict - the strict security headers will be included.
|
127
222
|
config.security_headers = :strict
|
223
|
+
|
128
224
|
## set whether to enable request rate limiting
|
129
225
|
# This is useful for preventing abuse and denial of service attacks.
|
130
226
|
config.rate_limiting_enabled = true
|
227
|
+
|
131
228
|
## Set the rate limit for requests
|
132
229
|
# This is the maximum number of requests that a user can make
|
133
230
|
# in a given time period. The default is 60 requests per minute.
|
134
231
|
# This is only applied if `rate_limiting_enabled` is set to true.
|
135
232
|
config.rate_limit_requests_per_minute = 60
|
233
|
+
|
136
234
|
## Set the rate limit response status code
|
137
235
|
# This is the status code that will be returned when a user exceeds
|
138
236
|
# the rate limit. The status code should be a 4xx or 5xx code
|
@@ -140,11 +238,10 @@ Securial.configure do |config|
|
|
140
238
|
# or 503 Service Unavailable. The default is 429 Too Many Requests.
|
141
239
|
# This is only applied if `rate_limiting_enabled` is set to true.
|
142
240
|
config.rate_limit_response_status = 429
|
241
|
+
|
143
242
|
## Set the rate limit response message
|
144
243
|
# This is the message that will be returned when a user exceeds
|
145
244
|
# the rate limit. The default is "Too many requests, please try again later."
|
146
245
|
# This is only applied if `rate_limiting_enabled` is set to true.
|
147
246
|
config.rate_limit_response_message = "Too many requests, please try again later."
|
148
|
-
|
149
|
-
|
150
|
-
end
|
247
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# rubocop:disable Rails/Output
|
2
|
+
def run(command, chdir: nil)
|
3
|
+
puts "→ #{command}"
|
4
|
+
if chdir
|
5
|
+
Dir.chdir(chdir) do
|
6
|
+
system(command) || abort("❌ Command failed: #{command}")
|
7
|
+
end
|
8
|
+
else
|
9
|
+
system(command) || abort("❌ Command failed: #{command}")
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# rubocop:disable Rails/Output
|
2
|
+
require_relative "run"
|
3
|
+
|
4
|
+
def securial_new(app_name, rails_options)
|
5
|
+
puts "🏗️ Creating new Rails app: #{app_name}"
|
6
|
+
create_rails_app(app_name, rails_options)
|
7
|
+
add_securial_gem(app_name)
|
8
|
+
install_gems(app_name)
|
9
|
+
install_securial(app_name)
|
10
|
+
mount_securial_engine(app_name)
|
11
|
+
print_final_instructions(app_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_rails_app(app_name, rails_options)
|
15
|
+
rails_command = ["rails", "new", app_name, *rails_options].join(" ")
|
16
|
+
run(rails_command)
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_securial_gem(app_name)
|
20
|
+
puts "📦 Adding Securial gem to Gemfile"
|
21
|
+
gemfile_path = File.join(app_name, "Gemfile")
|
22
|
+
File.open(gemfile_path, "a") { |f| f.puts "\ngem 'securial'" }
|
23
|
+
end
|
24
|
+
|
25
|
+
def install_gems(app_name)
|
26
|
+
run("bundle install", chdir: app_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def install_securial(app_name)
|
30
|
+
puts "🔧 Installing Securial"
|
31
|
+
run("bin/rails generate securial:install", chdir: app_name)
|
32
|
+
run("bin/rails db:migrate", chdir: app_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def mount_securial_engine(app_name)
|
36
|
+
puts "🔗 Mounting Securial engine in routes"
|
37
|
+
routes_path = File.join(app_name, "config/routes.rb")
|
38
|
+
routes = File.read(routes_path)
|
39
|
+
updated = routes.sub("Rails.application.routes.draw do") do |match|
|
40
|
+
"#{match}\n mount Securial::Engine => '/securial'"
|
41
|
+
end
|
42
|
+
File.write(routes_path, updated)
|
43
|
+
end
|
44
|
+
|
45
|
+
def print_final_instructions(app_name)
|
46
|
+
puts "🎉 Securial has been successfully installed in your Rails app!"
|
47
|
+
puts "✅ Your app is ready at: ./#{app_name}"
|
48
|
+
puts ""
|
49
|
+
puts "➡️ Next steps:"
|
50
|
+
puts " cd #{app_name}"
|
51
|
+
puts "⚙️ Optional: Configure Securial in config/initializers/securial.rb"
|
52
|
+
puts " rails server"
|
53
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# rubocop:disable Rails/Output
|
2
|
+
def show_help
|
3
|
+
puts <<~HELP
|
4
|
+
Securial CLI
|
5
|
+
|
6
|
+
Securial is a mountable Rails engine that provides robust, extensible
|
7
|
+
authentication and access control for Rails applications. It supports JWT,
|
8
|
+
API tokens, session-based auth, and is designed for easy integration with
|
9
|
+
modern web and mobile apps.
|
10
|
+
|
11
|
+
Usage:
|
12
|
+
securial new APP_NAME [rails_options...] # Create a new Rails app with Securial pre-installed
|
13
|
+
securial -v, --version # Show the Securial gem version
|
14
|
+
securial -h, --help # Show this help message
|
15
|
+
|
16
|
+
Example:
|
17
|
+
securial new myapp --api --database=postgresql -T
|
18
|
+
|
19
|
+
More Info:
|
20
|
+
review the [Changelog] and [WIKI] for more info on the latest
|
21
|
+
changes and how to use this gem/engine:
|
22
|
+
[Changelog]: https://github.com/AlyBadawy/Securial/blob/main/CHANGELOG.md
|
23
|
+
[WIKI]: https://github.com/AlyBadawy/Securial/wiki
|
24
|
+
|
25
|
+
HELP
|
26
|
+
end
|