Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Since Authentication Zero generates this code into your application instead of b
- Send invitations (--invitable)
- "Sign-in as" button (--masqueradable)
- Multi-tentant application (--tenantable)
- Add default locale files for en, de, ja (--i18n)

## Generated code

Expand Down
1 change: 1 addition & 0 deletions authentication-zero.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ Gem::Specification.new do |spec|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
end

end
3 changes: 3 additions & 0 deletions lib/authentication_zero.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
require "authentication_zero/version"
require "i18n"

module AuthenticationZero
# Load translations when gem is loaded
I18n.load_path += Dir[File.expand_path("locales/*.yml", __dir__)]
end
16 changes: 16 additions & 0 deletions lib/generators/authentication/authentication_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class AuthenticationGenerator < Rails::Generators::Base
class_option :invitable, type: :boolean, desc: "Add sending invitations"
class_option :masqueradable, type: :boolean, desc: "Add sign-in as button functionallity"
class_option :tenantable, type: :boolean, desc: "Add artifacts to implement a row-level tenant app"
class_option :i18n, type: :boolean, desc: "Add default locale files (en, de, ja) to config/locales/authentication"

source_root File.expand_path("templates", __dir__)

Expand Down Expand Up @@ -42,6 +43,10 @@ def add_gems
if webauthn?
gem "webauthn", comment: "Use webauthn for making rails become a conformant web authn relying party [https://github.com/cedarcode/webauthn-ruby]"
end

if i18n?
gem "rails-i18n", "~> 8.0.0", comment: "Use rails-i18n gem for translation [https://github.com/svenfuchs/rails-i18n]"
end
end

def create_configuration_files
Expand Down Expand Up @@ -206,6 +211,13 @@ def add_routes
route 'get "sign_in", to: "sessions#new"' unless options.api?
end

def copy_i18n_files
if options.i18n?
# Copy from locales to app
directory "i18n/locales", "config/locales/authentication", force: false
end
end

def create_test_files
directory "test_unit/controllers/#{format}", "test/controllers"
directory "test_unit/mailers/", "test/mailers"
Expand Down Expand Up @@ -256,4 +268,8 @@ def importmaps?
def node?
Rails.root.join("package.json").exist?
end

def i18n?
options.i18n?
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ class Identity::EmailVerificationsController < ApplicationController
def set_user
@user = User.find_by_token_for!(:email_verification, params[:sid])
rescue StandardError
render json: { error: "That email verification link is invalid" }, status: :bad_request
render json: { error: t('authentication_zero.controllers.identity.email_verifications.set_user.invalid_verification_link') }, status: :bad_request
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Identity::PasswordResetsController < ApplicationController
if @user = User.find_by(email: params[:email], verified: true)
UserMailer.with(user: @user).password_reset.deliver_later
else
render json: { error: "You can't reset your password until you verify your email" }, status: :bad_request
render json: { error: t('authentication_zero.controllers.identity.password_resets.create.cant_reset_until_verified') }, status: :bad_request
end
end

Expand All @@ -27,7 +27,7 @@ class Identity::PasswordResetsController < ApplicationController
def set_user
@user = User.find_by_token_for!(:password_reset, params[:sid])
rescue StandardError
render json: { error: "That password reset link is invalid" }, status: :bad_request
render json: { error: t('authentication_zero.controllers.identity.password_resets.set_user.invalid_reset_link') }, status: :bad_request
end

def user_params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class SessionsController < ApplicationController

render json: @session, status: :created
else
render json: { error: "That email or password is incorrect" }, status: :unauthorized
render json: { error: t('authentication_zero.controllers.sessions.create.incorrect_email_or_password') }, status: :unauthorized
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ class Identity::EmailVerificationsController < ApplicationController

def show
@user.update! verified: true
redirect_to root_path, notice: "Thank you for verifying your email address"
redirect_to root_path, notice: t('authentication_zero.controllers.identity.email_verifications.show.thank_you_verified')
end

