authentication-zero 2.3.6 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3cd20da7b0f56b6c19dcc3133bd3423222705fd77b64b6754284b2d0a34b795d
4
- data.tar.gz: a4fecf9bdff5dc659b584326323ac6b53840d4bc9e0e0096f957d68d34ce521b
3
+ metadata.gz: 3aaf162f00b6413821ae603869fb83f1cf577f956490821ffa051a6bf3b314ce
4
+ data.tar.gz: 9d4d1efd1aeddc346f39d4aec8752ec3f4a693e12908ec7c6ebc4cdcc0888684
5
5
  SHA512:
6
- metadata.gz: 9b16ae0a95f453247ea61761bd50bac1abb196980ec8ec56cae879e58239b3f80ffcbb43cde1de81ac4bd50efecaaada6416890a9a04090c3c558c3ffa28870d
7
- data.tar.gz: 4563fc71ef94b056bd823dca4dee733d0a337796b995d886e9eeca5cd82706deb43e108857dd70e1bedf1b29a67c0eb1dd08ef2f9fc231a1c0ef51f3c74f17e8
6
+ metadata.gz: 112be1974500241c1e8a78411ba1b1846a7de6ab6a04c81b76963ded1b5150a7f7a12097ba06202210c73446c8404939718d9e7f14d93be3d96a9995235cd56e
7
+ data.tar.gz: d0d7c2965efdc83e16fcc068c1a1069269a60d68adafc0714291f310e726d90a698f0105752607a747894b683d7e544481b56cad3dee949ca52262f0c34e1250
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
- ## Rails 2.3.0 (February 26, 2022) ##
1
+ ## Authentication Zero 2.4.0 (February 28, 2022) ##
2
+
3
+ * Implemented lockable
4
+
5
+ ## Authentication Zero 2.3.0 (February 26, 2022) ##
2
6
 
3
7
  * Implemented sudo
4
8
  * Destroy sessions after change password
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- authentication-zero (2.3.6)
4
+ authentication-zero (2.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
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 (html)
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
- - Send e-mail verification when your email has been changed
17
- - Send email when someone has logged into your account
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).
@@ -1,3 +1,3 @@
1
1
  module AuthenticationZero
2
- VERSION = "2.3.6"
2
+ VERSION = "2.4.0"
3
3
  end
@@ -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, default: false
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
@@ -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: :update
5
8
 
6
9
  def create
@@ -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
@@ -12,7 +12,7 @@ class SessionsController < ApplicationController
12
12
  end
13
13
 
14
14
  def create
15
- <%= singular_table_name %> = <%= class_name %>.find_by_email(params[:email])
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
18
  @session = <%= singular_table_name %>.sessions.create!(session_params)
@@ -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
@@ -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
@@ -12,7 +12,7 @@ class SessionsController < ApplicationController
12
12
  end
13
13
 
14
14
  def create
15
- <%= singular_table_name %> = <%= class_name %>.find_by_email(params[:email])
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
18
  @session = <%= singular_table_name %>.sessions.create!(session_params)
@@ -0,0 +1,10 @@
1
+ class Locking
2
+ def self.lock_on(key, wait:, attempts:, &block)
3
+ counter = Kredis.counter(key, expires_in: wait)
4
+ counter.increment
5
+
6
+ if counter.value > attempts
7
+ yield
8
+ end
9
+ end
10
+ end
@@ -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.3.6
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-27 00:00:00.000000000 Z
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