diff --git a/app/assets/stylesheets/lists.scss b/app/assets/stylesheets/lists.scss
index 9cfc46ecf05..47805663f00 100644
--- a/app/assets/stylesheets/lists.scss
+++ b/app/assets/stylesheets/lists.scss
@@ -9,4 +9,12 @@
.recovery-codes {
list-style: none;
+ margin: 0 auto;
+ text-align: center;
+
+ li {
+ font-size: 125%;
+ line-height: 1.5;
+ letter-spacing: 1px;
+ }
}
diff --git a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
new file mode 100644
index 00000000000..4cf62db13ef
--- /dev/null
+++ b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Settings
+ module TwoFactorAuthentication
+ class ConfirmationsController < ApplicationController
+ layout 'admin'
+
+ before_action :authenticate_user!
+
+ def new
+ prepare_two_factor_form
+ end
+
+ def create
+ if current_user.validate_and_consume_otp!(confirmation_params[:code])
+ flash[:notice] = I18n.t('two_factor_authentication.enabled_success')
+
+ current_user.otp_required_for_login = true
+ @recovery_codes = current_user.generate_otp_backup_codes!
+ current_user.save!
+
+ render 'settings/two_factor_authentication/recovery_codes/index'
+ else
+ flash.now[:alert] = I18n.t('two_factor_authentication.wrong_code')
+ prepare_two_factor_form
+ render :new
+ end
+ end
+
+ private
+
+ def confirmation_params
+ params.require(:form_two_factor_confirmation).permit(:code)
+ end
+
+ def prepare_two_factor_form
+ @confirmation = Form::TwoFactorConfirmation.new
+ @provision_url = current_user.otp_provisioning_uri(current_user.email, issuer: Rails.configuration.x.local_domain)
+ @qrcode = RQRCode::QRCode.new(@provision_url)
+ end
+ end
+ end
+end
diff --git a/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb b/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
new file mode 100644
index 00000000000..e591e9502d9
--- /dev/null
+++ b/app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Settings
+ module TwoFactorAuthentication
+ class RecoveryCodesController < ApplicationController
+ layout 'admin'
+
+ before_action :authenticate_user!
+
+ def create
+ @recovery_codes = current_user.generate_otp_backup_codes!
+ current_user.save!
+ flash[:notice] = I18n.t('two_factor_authentication.recovery_codes_regenerated')
+ render :index
+ end
+ end
+ end
+end
diff --git a/app/controllers/settings/two_factor_authentications_controller.rb b/app/controllers/settings/two_factor_authentications_controller.rb
new file mode 100644
index 00000000000..f66c3a90833
--- /dev/null
+++ b/app/controllers/settings/two_factor_authentications_controller.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Settings
+ class TwoFactorAuthenticationsController < ApplicationController
+ layout 'admin'
+
+ before_action :authenticate_user!
+ before_action :verify_otp_required, only: [:create]
+
+ def show; end
+
+ def create
+ current_user.otp_secret = User.generate_otp_secret(32)
+ current_user.save!
+ redirect_to new_settings_two_factor_authentication_confirmation_path
+ end
+
+ def destroy
+ current_user.otp_required_for_login = false
+ current_user.save!
+ redirect_to settings_two_factor_authentication_path
+ end
+
+ private
+
+ def verify_otp_required
+ redirect_to settings_two_factor_authentication_path if current_user.otp_required_for_login?
+ end
+ end
+end
diff --git a/app/controllers/settings/two_factor_auths_controller.rb b/app/controllers/settings/two_factor_auths_controller.rb
deleted file mode 100644
index a06b2a9f922..00000000000
--- a/app/controllers/settings/two_factor_auths_controller.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-class Settings::TwoFactorAuthsController < ApplicationController
- layout 'admin'
-
- before_action :authenticate_user!
-
- def show; end
-
- def new
- redirect_to settings_two_factor_auth_path if current_user.otp_required_for_login
-
- @confirmation = Form::TwoFactorConfirmation.new
- current_user.otp_secret = User.generate_otp_secret(32)
- current_user.save!
- set_qr_code
- end
-
- def create
- if current_user.validate_and_consume_otp!(confirmation_params[:code])
- current_user.otp_required_for_login = true
- @codes = current_user.generate_otp_backup_codes!
- current_user.save!
- flash[:notice] = I18n.t('two_factor_auth.enabled_success')
- else
- @confirmation = Form::TwoFactorConfirmation.new
- set_qr_code
- flash.now[:alert] = I18n.t('two_factor_auth.wrong_code')
- render :new
- end
- end
-
- def recovery_codes
- @codes = current_user.generate_otp_backup_codes!
- current_user.save!
- flash[:notice] = I18n.t('two_factor_auth.recovery_codes_regenerated')
- end
-
- def disable
- current_user.otp_required_for_login = false
- current_user.save!
-
- redirect_to settings_two_factor_auth_path
- end
-
- private
-
- def set_qr_code
- @provision_url = current_user.otp_provisioning_uri(current_user.email, issuer: Rails.configuration.x.local_domain)
- @qrcode = RQRCode::QRCode.new(@provision_url)
- end
-
- def confirmation_params
- params.require(:form_two_factor_confirmation).permit(:code)
- end
-end
diff --git a/app/views/settings/shared/_links.html.haml b/app/views/settings/shared/_links.html.haml
index 6490ffdd868..0abb5a7abb1 100644
--- a/app/views/settings/shared/_links.html.haml
+++ b/app/views/settings/shared/_links.html.haml
@@ -5,6 +5,6 @@
%li= link_to t('settings.preferences'), settings_preferences_path
- if controller_name != 'registrations'
%li= link_to t('auth.change_password'), edit_user_registration_path
- - if controller_name != 'two_factor_auths'
- %li= link_to t('settings.two_factor_auth'), settings_two_factor_auth_path
+ - if controller_name != 'two_factor_authentications'
+ %li= link_to t('settings.two_factor_authentication'), settings_two_factor_authentication_path
%li= link_to t('settings.back'), root_path
diff --git a/app/views/settings/two_factor_authentication/confirmations/new.html.haml b/app/views/settings/two_factor_authentication/confirmations/new.html.haml
new file mode 100644
index 00000000000..9d950c78e79
--- /dev/null
+++ b/app/views/settings/two_factor_authentication/confirmations/new.html.haml
@@ -0,0 +1,17 @@
+- content_for :page_title do
+ = t('settings.two_factor_authentication')
+
+= simple_form_for @confirmation, url: settings_two_factor_authentication_confirmation_path, method: :post do |f|
+ %p.hint= t('two_factor_authentication.instructions_html')
+
+ .qr-wrapper
+ .qr-code= raw @qrcode.as_svg(padding: 0, module_size: 4)
+
+ .qr-alternative
+ %p.hint= t('two_factor_authentication.manual_instructions')
+ %samp.qr-alternative__code= current_user.otp_secret.scan(/.{4}/).join(' ')
+
+ = f.input :code, hint: t('two_factor_authentication.code_hint'), placeholder: t('simple_form.labels.defaults.otp_attempt')
+
+ .actions
+ = f.button :button, t('two_factor_authentication.enable'), type: :submit
diff --git a/app/views/settings/two_factor_authentication/recovery_codes/index.html.haml b/app/views/settings/two_factor_authentication/recovery_codes/index.html.haml
new file mode 100644
index 00000000000..7d409826e4f
--- /dev/null
+++ b/app/views/settings/two_factor_authentication/recovery_codes/index.html.haml
@@ -0,0 +1,9 @@
+- content_for :page_title do
+ = t('settings.two_factor_authentication')
+
+%p.hint= t('two_factor_authentication.recovery_instructions')
+
+%ol.recovery-codes
+ - @recovery_codes.each do |code|
+ %li<
+ %samp= code
diff --git a/app/views/settings/two_factor_authentications/show.html.haml b/app/views/settings/two_factor_authentications/show.html.haml
new file mode 100644
index 00000000000..88b5bd20e49
--- /dev/null
+++ b/app/views/settings/two_factor_authentications/show.html.haml
@@ -0,0 +1,26 @@
+- content_for :page_title do
+ = t('settings.two_factor_authentication')
+
+.simple_form
+ %p.hint
+ = t('two_factor_authentication.description_html')
+
+ - if current_user.otp_required_for_login
+ = link_to t('two_factor_authentication.disable'),
+ settings_two_factor_authentication_path,
+ data: { method: :delete },
+ class: 'block-button'
+ - else
+ = link_to t('two_factor_authentication.setup'),
+ settings_two_factor_authentication_path,
+ data: { method: :post },
+ class: 'block-button'
+
+- if current_user.otp_required_for_login
+ .simple_form
+ %p.hint
+ = t('two_factor_authentication.lost_recovery_codes')
+ = link_to t('two_factor_authentication.generate_recovery_codes'),
+ settings_two_factor_authentication_recovery_codes_path,
+ data: { method: :post },
+ class: 'block-button'
diff --git a/app/views/settings/two_factor_auths/_recovery_codes.html.haml b/app/views/settings/two_factor_auths/_recovery_codes.html.haml
deleted file mode 100644
index 054588b97d6..00000000000
--- a/app/views/settings/two_factor_auths/_recovery_codes.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-%p.hint= t('two_factor_auth.recovery_instructions')
-
-%ol.recovery-codes
- - recovery_codes.each do |code|
- %li
- %samp= code
diff --git a/app/views/settings/two_factor_auths/create.html.haml b/app/views/settings/two_factor_auths/create.html.haml
deleted file mode 100644
index aaeebaf2e0b..00000000000
--- a/app/views/settings/two_factor_auths/create.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-- content_for :page_title do
- = t('settings.two_factor_auth')
-
-= render 'recovery_codes', recovery_codes: @codes
diff --git a/app/views/settings/two_factor_auths/new.html.haml b/app/views/settings/two_factor_auths/new.html.haml
deleted file mode 100644
index 5bae743ef6f..00000000000
--- a/app/views/settings/two_factor_auths/new.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- content_for :page_title do
- = t('settings.two_factor_auth')
-
-= simple_form_for @confirmation, url: settings_two_factor_auth_path, method: :post do |f|
- %p.hint= t('two_factor_auth.instructions_html')
-
- .qr-wrapper
- .qr-code= raw @qrcode.as_svg(padding: 0, module_size: 4)
-
- .qr-alternative
- %p.hint= t('two_factor_auth.manual_instructions')
- %samp.qr-alternative__code= current_user.otp_secret.scan(/.{4}/).join(' ')
-
- = f.input :code, hint: t('two_factor_auth.code_hint'), placeholder: t('simple_form.labels.defaults.otp_attempt')
-
- .actions
- = f.button :button, t('two_factor_auth.enable'), type: :submit
diff --git a/app/views/settings/two_factor_auths/recovery_codes.html.haml b/app/views/settings/two_factor_auths/recovery_codes.html.haml
deleted file mode 100644
index aaeebaf2e0b..00000000000
--- a/app/views/settings/two_factor_auths/recovery_codes.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-- content_for :page_title do
- = t('settings.two_factor_auth')
-
-= render 'recovery_codes', recovery_codes: @codes
diff --git a/app/views/settings/two_factor_auths/show.html.haml b/app/views/settings/two_factor_auths/show.html.haml
deleted file mode 100644
index c966ecebfda..00000000000
--- a/app/views/settings/two_factor_auths/show.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- content_for :page_title do
- = t('settings.two_factor_auth')
-
-.simple_form
- %p.hint= t('two_factor_auth.description_html')
-
- - if current_user.otp_required_for_login
- = link_to t('two_factor_auth.disable'), disable_settings_two_factor_auth_path, data: { method: 'POST' }, class: 'block-button'
- - else
- = link_to t('two_factor_auth.setup'), new_settings_two_factor_auth_path, class: 'block-button'
-
-- if current_user.otp_required_for_login
- %p
-
- .simple_form
- %p.hint= t('two_factor_auth.lost_recovery_codes')
- = link_to t('two_factor_auth.generate_recovery_codes'), recovery_codes_settings_two_factor_auth_path, data: { method: 'POST' }, class: 'block-button'
diff --git a/config/locales/bg.yml b/config/locales/bg.yml
index f751c81a5d3..4d8c59eb83f 100644
--- a/config/locales/bg.yml
+++ b/config/locales/bg.yml
@@ -139,7 +139,7 @@ bg:
import: Импортиране
preferences: Предпочитания
settings: Настройки
- two_factor_auth: Двустепенно удостоверяване
+ two_factor_authentication: Двустепенно удостоверяване
statuses:
open_in_web: Отвори в уеб
over_character_limit: прехвърлен лимит от %{max} символа
@@ -155,7 +155,7 @@ bg:
time:
formats:
default: "%d %b, %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
description_html: При активация на двустепенно удостоверяване, за да влезеш в приложението, ще трябва да използваш телефона си. През него ще се генерира код, който да въвеждаш при влизане.
disable: Деактивирай
enable: Активирай
diff --git a/config/locales/en.yml b/config/locales/en.yml
index c1438134f7e..cf492e117ca 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -277,7 +277,7 @@ en:
import: Import
preferences: Preferences
settings: Settings
- two_factor_auth: Two-factor Authentication
+ two_factor_authentication: Two-factor Authentication
statuses:
open_in_web: Open in web
over_character_limit: character limit of %{max} exceeded
@@ -293,7 +293,7 @@ en:
time:
formats:
default: "%b %d, %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: Enter the code generated by your authenticator app to confirm
description_html: If you enable two-factor authentication, logging in will require you to be in possession of your phone, which will generate tokens for you to enter.
disable: Disable
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index 692fcc43a9a..7b36f397744 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -134,7 +134,7 @@ eo:
import: Alporti
preferences: Preferoj
settings: Agordoj
- two_factor_auth: Dufaktora aŭtentigo
+ two_factor_authentication: Dufaktora aŭtentigo
statuses:
open_in_web: Malfermi retumile
over_character_limit: limo de %{max} signoj trapasita
@@ -150,7 +150,7 @@ eo:
time:
formats:
default: "%b %d, %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
description_html: Se vi ebligas dufaktoran aŭtentigon, vi bezonos vian poŝtelefonon por ensaluti, ĉar ĝi kreos nombrojn, kiujn vi devos entajpi.
disable: Malebligi
enable: Ebligi
diff --git a/config/locales/es.yml b/config/locales/es.yml
index e99c592ff1a..60739c98d2c 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -139,7 +139,7 @@ es:
import: Importar
preferences: Preferencias
settings: Ajustes
- two_factor_auth: Autenticación de dos factores
+ two_factor_authentication: Autenticación de dos factores
statuses:
open_in_web: Abrir en web
over_character_limit: Límite de caracteres de %{max} superado
@@ -155,7 +155,7 @@ es:
time:
formats:
default: "%b %d, %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
description_html: Sí habilitas la autenticación de dos factores, se requerirá estar en posesión de su teléfono, lo que generará tokens para que usted pueda iniciar sesión.
disable: Deshabilitar
enable: Habilitar
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index 3d5e240af91..1694cb7617d 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -134,7 +134,7 @@ fi:
import: Tuo dataa
preferences: Ominaisuudet
settings: Asetukset
- two_factor_auth: Kaksivaiheinen tunnistus
+ two_factor_authentication: Kaksivaiheinen tunnistus
statuses:
open_in_web: Avaa webissä
over_character_limit: sallittu kirjanmäärä %{max} ylitetty
@@ -150,7 +150,7 @@ fi:
time:
formats:
default: "%b %d, %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
description_html: Jos otat käyttöön kaksivaiheisen tunnistuksen, kirjautumiseen vaaditaan puhelin, joka voi luoda tokeneita kirjautumista varten.
disable: Poista käytöstä
enable: Ota käyttöön
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index bd67b4409d7..03e5abd64e6 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -273,7 +273,7 @@ fr:
import: Import de données
preferences: Préférences
settings: Réglages
- two_factor_auth: Identification à deux facteurs (Two-factor auth)
+ two_factor_authentication: Identification à deux facteurs (Two-factor auth)
statuses:
open_in_web: Ouvrir sur le web
over_character_limit: limite de caractères dépassée de %{max} caractères
@@ -289,7 +289,7 @@ fr:
time:
formats:
default: "%d %b %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: Entrez le code généré par votre application pour confirmer
description_html: Si vous activez l'identification à deux facteurs, vous devrez être en possession de votre téléphone afin de générer un code de connexion.
disable: Désactiver
diff --git a/config/locales/hr.yml b/config/locales/hr.yml
index 598cf8ecce6..bd137af262b 100644
--- a/config/locales/hr.yml
+++ b/config/locales/hr.yml
@@ -136,7 +136,7 @@ hr:
import: Uvezi
preferences: Postavke
settings: Podešenja
- two_factor_auth: Dvo-faktorska Autentifikacija
+ two_factor_authentication: Dvo-faktorska Autentifikacija
statuses:
open_in_web: Otvori na webu
over_character_limit: prijeđen je limit od %{max} znakova
@@ -152,7 +152,7 @@ hr:
time:
formats:
default: "%b %d, %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
description_html: Ako omogućiš dvo-faktorsku autentifikaciju, prijavljivanje će zahtjevati da kod sebe imaš svoj mobitel, koji će generirati tokene koje ćeš unijeti.
disable: Onemogući
enable: Omogući
diff --git a/config/locales/id.yml b/config/locales/id.yml
index 2ddf982c0f6..2ebe680628d 100644
--- a/config/locales/id.yml
+++ b/config/locales/id.yml
@@ -250,7 +250,7 @@ id:
import: Impor
preferences: Pilihan
settings: Pengaturan
- two_factor_auth: Autentikasi Two-factor
+ two_factor_authentication: Autentikasi Two-factor
statuses:
open_in_web: Buka di web
over_character_limit: melebihi %{max} karakter
@@ -266,7 +266,7 @@ id:
time:
formats:
default: "%d %b %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: Masukkan kode yang dibuat oleh app autentikator sebagai konfirmasi
description_html: Jika anda menaktifkan ototentikasi dua faktor, saat login anda harus menggunakan telepon anda untuk membuat token supaya anda bisa masuk.
disable: Matikan
diff --git a/config/locales/io.yml b/config/locales/io.yml
index b4b1ce61ffe..98a7be3dced 100644
--- a/config/locales/io.yml
+++ b/config/locales/io.yml
@@ -276,7 +276,7 @@ io:
import: Importacar
preferences: Preferi
settings: Settings
- two_factor_auth: Dufaktora autentikigo
+ two_factor_authentication: Dufaktora autentikigo
statuses:
open_in_web: Apertar retnavigile
over_character_limit: limito de %{max} signi ecesita
@@ -292,7 +292,7 @@ io:
time:
formats:
default: "%b %d, %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: Enter the code generated by your authenticator app to confirm
description_html: Se tu posibligas dufaktora autentikigo, tu bezonos tua poshtelefonilo por enirar, nam ol kreos nombri, quin tu devos enskribar.
disable: Extingar
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 0ace8a76a37..a841df284ce 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -140,7 +140,7 @@ it:
import: Importa
preferences: Preferenze
settings: Impostazioni
- two_factor_auth: Autenticazione a Due Fattori
+ two_factor_authentication: Autenticazione a Due Fattori
statuses:
open_in_web: Apri sul Web
over_character_limit: Limite caratteri superato di %{max}
@@ -156,7 +156,7 @@ it:
time:
formats:
default: "%b %d, %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: Inserisci il codice generato dalla tua app di autenticazione
description_html: Se abiliti l'autorizzazione a due fattori, entrare nel tuo account ti richiederà di avere vicino il tuo telefono, il quale ti genererà un codice per eseguire l'accesso.
disable: Disabilita
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 47b86b38ec1..99606765438 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -276,7 +276,7 @@ ja:
import: データのインポート
preferences: ユーザー設定
settings: 設定
- two_factor_auth: 二段階認証
+ two_factor_authentication: 二段階認証
statuses:
open_in_web: Webで開く
over_character_limit: 上限は %{max}文字までです
@@ -292,7 +292,7 @@ ja:
time:
formats:
default: "%Y年%m月%d日 %H:%M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: 確認するには認証アプリで表示されたコードを入力してください
description_html: "二段階認証を有効にするとログイン時、電話でコードを受け取る必要があります。"
disable: 無効
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 543acbdfe5d..5dc398dc648 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -137,7 +137,7 @@ nl:
import: Import
preferences: Voorkeuren
settings: Instellingen
- two_factor_auth: Tweestapsverificatie
+ two_factor_authentication: Tweestapsverificatie
statuses:
open_in_web: Openen in web
over_character_limit: Limiet van %{max} tekens overschreden
@@ -153,7 +153,7 @@ nl:
time:
formats:
default: "%d %B %J om %U:%M"
- two_factor_auth:
+ two_factor_authentication:
description_html: Na het instellen van tweestapsverificatie, kun jij je alleen aanmelden als je jouw mobiele telefoon bij je hebt. Hiermee genereer je namelijk de in te voeren aanmeldcode.
disable: Uitschakelen
enable: Inschakelen
diff --git a/config/locales/no.yml b/config/locales/no.yml
index 41a55c6e62c..1b0648795dd 100644
--- a/config/locales/no.yml
+++ b/config/locales/no.yml
@@ -134,7 +134,7 @@
import: Importér
preferences: Preferanser
settings: Innstillinger
- two_factor_auth: Tofaktorautentisering
+ two_factor_authentication: Tofaktorautentisering
statuses:
open_in_web: Åpne i nettleser
over_character_limit: grense på %{max} tegn overskredet
@@ -150,7 +150,7 @@
time:
formats:
default: "%d, %b %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
description_html: Hvis du skrur på tofaktorautentisering må du ha din telefon for å logge inn. Denne vil generere koder som du må taste inn.
disable: Skru av
enable: Skru på
diff --git a/config/locales/oc.yml b/config/locales/oc.yml
index 46e32d8d320..dc345d0d888 100644
--- a/config/locales/oc.yml
+++ b/config/locales/oc.yml
@@ -292,7 +292,7 @@ oc:
import: Import
preferences: Preferéncias
settings: Paramètres
- two_factor_auth: Autentificacion en dos temps
+ two_factor_authentication: Autentificacion en dos temps
statuses:
open_in_web: Dobrir sul web
over_character_limit: limit de %{max} caractèrs passat
@@ -308,7 +308,7 @@ oc:
time:
formats:
default: "%b %d %Y a %H o %M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: Enter the code generated by your authenticator app to confirm
description_html: S’activatz l’autentificacion two-factor, vos
caldrà vòstre mobil per vos connectar perque generarà un geton per vos daissar
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index f213f3249ef..0242b7ca717 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -134,7 +134,7 @@ pl:
import: Importuj dane
preferences: Preferencje
settings: Ustawienia
- two_factor_auth: Uwierzytelnianie dwuetapowe
+ two_factor_authentication: Uwierzytelnianie dwuetapowe
statuses:
open_in_web: Otwórz w przeglądarce
over_character_limit: limit %{max} znaków przekroczony
@@ -150,7 +150,7 @@ pl:
time:
formats:
default: "%b %d, %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
description_html: Jeśli włączysz uwierzytelnianie dwustopniowe, logowanie się będzie wymagało podania tokenu wyświetlonego na Twoim telefone.
disable: Wyłącz
enable: Włącz
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 3d1869ebdb7..532e3dc07fc 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -267,7 +267,7 @@ ru:
import: Импорт
preferences: Настройки
settings: Опции
- two_factor_auth: Двухфакторная аутентификация
+ two_factor_authentication: Двухфакторная аутентификация
statuses:
open_in_web: Открыть в WWW
over_character_limit: превышен лимит символов (%{max})
@@ -283,7 +283,7 @@ ru:
time:
formats:
default: "%b %d, %Y, %H:%M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: Для подтверждения введите код, сгенерированный приложением аутентификатора
description_html: При включении двухфакторной аутентификации, вход потребует от Вас использования Вашего телефона, который сгенерирует входные токены.
disable: Отключить
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index e11e687888f..f89a3ecb67f 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -269,7 +269,7 @@ zh-CN:
export: 数据导出
preferences: 首选项
settings: 设置
- two_factor_auth: 两步认证
+ two_factor_authentication: 两步认证
statuses:
# Hey, this is already in a web browser!
open_in_web: 打开网页
@@ -286,7 +286,7 @@ zh-CN:
time:
formats:
default: "%Y年%-m月%d日 %H:%M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: 请输入你认证器产生的代码,以确认设置
description_html: 当你启用两步认证后,你登录时将额外需要使用手机或其他认证器生成的代码。
disable: 停用
diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml
index 289c9445af4..147385fad7e 100644
--- a/config/locales/zh-HK.yml
+++ b/config/locales/zh-HK.yml
@@ -276,7 +276,7 @@ zh-HK:
import: 匯入
preferences: 偏好設定
settings: 設定
- two_factor_auth: 雙重認證
+ two_factor_authentication: 雙重認證
statuses:
open_in_web: 開啟網頁
over_character_limit: 超過了 %{max} 字的限制
@@ -292,7 +292,7 @@ zh-HK:
time:
formats:
default: "%Y年%-m月%d日 %H:%M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: 請輸入你認證器產生的代碼,以確認設定
description_html: 當你啟用雙重認證後,你登入時將需要使你手機、或其他種類認證器產生的代碼。
disable: 停用
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index c29f2e2316e..965e007fdc4 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -248,7 +248,7 @@ zh-TW:
import: 匯入
preferences: 偏好設定
settings: 設定
- two_factor_auth: 雙因子認證
+ two_factor_authentication: 雙因子認證
statuses:
open_in_web: 以網頁開啟
over_character_limit: 超過了 %{max} 字的限制
@@ -264,7 +264,7 @@ zh-TW:
time:
formats:
default: "%Y年%-m月%d日 %H:%M"
- two_factor_auth:
+ two_factor_authentication:
code_hint: 請輸入您認證器產生的代碼,以進行認證
description_html: 當您啟用雙因子認證後,您登入時將需要使您手機、或其他種類認證器產生的代碼。
disable: 停用
diff --git a/config/navigation.rb b/config/navigation.rb
index a3f752e477e..bdc0a7b6c53 100644
--- a/config/navigation.rb
+++ b/config/navigation.rb
@@ -8,7 +8,7 @@ SimpleNavigation::Configuration.run do |navigation|
settings.item :profile, safe_join([fa_icon('user fw'), t('settings.edit_profile')]), settings_profile_url
settings.item :preferences, safe_join([fa_icon('sliders fw'), t('settings.preferences')]), settings_preferences_url
settings.item :password, safe_join([fa_icon('cog fw'), t('auth.change_password')]), edit_user_registration_url
- settings.item :two_factor_auth, safe_join([fa_icon('mobile fw'), t('settings.two_factor_auth')]), settings_two_factor_auth_url, highlights_on: %r{/settings/two_factor_auth}
+ settings.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_url, highlights_on: %r{/settings/two_factor_authentication}
settings.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_import_url
settings.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_url
settings.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url
diff --git a/config/routes.rb b/config/routes.rb
index d9b36661e62..abc77535ab3 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -58,11 +58,10 @@ Rails.application.routes.draw do
resources :mutes, only: :index, controller: :muted_accounts
end
- resource :two_factor_auth, only: [:show, :new, :create] do
- member do
- post :disable
- post :recovery_codes
- end
+ resource :two_factor_authentication, only: [:show, :create, :destroy]
+ namespace :two_factor_authentication do
+ resources :recovery_codes, only: [:create]
+ resource :confirmation, only: [:new, :create]
end
end
diff --git a/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb
new file mode 100644
index 00000000000..bf555078e47
--- /dev/null
+++ b/spec/controllers/settings/two_factor_authentication/confirmations_controller_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Settings::TwoFactorAuthentication::ConfirmationsController do
+ render_views
+
+ let(:user) { Fabricate(:user) }
+ before do
+ user.otp_secret = User.generate_otp_secret(32)
+ user.save!
+
+ sign_in user, scope: :user
+ end
+
+ describe 'GET #new' do
+ it 'returns http success' do
+ get :new
+
+ expect(response).to have_http_status(:success)
+ expect(response).to render_template(:new)
+ end
+ end
+
+ describe 'POST #create' do
+ describe 'when creation succeeds' do
+ it 'renders page with success' do
+ allow_any_instance_of(User).to receive(:validate_and_consume_otp!).with('123456').and_return(true)
+
+ post :create, params: { form_two_factor_confirmation: { code: '123456' } }
+ expect(response).to have_http_status(:success)
+ expect(response).to render_template('settings/two_factor_authentication/recovery_codes/index')
+ end
+ end
+
+ describe 'when creation fails' do
+ it 'renders the new view' do
+ allow_any_instance_of(User).to receive(:validate_and_consume_otp!).with('123456').and_return(false)
+
+ post :create, params: { form_two_factor_confirmation: { code: '123456' } }
+ expect(response).to have_http_status(:success)
+ expect(response).to render_template(:new)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb b/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb
new file mode 100644
index 00000000000..3d6f5faab18
--- /dev/null
+++ b/spec/controllers/settings/two_factor_authentication/recovery_codes_controller_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Settings::TwoFactorAuthentication::RecoveryCodesController do
+ render_views
+
+ let(:user) { Fabricate(:user) }
+ before do
+ sign_in user, scope: :user
+ end
+
+ describe 'POST #create' do
+ it 'updates the codes and shows them on a view' do
+ before = user.otp_backup_codes
+
+ post :create
+ user.reload
+
+ expect(user.otp_backup_codes).not_to eq(before)
+ expect(response).to have_http_status(:success)
+ expect(response).to render_template(:index)
+ end
+ end
+end
diff --git a/spec/controllers/settings/two_factor_authentications_controller_spec.rb b/spec/controllers/settings/two_factor_authentications_controller_spec.rb
new file mode 100644
index 00000000000..25d7a928d16
--- /dev/null
+++ b/spec/controllers/settings/two_factor_authentications_controller_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe Settings::TwoFactorAuthenticationsController do
+ render_views
+
+ let(:user) { Fabricate(:user) }
+ before do
+ sign_in user, scope: :user
+ end
+
+ describe 'GET #show' do
+ describe 'when user requires otp for login already' do
+ it 'returns http success' do
+ user.update(otp_required_for_login: true)
+ get :show
+
+ expect(response).to have_http_status(:success)
+ end
+ end
+
+ describe 'when user does not require otp for login' do
+ it 'returns http success' do
+ user.update(otp_required_for_login: false)
+ get :show
+
+ expect(response).to have_http_status(:success)
+ end
+ end
+ end
+
+ describe 'POST #create' do
+ describe 'when user requires otp for login already' do
+ it 'redirects to show page' do
+ user.update(otp_required_for_login: true)
+ post :create
+
+ expect(response).to redirect_to(settings_two_factor_authentication_path)
+ end
+ end
+
+ describe 'when creation succeeds' do
+ it 'updates user secret' do
+ before = user.otp_secret
+ post :create
+
+ expect(user.reload.otp_secret).not_to eq(before)
+ expect(response).to redirect_to(new_settings_two_factor_authentication_confirmation_path)
+ end
+ end
+ end
+
+ describe 'POST #destroy' do
+ before do
+ user.update(otp_required_for_login: true)
+ end
+ it 'turns off otp requirement' do
+ post :destroy
+
+ expect(response).to redirect_to(settings_two_factor_authentication_path)
+ user.reload
+ expect(user.otp_required_for_login).to eq(false)
+ end
+ end
+end