def create
send_email_verification
redirect_to root_path, notice: "We sent a verification email to your email address"
redirect_to root_path, notice: t('authentication_zero.controllers.identity.email_verifications.create.verification_email_sent')
end

private
def set_user
@user = User.find_by_token_for!(:email_verification, params[:sid])
rescue StandardError
redirect_to edit_identity_email_path, alert: "That email verification link is invalid"
redirect_to edit_identity_email_path, alert: t('authentication_zero.controllers.identity.email_verifications.set_user.invalid_verification_link')
end

def send_email_verification
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Identity::EmailsController < ApplicationController
def redirect_to_root
if @user.email_previously_changed?
resend_email_verification
redirect_to root_path, notice: "Your email has been changed"
redirect_to root_path, notice: t('authentication_zero.controllers.identity.emails.update.email_changed')
else
redirect_to root_path
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ class Identity::PasswordResetsController < ApplicationController
def create
if @user = User.find_by(email: params[:email], verified: true)
send_password_reset_email
redirect_to sign_in_path, notice: "Check your email for reset instructions"
redirect_to sign_in_path, notice: t('authentication_zero.controllers.identity.password_resets.create.check_email_reset_instructions')
else
redirect_to new_identity_password_reset_path, alert: "You can't reset your password until you verify your email"
redirect_to new_identity_password_reset_path, alert: t('authentication_zero.controllers.identity.password_resets.create.cant_reset_until_verified')
end
end

def update
if @user.update(user_params)
redirect_to sign_in_path, notice: "Your password was reset successfully. Please sign in"
redirect_to sign_in_path, notice: t('authentication_zero.controllers.identity.password_resets.update.password_reset_success')
else
render :edit, status: :unprocessable_entity
end
Expand All @@ -33,7 +33,7 @@ class Identity::PasswordResetsController < ApplicationController
def set_user
@user = User.find_by_token_for!(:password_reset, params[:sid])
rescue StandardError
redirect_to new_identity_password_reset_path, alert: "That password reset link is invalid"
redirect_to new_identity_password_reset_path, alert: t('authentication_zero.controllers.identity.password_resets.set_user.invalid_reset_link')
end

def user_params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class InvitationsController < ApplicationController

if @user.save
send_invitation_instructions
redirect_to new_invitation_path, notice: "An invitation email has been sent to #{@user.email}"
redirect_to new_invitation_path, notice: t('authentication_zero.controllers.invitations.create.invitation_sent', email: @user.email)
else
render :new, status: :unprocessable_entity
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class MasqueradesController < ApplicationController
session_record = @user.sessions.create!
cookies.signed.permanent[:session_token] = { value: session_record.id, httponly: true }

redirect_to root_path, notice: "Signed in successfully"
redirect_to root_path, notice: t('authentication_zero.controllers.masquerades.create.signed_in_successfully')
end

private
Expand All @@ -15,6 +15,6 @@ class MasqueradesController < ApplicationController
end

def authorize
redirect_to(root_path, alert: "You must be in development") unless Rails.env.development?
redirect_to(root_path, alert: t('authentication_zero.controllers.masquerades.authorize.must_be_in_development')) unless Rails.env.development?
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class PasswordsController < ApplicationController

def update
if @user.update(user_params)
redirect_to root_path, notice: "Your password has been changed"
redirect_to root_path, notice: t('authentication_zero.controllers.passwords.update.password_changed')
else
render :edit, status: :unprocessable_entity
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class RegistrationsController < ApplicationController
cookies.signed.permanent[:session_token] = { value: session_record.id, httponly: true }

send_email_verification
redirect_to root_path, notice: "Welcome! You have signed up successfully"
redirect_to root_path, notice: t('authentication_zero.controllers.registrations.create.welcome_signed_up')
else
render :new, status: :unprocessable_entity
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ class Sessions::OmniauthController < ApplicationController
session_record = @user.sessions.create!
cookies.signed.permanent[:session_token] = { value: session_record.id, httponly: true }

