Skip to content

Commit 4e4492b

Browse files
committed
Run authentication-zero generator and add specs
1 parent cc711eb commit 4e4492b

39 files changed

+968
-5
lines changed

Gemfile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ gem "puma", ">= 5.0"
1414
gem "jbuilder"
1515

1616
# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
17-
# gem "bcrypt", "~> 3.1.7"
17+
gem "bcrypt", "~> 3.1.7"
1818

1919
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
2020
gem "tzinfo-data", platforms: %i[ windows jruby ]
@@ -42,6 +42,10 @@ gem "vite_rails", "~> 3.0"
4242
# The Rails adapter for Inertia.js [https://inertia-rails.dev]
4343
gem "inertia_rails", "~> 3.10"
4444

45+
# An authentication system generator for Rails applications
46+
# we leave gem here to watch for security updates
47+
gem "authentication-zero"
48+
4549
group :development, :test do
4650
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
4751
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"

Gemfile.lock

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ GEM
7575
addressable (2.8.7)
7676
public_suffix (>= 2.0.2, < 7.0)
7777
ast (2.4.3)
78+
authentication-zero (4.0.3)
7879
base64 (0.3.0)
80+
bcrypt (3.1.20)
7981
bcrypt_pbkdf (1.1.1)
8082
benchmark (0.4.1)
8183
bigdecimal (3.2.2)
@@ -392,6 +394,8 @@ PLATFORMS
392394
x86_64-linux-musl
393395

394396
DEPENDENCIES
397+
authentication-zero
398+
bcrypt (~> 3.1.7)
395399
bootsnap
396400
brakeman
397401
capybara
Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
1-
# frozen_string_literal: true
2-
31
class ApplicationController < ActionController::Base
42
# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
53
allow_browser versions: :modern
4+
5+
before_action :set_current_request_details
6+
before_action :authenticate
7+
8+
private
9+
def authenticate
10+
if session_record = Session.find_by_id(cookies.signed[:session_token])
11+
Current.session = session_record
12+
else
13+
redirect_to sign_in_path
14+
end
15+
end
16+
17+
def set_current_request_details
18+
Current.user_agent = request.user_agent
19+
Current.ip_address = request.ip
20+
end
621
end

app/controllers/home_controller.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class HomeController < ApplicationController
2+
def index
3+
end
4+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
class Identity::EmailVerificationsController < ApplicationController
2+
skip_before_action :authenticate, only: :show
3+
4+
before_action :set_user, only: :show
5+
6+
def show
7+
@user.update! verified: true
8+
redirect_to root_path, notice: "Thank you for verifying your email address"
9+
end
10+
11+
def create
12+
send_email_verification
13+
redirect_to root_path, notice: "We sent a verification email to your email address"
14+
end
15+
16+
private
17+
def set_user
18+
@user = User.find_by_token_for!(:email_verification, params[:sid])
19+
rescue StandardError
20+
redirect_to edit_identity_email_path, alert: "That email verification link is invalid"
21+
end
22+
23+
def send_email_verification
24+
UserMailer.with(user: Current.user).email_verification.deliver_later
25+
end
26+
end
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
class Identity::EmailsController < ApplicationController
2+
before_action :set_user
3+
4+
def edit
5+
end
6+
7+
def update
8+
if @user.update(user_params)
9+
redirect_to_root
10+
else
11+
render :edit, status: :unprocessable_content
12+
end
13+
end
14+
15+
private
16+
def set_user
17+
@user = Current.user
18+
end
19+
20+
def user_params
21+
params.permit(:email, :password_challenge).with_defaults(password_challenge: "")
22+
end
23+
24+
def redirect_to_root
25+
if @user.email_previously_changed?
26+
resend_email_verification
27+
redirect_to root_path, notice: "Your email has been changed"
28+
else
29+
redirect_to root_path
30+
end
31+
end
32+
33+
def resend_email_verification
34+
UserMailer.with(user: @user).email_verification.deliver_later
35+
end
36+
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
class Identity::PasswordResetsController < ApplicationController
2+
skip_before_action :authenticate
3+
4+
before_action :set_user, only: %i[ edit update ]
5+
6+
def new
7+
end
8+
9+
def edit
10+
end
11+
12+
def create
13+
if @user = User.find_by(email: params[:email], verified: true)
14+
send_password_reset_email
15+
redirect_to sign_in_path, notice: "Check your email for reset instructions"
16+
else
17+
redirect_to new_identity_password_reset_path, alert: "You can't reset your password until you verify your email"
18+
end
19+
end
20+
21+
def update
22+
if @user.update(user_params)
23+
redirect_to sign_in_path, notice: "Your password was reset successfully. Please sign in"
24+
else
25+
render :edit, status: :unprocessable_content
26+
end
27+
end
28+
29+
private
30+
def set_user
31+
@user = User.find_by_token_for!(:password_reset, params[:sid])
32+
rescue StandardError
33+
redirect_to new_identity_password_reset_path, alert: "That password reset link is invalid"
34+
end
35+
36+
def user_params
37+
params.permit(:password, :password_confirmation)
38+
end
39+
40+
def send_password_reset_email
41+
UserMailer.with(user: @user).password_reset.deliver_later
42+
end
43+
end
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
class PasswordsController < ApplicationController
2+
before_action :set_user
3+
4+
def edit
5+
end
6+
7+
def update
8+
if @user.update(user_params)
9+
redirect_to root_path, notice: "Your password has been changed"
10+
else
11+
render :edit, status: :unprocessable_content
12+
end
13+
end
14+
15+
private
16+
def set_user
17+
@user = Current.user
18+
end
19+
20+
def user_params
21+
params.permit(:password, :password_confirmation, :password_challenge).with_defaults(password_challenge: "")
22+
end
23+
end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class RegistrationsController < ApplicationController
2+
skip_before_action :authenticate
3+
4+
def new
5+
@user = User.new
6+
end
7+
8+
def create
9+
@user = User.new(user_params)
10+
11+
if @user.save
12+
session_record = @user.sessions.create!
13+
cookies.signed.permanent[:session_token] = { value: session_record.id, httponly: true }
14+
15+
send_email_verification
16+
redirect_to root_path, notice: "Welcome! You have signed up successfully"
17+
else
18+
render :new, status: :unprocessable_content
19+
end
20+
end
21+
22+
private
23+
def user_params
24+
params.permit(:email, :name, :password, :password_confirmation)
25+
end
26+
27+
def send_email_verification
28+
UserMailer.with(user: @user).email_verification.deliver_later
29+
end
30+
end
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
class SessionsController < ApplicationController
2+
skip_before_action :authenticate, only: %i[ new create ]
3+
4+
before_action :set_session, only: :destroy
5+
6+
def index
7+
@sessions = Current.user.sessions.order(created_at: :desc)
8+
end
9+
10+
def new
11+
end
12+
13+
def create
14+
if user = User.authenticate_by(email: params[:email], password: params[:password])
15+
@session = user.sessions.create!
16+
cookies.signed.permanent[:session_token] = { value: @session.id, httponly: true }
17+
18+
redirect_to root_path, notice: "Signed in successfully"
19+
else
20+
redirect_to sign_in_path(email_hint: params[:email]), alert: "That email or password is incorrect"
21+
end
22+
end
23+
24+
def destroy
25+
@session.destroy; redirect_to(sessions_path, notice: "That session has been logged out")
26+
end
27+
28+
private
29+
def set_session
30+
@session = Current.user.sessions.find(params[:id])
31+
end
32+
end

0 commit comments

Comments
 (0)