authentication-zero 2.3.4 → 2.4.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/CHANGELOG.md +5 -1
- data/Gemfile.lock +1 -1
- data/README.md +9 -4
- data/lib/authentication_zero/version.rb +1 -1
- data/lib/generators/authentication/authentication_generator.rb +11 -4
- data/lib/generators/authentication/templates/controllers/api/password_resets_controller.rb.tt +12 -2
- data/lib/generators/authentication/templates/controllers/api/registrations_controller.rb.tt +4 -4
- data/lib/generators/authentication/templates/controllers/api/sessions_controller.rb.tt +4 -4
- data/lib/generators/authentication/templates/controllers/html/password_resets_controller.rb.tt +12 -2
- data/lib/generators/authentication/templates/controllers/html/registrations_controller.rb.tt +3 -3
- data/lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt +3 -3
- data/lib/generators/authentication/templates/mailers/identity_mailer.rb.tt +1 -1
- data/lib/generators/authentication/templates/migrations/create_sessions_migration.rb.tt +1 -1
- data/lib/generators/authentication/templates/models/locking.rb.tt +10 -0
- data/lib/generators/authentication/templates/test_unit/controllers/api/password_resets_controller_test.rb.tt +3 -0
- data/lib/generators/authentication/templates/test_unit/controllers/html/password_resets_controller_test.rb.tt +3 -0
- data/lib/generators/authentication/templates/test_unit/system/password_resets_test.rb.tt +3 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3aaf162f00b6413821ae603869fb83f1cf577f956490821ffa051a6bf3b314ce
|
4
|
+
data.tar.gz: 9d4d1efd1aeddc346f39d4aec8752ec3f4a693e12908ec7c6ebc4cdcc0888684
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 112be1974500241c1e8a78411ba1b1846a7de6ab6a04c81b76963ded1b5150a7f7a12097ba06202210c73446c8404939718d9e7f14d93be3d96a9995235cd56e
|
7
|
+
data.tar.gz: d0d7c2965efdc83e16fcc068c1a1069269a60d68adafc0714291f310e726d90a698f0105752607a747894b683d7e544481b56cad3dee949ca52262f0c34e1250
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -8,13 +8,14 @@ The purpose of authentication zero is to generate a pre-built authentication sys
|
|
8
8
|
- **Inspired by hey.com**
|
9
9
|
- Sign up
|
10
10
|
- Email and password validations
|
11
|
-
- Authentication by cookie
|
12
|
-
- Authentication by token (api)
|
11
|
+
- Authentication by cookie
|
12
|
+
- Authentication by token (--api)
|
13
13
|
- Ask password before sensitive data changes, aka: sudo
|
14
14
|
- Reset the user password and send reset instructions
|
15
15
|
- Reset the user password only from verified emails
|
16
|
-
-
|
17
|
-
- Send
|
16
|
+
- Lock sending reset password email after many attempts (--lockable)
|
17
|
+
- Send e-mail notification when your email has been changed
|
18
|
+
- Send e-mail notification when someone has logged into your account
|
18
19
|
- Manage multiple sessions & devices
|
19
20
|
- Cancel my account
|
20
21
|
- Log out
|
@@ -93,6 +94,10 @@ $ rails generate authentication user
|
|
93
94
|
|
94
95
|
Then run `bundle install` again!
|
95
96
|
|
97
|
+
#### --lockable
|
98
|
+
|
99
|
+
Run `rails kredis:install`, to add a default configuration at `config/redis/shared.yml`.
|
100
|
+
|
96
101
|
## Development
|
97
102
|
|
98
103
|
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
@@ -5,18 +5,24 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
5
5
|
|
6
6
|
class_option :api, type: :boolean, desc: "Generates API authentication"
|
7
7
|
|
8
|
+
class_option :lockable, type: :boolean, desc: "Generates password reset locking"
|
9
|
+
|
10
|
+
class_option :skip_routes, type: :boolean
|
11
|
+
|
8
12
|
class_option :migration, type: :boolean, default: true
|
9
13
|
class_option :test_framework, type: :string, desc: "Test framework to be invoked"
|
10
14
|
|
11
15
|
class_option :fixture, type: :boolean, default: true
|
12
16
|
class_option :system_tests, type: :string, desc: "Skip system test files"
|
13
17
|
|
14
|
-
class_option :skip_routes, type: :boolean
|
18
|
+
class_option :skip_routes, type: :boolean
|
15
19
|
|
16
20
|
source_root File.expand_path("templates", __dir__)
|
17
21
|
|
18
22
|
def add_bcrypt
|
19
|
-
uncomment_lines "Gemfile", /bcrypt/
|
23
|
+
uncomment_lines "Gemfile", /"bcrypt"/
|
24
|
+
uncomment_lines "Gemfile", /"redis"/ if options.lockable
|
25
|
+
uncomment_lines "Gemfile", /"kredis"/ if options.lockable
|
20
26
|
end
|
21
27
|
|
22
28
|
def create_migrations
|
@@ -30,6 +36,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
30
36
|
template "models/model.rb", "app/models/#{file_name}.rb"
|
31
37
|
template "models/session.rb", "app/models/session.rb"
|
32
38
|
template "models/current.rb", "app/models/current.rb"
|
39
|
+
template "models/locking.rb", "app/models/locking.rb" if options.lockable
|
33
40
|
end
|
34
41
|
|
35
42
|
hook_for :fixture_replacement
|
@@ -55,7 +62,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
55
62
|
end
|
56
63
|
|
57
64
|
def require_sudo
|
58
|
-
if
|
65
|
+
if Current.session.sudo_at < 30.minutes.ago
|
59
66
|
render json: { error: "Enter your password to continue" }, status: :forbidden
|
60
67
|
end
|
61
68
|
end
|
@@ -73,7 +80,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
73
80
|
end
|
74
81
|
|
75
82
|
def require_sudo
|
76
|
-
if
|
83
|
+
if Current.session.sudo_at < 30.minutes.ago
|
77
84
|
redirect_to new_sudo_path(proceed_to_url: request.url)
|
78
85
|
end
|
79
86
|
end
|
data/lib/generators/authentication/templates/controllers/api/password_resets_controller.rb.tt
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
class PasswordResetsController < ApplicationController
|
2
2
|
skip_before_action :authenticate
|
3
3
|
|
4
|
+
<% if options.lockable? -%>
|
5
|
+
before_action :require_locking, only: :create
|
6
|
+
<% end -%>
|
4
7
|
before_action :set_<%= singular_table_name %>, only: :update
|
5
8
|
|
6
9
|
def create
|
7
|
-
if
|
8
|
-
IdentityMailer.with(<%= singular_table_name %>:
|
10
|
+
if @<%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email], verified: true)
|
11
|
+
IdentityMailer.with(<%= singular_table_name %>: @<%= singular_table_name %>).password_reset_provision.deliver_later
|
9
12
|
else
|
10
13
|
render json: { error: "You can't reset your password until you verify your email" }, status: :not_found
|
11
14
|
end
|
@@ -29,4 +32,11 @@ class PasswordResetsController < ApplicationController
|
|
29
32
|
def <%= "#{singular_table_name}_params" %>
|
30
33
|
params.permit(:password, :password_confirmation)
|
31
34
|
end
|
35
|
+
<% if options.lockable? %>
|
36
|
+
def require_locking
|
37
|
+
Locking.lock_on("password_reset_lock_#{request.remote_ip}", wait: 1.hour, attempts: 10) do
|
38
|
+
render json: { error: "You've exceeded the maximum number of attempts" }, status: :too_many_requests
|
39
|
+
end
|
40
|
+
end
|
41
|
+
<% end -%>
|
32
42
|
end
|
@@ -2,12 +2,12 @@ class RegistrationsController < ApplicationController
|
|
2
2
|
skip_before_action :authenticate, only: :create
|
3
3
|
|
4
4
|
def create
|
5
|
-
|
5
|
+
@<%= singular_table_name %> = <%= class_name %>.new(<%= "#{singular_table_name}_params" %>)
|
6
6
|
|
7
|
-
if
|
8
|
-
render json:
|
7
|
+
if @<%= singular_table_name %>.save
|
8
|
+
render json: @<%= singular_table_name %>, status: :created
|
9
9
|
else
|
10
|
-
render json:
|
10
|
+
render json: @<%= singular_table_name %>.errors, status: :unprocessable_entity
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -12,13 +12,13 @@ class SessionsController < ApplicationController
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def create
|
15
|
-
<%= singular_table_name %> = <%= class_name %>.
|
15
|
+
<%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email])
|
16
16
|
|
17
17
|
if <%= singular_table_name %> && <%= singular_table_name %>.authenticate(params[:password])
|
18
|
-
session = <%= singular_table_name %>.sessions.create!(session_params)
|
19
|
-
response.set_header("X-Session-Token", session.signed_id)
|
18
|
+
@session = <%= singular_table_name %>.sessions.create!(session_params)
|
19
|
+
response.set_header("X-Session-Token", @session.signed_id)
|
20
20
|
|
21
|
-
render json: session, status: :created
|
21
|
+
render json: @session, status: :created
|
22
22
|
else
|
23
23
|
render json: { error: "That email or password is incorrect" }, status: :unauthorized
|
24
24
|
end
|
data/lib/generators/authentication/templates/controllers/html/password_resets_controller.rb.tt
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
class PasswordResetsController < ApplicationController
|
2
2
|
skip_before_action :authenticate
|
3
3
|
|
4
|
+
<% if options.lockable? -%>
|
5
|
+
before_action :require_locking, only: :create
|
6
|
+
<% end -%>
|
4
7
|
before_action :set_<%= singular_table_name %>, only: %i[ edit update ]
|
5
8
|
|
6
9
|
def new
|
@@ -10,8 +13,8 @@ class PasswordResetsController < ApplicationController
|
|
10
13
|
end
|
11
14
|
|
12
15
|
def create
|
13
|
-
if
|
14
|
-
IdentityMailer.with(<%= singular_table_name %>:
|
16
|
+
if @<%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email], verified: true)
|
17
|
+
IdentityMailer.with(<%= singular_table_name %>: @<%= singular_table_name %>).password_reset_provision.deliver_later
|
15
18
|
redirect_to sign_in_path, notice: "Check your email for reset instructions"
|
16
19
|
else
|
17
20
|
redirect_to new_password_reset_path, alert: "You can't reset your password until you verify your email"
|
@@ -36,4 +39,11 @@ class PasswordResetsController < ApplicationController
|
|
36
39
|
def <%= "#{singular_table_name}_params" %>
|
37
40
|
params.require(:<%= singular_table_name %>).permit(:password, :password_confirmation)
|
38
41
|
end
|
42
|
+
<% if options.lockable? %>
|
43
|
+
def require_locking
|
44
|
+
Locking.lock_on("password_reset_lock_#{request.remote_ip}", wait: 1.hour, attempts: 10) do
|
45
|
+
redirect_to new_password_reset_path, alert: "You've exceeded the maximum number of attempts"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
<% end -%>
|
39
49
|
end
|
data/lib/generators/authentication/templates/controllers/html/registrations_controller.rb.tt
CHANGED
@@ -6,10 +6,10 @@ class RegistrationsController < ApplicationController
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def create
|
9
|
-
|
9
|
+
@<%= singular_table_name %> = <%= class_name %>.new(<%= "#{singular_table_name}_params" %>)
|
10
10
|
|
11
|
-
if
|
12
|
-
session =
|
11
|
+
if @<%= singular_table_name %>.save
|
12
|
+
session = @<%= singular_table_name %>.sessions.create!(session_params)
|
13
13
|
cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
|
14
14
|
|
15
15
|
redirect_to root_path, notice: "Welcome! You have signed up successfully"
|
@@ -12,11 +12,11 @@ class SessionsController < ApplicationController
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def create
|
15
|
-
<%= singular_table_name %> = <%= class_name %>.
|
15
|
+
<%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email])
|
16
16
|
|
17
17
|
if <%= singular_table_name %> && <%= singular_table_name %>.authenticate(params[:password])
|
18
|
-
session = <%= singular_table_name %>.sessions.create!(session_params)
|
19
|
-
cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
|
18
|
+
@session = <%= singular_table_name %>.sessions.create!(session_params)
|
19
|
+
cookies.signed.permanent[:session_token] = { value: @session.id, httponly: true }
|
20
20
|
|
21
21
|
redirect_to root_path, notice: "Signed in successfully"
|
22
22
|
else
|
@@ -8,7 +8,7 @@ class IdentityMailer < ApplicationMailer
|
|
8
8
|
|
9
9
|
def email_verify_confirmation
|
10
10
|
@<%= singular_table_name %> = params[:<%= singular_table_name %>]
|
11
|
-
@signed_id = @<%= singular_table_name %>.signed_id(purpose: @<%= singular_table_name %>.email, expires_in:
|
11
|
+
@signed_id = @<%= singular_table_name %>.signed_id(purpose: @<%= singular_table_name %>.email, expires_in: 3.days)
|
12
12
|
|
13
13
|
mail to: @<%= singular_table_name %>.email, subject: "Verify your email"
|
14
14
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
2
2
|
def change
|
3
3
|
create_table :sessions do |t|
|
4
|
-
t.references
|
4
|
+
t.references :<%= singular_table_name %>, null: false, foreign_key: true
|
5
5
|
|
6
6
|
t.string :user_agent, null: false
|
7
7
|
t.string :ip_address, null: false
|
@@ -6,6 +6,9 @@ class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
|
|
6
6
|
@sid = @<%= singular_table_name %>.signed_id(purpose: :password_reset, expires_in: 20.minutes)
|
7
7
|
@sid_exp = @<%= singular_table_name %>.signed_id(purpose: :password_reset, expires_in: 0.minutes)
|
8
8
|
end
|
9
|
+
<% if options.lockable? %>
|
10
|
+
teardown { Kredis.clear_all }
|
11
|
+
<% end -%>
|
9
12
|
|
10
13
|
test "should send a password reset email" do
|
11
14
|
assert_enqueued_email_with IdentityMailer, :password_reset_provision, args: { <%= singular_table_name %>: @<%= singular_table_name %> } do
|
@@ -6,6 +6,9 @@ class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
|
|
6
6
|
@sid = @<%= singular_table_name %>.signed_id(purpose: :password_reset, expires_in: 20.minutes)
|
7
7
|
@sid_exp = @<%= singular_table_name %>.signed_id(purpose: :password_reset, expires_in: 0.minutes)
|
8
8
|
end
|
9
|
+
<% if options.lockable? %>
|
10
|
+
teardown { Kredis.clear_all }
|
11
|
+
<% end -%>
|
9
12
|
|
10
13
|
test "should get new" do
|
11
14
|
get new_password_reset_url
|
@@ -5,6 +5,9 @@ class PasswordResetsTest < ApplicationSystemTestCase
|
|
5
5
|
@<%= singular_table_name %> = <%= table_name %>(:lazaro_nixon)
|
6
6
|
@sid = @<%= singular_table_name %>.signed_id(purpose: :password_reset, expires_in: 20.minutes)
|
7
7
|
end
|
8
|
+
<% if options.lockable? %>
|
9
|
+
teardown { Kredis.clear_all }
|
10
|
+
<% end -%>
|
8
11
|
|
9
12
|
test "sending a password reset email" do
|
10
13
|
visit sign_in_url
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: authentication-zero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nixon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02-
|
11
|
+
date: 2022-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- lib/generators/authentication/templates/migrations/create_sessions_migration.rb.tt
|
65
65
|
- lib/generators/authentication/templates/migrations/create_table_migration.rb.tt
|
66
66
|
- lib/generators/authentication/templates/models/current.rb.tt
|
67
|
+
- lib/generators/authentication/templates/models/locking.rb.tt
|
67
68
|
- lib/generators/authentication/templates/models/model.rb.tt
|
68
69
|
- lib/generators/authentication/templates/models/session.rb.tt
|
69
70
|
- lib/generators/authentication/templates/test_unit/controllers/api/email_verifications_controller_test.rb.tt
|