redirect_to root_path, notice: "Signed in successfully"
redirect_to root_path, notice: t('authentication_zero.controllers.sessions.omniauth.create.signed_in_successfully')
else
redirect_to sign_in_path, alert: "Authentication failed"
redirect_to sign_in_path, alert: t('authentication_zero.controllers.sessions.omniauth.create.authentication_failed')
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@ class Sessions::PasswordlessesController < ApplicationController
cookies.signed.permanent[:session_token] = { value: session_record.id, httponly: true }

revoke_sign_in_tokens
redirect_to(root_path, notice: "Signed in successfully")
redirect_to(root_path, notice: t('authentication_zero.controllers.sessions.passwordlesses.edit.signed_in_successfully'))
end

def create
if @user = User.find_by(email: params[:email], verified: true)
send_passwordless_email
redirect_to sign_in_path, notice: "Check your email for sign in instructions"
redirect_to sign_in_path, notice: t('authentication_zero.controllers.sessions.passwordlesses.create.check_email_sign_in_instructions')
else
redirect_to new_sessions_passwordless_path, alert: "You can't sign in until you verify your email"
redirect_to new_sessions_passwordless_path, alert: t('authentication_zero.controllers.sessions.passwordlesses.create.cant_sign_in_until_verified')
end
end

private
def set_user
token = SignInToken.find_signed!(params[:sid]); @user = token.user
rescue StandardError
redirect_to new_sessions_passwordless_path, alert: "That sign in link is invalid"
redirect_to new_sessions_passwordless_path, alert: t('authentication_zero.controllers.sessions.passwordlesses.set_user.invalid_sign_in_link')
end

def send_passwordless_email
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Sessions::SudosController < ApplicationController
if session_record.user.authenticate(params[:password])
session_record.touch(:sudo_at); redirect_to(params[:proceed_to_url])
else
redirect_to new_sessions_sudo_path(proceed_to_url: params[:proceed_to_url]), alert: "The password you entered is incorrect"
redirect_to new_sessions_sudo_path(proceed_to_url: params[:proceed_to_url]), alert: t('authentication_zero.controllers.sessions.sudos.create.incorrect_password')
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class SessionsController < ApplicationController
@session = user.sessions.create!
cookies.signed.permanent[:session_token] = { value: @session.id, httponly: true }

redirect_to root_path, notice: "Signed in successfully"
redirect_to root_path, notice: t('authentication_zero.controllers.sessions.create.signed_in_successfully')
end
<%- else -%>
@session = user.sessions.create!
Expand All @@ -29,12 +29,12 @@ class SessionsController < ApplicationController
redirect_to root_path, notice: "Signed in successfully"
<%- end -%>
else
redirect_to sign_in_path(email_hint: params[:email]), alert: "That email or password is incorrect"
redirect_to sign_in_path(email_hint: params[:email]), alert: t('authentication_zero.controllers.sessions.create.incorrect_email_or_password')
end
end

def destroy
@session.destroy; redirect_to(sessions_path, notice: "That session has been logged out")
@session.destroy; redirect_to(sessions_path, notice: t('authentication_zero.controllers.sessions.destroy.session_logged_out'))
end

private
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ class TwoFactorAuthentication::Challenge::RecoveryCodesController < ApplicationC
if recover_code = @user.recovery_codes.find_by(code: params[:code], used: false)
recover_code.update!(used: true); sign_in_and_redirect_to_root
else
redirect_to new_two_factor_authentication_challenge_recovery_codes_path, alert: "That code didn't work. Please try again"
redirect_to new_two_factor_authentication_challenge_recovery_codes_path, alert: t('authentication_zero.controllers.two_factor_authentication.challenge.recovery_codes.create.code_didnt_work')
end
end

