diff --git a/app/views/users/two_factor/_form.html.erb b/app/views/kiqr/two_factor/_form.html.erb
similarity index 100%
rename from app/views/users/two_factor/_form.html.erb
rename to app/views/kiqr/two_factor/_form.html.erb
diff --git a/app/views/users/two_factor/disable.html.erb b/app/views/kiqr/two_factor/disable.html.erb
similarity index 100%
rename from app/views/users/two_factor/disable.html.erb
rename to app/views/kiqr/two_factor/disable.html.erb
diff --git a/app/views/users/two_factor/setup.html.erb b/app/views/kiqr/two_factor/setup.html.erb
similarity index 100%
rename from app/views/users/two_factor/setup.html.erb
rename to app/views/kiqr/two_factor/setup.html.erb
diff --git a/app/views/users/two_factor/show.html.erb b/app/views/kiqr/two_factor/show.html.erb
similarity index 100%
rename from app/views/users/two_factor/show.html.erb
rename to app/views/kiqr/two_factor/show.html.erb
diff --git a/config/locales/kiqr.en.yml b/config/locales/kiqr.en.yml
index efe8374..b7aa858 100644
--- a/config/locales/kiqr.en.yml
+++ b/config/locales/kiqr.en.yml
@@ -33,67 +33,6 @@ en:
en: "English"
sv: "Swedish"
users:
- sessions:
- new:
- heading:
- title: "Sign in to your %{app_name} account"
- description: "Enter with your email address and password or select any of the other available options below."
- form:
- email:
- placeholder: "Enter your email"
- password:
- placeholder: "Enter your password"
- remember_me:
- label: "Remember me"
- submit_button: "Sign in"
- no_account: "Don't have an account?"
- sign_up: "Sign up!"
- otp:
- heading:
- title: "Two-factor authentication"
- description: "Enter the code from your authenticator app."
- form:
- otp:
- label: "One-time password"
- placeholder: "Enter the code"
- submit_button: "Verify"
- two_factor:
- show:
- title: "Two-factor authentication"
- description: "Add an extra layer of security to your user account."
- enable:
- box_title: "Enable two-factor authentication (2FA)"
- button: "Enable two-factor authentication"
- disable:
- box_title: "Disable two-factor authentication (2FA)"
- button: "Disable two-factor authentication"
- content: "Secure your account with an extra layer of protection. Two-Factor Authentication (2FA) adds a critical second step to your login process, combining something you know (your password) with something you have (a mobile device or authentication app). This makes it significantly harder for potential intruders to gain access to your account, even if they know your password."
- enabled: "Two-factor authentication has been enabled."
- disabled: "Two-factor authentication has been disabled."
- setup:
- title: "Setup two-factor authentication"
- description: "Add an extra layer of security to your user account."
- instructions: "To enable two factor authentication, scan the QR code below with your 2FA app (like Google Authenticator or Authy). This will link your user account directly to your 2FA app, generating unique, one-time codes that you'll use for secure access to your account."
- steps:
- - "Download an authenticator app on your smartphone if you haven't already."
- - "Scan the QR code with your authenticator app."
- - "Enter the 6-digit code generated by your authenticator app."
- success: "Two-factor authentication has been enabled."
- invalid_code: "Invalid code. Please try again."
- disable:
- title: "Disable two-factor authentication"
- description: "Remove the extra layer of security from your user account."
- instructions: "To disable two-factor authentication, enter the 6-digit code from your authenticator app."
- disabled: "Two-factor authentication has been disabled."
- invalid_code: "Invalid code. Please try again."
- label: "One-time password"
- placeholder: "Enter the 6-digit code"
- button: "Disable two-factor authentication"
- form:
- instructions: "Enter the code provided by your app to finish the two factor setup:"
- label: "One-time password"
- placeholder: "Enter the 6-digit code"
- verify_button: "Verify configuration"
preferences:
edit:
title: "User preferences"
diff --git a/config/routes/authentication.rb b/config/routes/authentication.rb
index 08ae558..8cf5a32 100644
--- a/config/routes/authentication.rb
+++ b/config/routes/authentication.rb
@@ -1,11 +1,4 @@
# User personal accounts.
scope module: :users, path: :users do
- get "two-factor" => "two_factor#show", :as => :edit_two_factor
- get "two-factor/new" => "two_factor#new", :as => :new_two_factor
- get "two-factor/setup" => "two_factor#setup", :as => :setup_two_factor
- get "two-factor/disable" => "two_factor#disable", :as => :disable_two_factor
- post "two-factor/verify" => "two_factor#verify", :as => :verify_two_factor
- delete "two-factor/destroy" => "two_factor#destroy", :as => :destroy_two_factor
-
resource :preferences, only: %i[edit update], as: :user_preferences
end
diff --git a/app/controllers/users/two_factor_controller.rb b/gems/kiqr/app/controllers/kiqr/two_factor_controller.rb
similarity index 80%
rename from app/controllers/users/two_factor_controller.rb
rename to gems/kiqr/app/controllers/kiqr/two_factor_controller.rb
index 8f15bf5..c8bb797 100644
--- a/app/controllers/users/two_factor_controller.rb
+++ b/gems/kiqr/app/controllers/kiqr/two_factor_controller.rb
@@ -1,4 +1,4 @@
-class Users::TwoFactorController < ApplicationController
+class Kiqr::TwoFactorController < ApplicationController
before_action :setup_user
before_action :ensure_not_enabled, only: %i[new setup verify]
@@ -25,10 +25,10 @@ def setup
def verify
if @user.validate_and_consume_otp!(params[:user][:otp_attempt])
@user.update(otp_required_for_login: true)
- redirect_to edit_two_factor_path, notice: I18n.t("users.two_factor.setup.success")
+ redirect_to edit_two_factor_path, notice: I18n.t("kiqr.two_factor.setup.success")
else
- @user.errors.add(:otp_attempt, I18n.t("users.two_factor.setup.invalid_code"))
- render turbo_stream: turbo_stream.replace("two_factor_form", partial: "users/two_factor/form", locals: {user: @user}), status: :unprocessable_entity
+ @user.errors.add(:otp_attempt, I18n.t("kiqr.two_factor.setup.invalid_code"))
+ render turbo_stream: turbo_stream.replace("two_factor_form", partial: "kiqr/two_factor/form", locals: {user: @user}), status: :unprocessable_entity
end
end
@@ -41,7 +41,7 @@ def destroy
if @user.validate_and_consume_otp!(params.dig(:user, :otp_attempt))
@user.update(otp_required_for_login: false, otp_backup_codes: [])
- redirect_to edit_two_factor_path, notice: I18n.t("users.two_factor.disable.disabled")
+ redirect_to edit_two_factor_path, notice: I18n.t("kiqr.two_factor.disable.disabled")
else
@user.errors.add(:otp_attempt, :invalid)
render :disable, status: :unprocessable_entity
diff --git a/gems/kiqr/config/locales/kiqr/en.yml b/gems/kiqr/config/locales/kiqr/en.yml
index f5ff97a..657a7a0 100644
--- a/gems/kiqr/config/locales/kiqr/en.yml
+++ b/gems/kiqr/config/locales/kiqr/en.yml
@@ -131,3 +131,64 @@ en:
owned_team_accounts: "Team accounts you are the owner of:"
submit: "Delete my account"
confirmation_message: "Are you sure? This will DELETE all of your data."
+ sessions:
+ new:
+ heading:
+ title: "Sign in to your %{app_name} account"
+ description: "Enter with your email address and password or select any of the other available options below."
+ form:
+ email:
+ placeholder: "Enter your email"
+ password:
+ placeholder: "Enter your password"
+ remember_me:
+ label: "Remember me"
+ submit_button: "Sign in"
+ no_account: "Don't have an account?"
+ sign_up: "Sign up!"
+ otp:
+ heading:
+ title: "Two-factor authentication"
+ description: "Enter the code from your authenticator app."
+ form:
+ otp:
+ label: "One-time password"
+ placeholder: "Enter the code"
+ submit_button: "Verify"
+ two_factor:
+ show:
+ title: "Two-factor authentication"
+ description: "Add an extra layer of security to your user account."
+ enable:
+ box_title: "Enable two-factor authentication (2FA)"
+ button: "Enable two-factor authentication"
+ disable:
+ box_title: "Disable two-factor authentication (2FA)"
+ button: "Disable two-factor authentication"
+ content: "Secure your account with an extra layer of protection. Two-Factor Authentication (2FA) adds a critical second step to your login process, combining something you know (your password) with something you have (a mobile device or authentication app). This makes it significantly harder for potential intruders to gain access to your account, even if they know your password."
+ enabled: "Two-factor authentication has been enabled."
+ disabled: "Two-factor authentication has been disabled."
+ setup:
+ title: "Setup two-factor authentication"
+ description: "Add an extra layer of security to your user account."
+ instructions: "To enable two factor authentication, scan the QR code below with your 2FA app (like Google Authenticator or Authy). This will link your user account directly to your 2FA app, generating unique, one-time codes that you'll use for secure access to your account."
+ steps:
+ - "Download an authenticator app on your smartphone if you haven't already."
+ - "Scan the QR code with your authenticator app."
+ - "Enter the 6-digit code generated by your authenticator app."
+ success: "Two-factor authentication has been enabled."
+ invalid_code: "Invalid code. Please try again."
+ disable:
+ title: "Disable two-factor authentication"
+ description: "Remove the extra layer of security from your user account."
+ instructions: "To disable two-factor authentication, enter the 6-digit code from your authenticator app."
+ disabled: "Two-factor authentication has been disabled."
+ invalid_code: "Invalid code. Please try again."
+ label: "One-time password"
+ placeholder: "Enter the 6-digit code"
+ button: "Disable two-factor authentication"
+ form:
+ instructions: "Enter the code provided by your app to finish the two factor setup:"
+ label: "One-time password"
+ placeholder: "Enter the 6-digit code"
+ verify_button: "Verify configuration"
diff --git a/gems/kiqr/lib/kiqr/rails/routes.rb b/gems/kiqr/lib/kiqr/rails/routes.rb
index 8c07bbe..1d405bf 100644
--- a/gems/kiqr/lib/kiqr/rails/routes.rb
+++ b/gems/kiqr/lib/kiqr/rails/routes.rb
@@ -10,6 +10,15 @@ def kiqr_routes(options = {})
invitation_routes(options)
onboarding_routes(options)
development_routes(options) if Rails.env.development?
+
+ scope path: :users do
+ get "two-factor", controller: options[:controllers][:two_factor], action: "show", as: :edit_two_factor
+ get "two-factor/new", controller: options[:controllers][:two_factor], action: "new", as: :new_two_factor
+ get "two-factor/setup", controller: options[:controllers][:two_factor], action: "setup", as: :setup_two_factor
+ get "two-factor/disable", controller: options[:controllers][:two_factor], action: "disable", as: :disable_two_factor
+ post "two-factor/verify", controller: options[:controllers][:two_factor], action: "verify", as: :verify_two_factor
+ delete "two-factor/destroy", controller: options[:controllers][:two_factor], action: "destroy", as: :destroy_two_factor
+ end
end
private
@@ -24,6 +33,7 @@ def default_controllers(options)
options[:controllers][:onboarding] ||= "kiqr/onboarding"
options[:controllers][:registrations] ||= "kiqr/registrations"
options[:controllers][:sessions] ||= "kiqr/sessions"
+ options[:controllers][:two_factor] ||= "kiqr/two_factor"
options
end
diff --git a/test/system/users/two_factor_test.rb b/test/system/users/two_factor_test.rb
index b698d05..609f639 100644
--- a/test/system/users/two_factor_test.rb
+++ b/test/system/users/two_factor_test.rb
@@ -4,11 +4,11 @@ class TwoFactorTest < ApplicationSystemTestCase
def prepare_otp_setup(user)
sign_in user
visit edit_two_factor_path
- assert_selector "a.button", text: I18n.t("users.two_factor.show.enable.button")
+ assert_selector "a.button", text: I18n.t("kiqr.two_factor.show.enable.button")
pre_otp_secret = user.otp_secret
- click_link I18n.t("users.two_factor.show.enable.button")
+ click_link I18n.t("kiqr.two_factor.show.enable.button")
assert_current_path setup_two_factor_path
assert_not user.otp_required_for_login?
@@ -26,7 +26,7 @@ def prepare_otp_setup(user)
assert_current_path edit_two_factor_path
assert user.reload.otp_required_for_login?
- assert_text I18n.t("users.two_factor.setup.success")
+ assert_text I18n.t("kiqr.two_factor.setup.success")
end
test "Show error message if otp code is wrong" do
@@ -39,7 +39,7 @@ def prepare_otp_setup(user)
assert_current_path setup_two_factor_path
assert_not user.reload.otp_required_for_login?
- assert_text I18n.t("users.two_factor.setup.invalid_code")
+ assert_text I18n.t("kiqr.two_factor.setup.invalid_code")
end
test "refreshes qr code image on new setup" do
@@ -56,6 +56,6 @@ def prepare_otp_setup(user)
user = create(:user, :otp_enabled)
sign_in user
visit edit_two_factor_path
- assert_selector "a.button", text: I18n.t("users.two_factor.show.disable.button")
+ assert_selector "a.button", text: I18n.t("kiqr.two_factor.show.disable.button")
end
end