private
def set_user
@user = User.find_signed!(session[:challenge_token], purpose: :authentication_challenge)
rescue StandardError
redirect_to sign_in_path, alert: "That's taking too long. Please re-enter your password and try again"
redirect_to sign_in_path, alert: t('authentication_zero.controllers.two_factor_authentication.challenge.recovery_codes.set_user.taking_too_long')
end

def sign_in_and_redirect_to_root
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ class TwoFactorAuthentication::Challenge::SecurityKeysController < ApplicationCo
if @user.security_keys.exists?(external_id: credential.id)
sign_in_and_redirect_to_root
else
render json: { error: "Verification failed: #{e.message}" }, status: :unprocessable_entity
render json: { error: t('authentication_zero.controllers.two_factor_authentication.challenge.security_keys.create.verification_failed', error: e.message) }, status: :unprocessable_entity
end
end

private
def set_user
@user = User.find_signed!(session[:challenge_token], purpose: :authentication_challenge)
rescue StandardError
redirect_to sign_in_path, alert: "That's taking too long. Please re-enter your password and try again"
redirect_to sign_in_path, alert: t('authentication_zero.controllers.two_factor_authentication.challenge.security_keys.set_user.taking_too_long')
end

def sign_in_and_redirect_to_root
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ class TwoFactorAuthentication::Challenge::TotpsController < ApplicationControlle
if @totp.verify(params[:code], drift_behind: 15)
sign_in_and_redirect_to_root
else
redirect_to new_two_factor_authentication_challenge_totp_path, alert: "That code didn't work. Please try again"
redirect_to new_two_factor_authentication_challenge_totp_path, alert: t('authentication_zero.controllers.two_factor_authentication.challenge.totps.create.code_didnt_work')
end
end

private
def set_user
@user = User.find_signed!(session[:challenge_token], purpose: :authentication_challenge)
rescue StandardError
redirect_to sign_in_path, alert: "That's taking too long. Please re-enter your password and try again"
redirect_to sign_in_path, alert: t('authentication_zero.controllers.two_factor_authentication.challenge.totps.set_user.taking_too_long')
end

def sign_in_and_redirect_to_root
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class TwoFactorAuthentication::Profile::RecoveryCodesController < ApplicationCon
@user.recovery_codes.delete_all
@user.recovery_codes.create!(new_recovery_codes)

redirect_to two_factor_authentication_profile_recovery_codes_path, notice: "Your new recovery codes have been generated"
redirect_to two_factor_authentication_profile_recovery_codes_path, notice: t('authentication_zero.controllers.two_factor_authentication.profile.recovery_codes.create.new_codes_generated')
end

private
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ class TwoFactorAuthentication::Profile::SecurityKeysController < ApplicationCont

def update
@security_key.update! name: params[:name]
redirect_to two_factor_authentication_profile_security_keys_path, notice: "Your changes have been saved"
redirect_to two_factor_authentication_profile_security_keys_path, notice: t('authentication_zero.controllers.two_factor_authentication.profile.security_keys.update.changes_saved')
end

def destroy
@security_key.destroy
redirect_to two_factor_authentication_profile_security_keys_path, notice: "#{@security_key.name} has been removed"
redirect_to two_factor_authentication_profile_security_keys_path, notice: t('authentication_zero.controllers.two_factor_authentication.profile.security_keys.destroy.security_key_removed', name: @security_key.name)
end

private
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class TwoFactorAuthentication::Profile::TotpsController < ApplicationController
@user.update! otp_required_for_sign_in: true
redirect_to two_factor_authentication_profile_recovery_codes_path
else
redirect_to new_two_factor_authentication_profile_totp_path, alert: "That code didn't work. Please try again"
redirect_to new_two_factor_authentication_profile_totp_path, alert: t('authentication_zero.controllers.two_factor_authentication.profile.totps.create.code_didnt_work')
end
end

Expand Down
Loading