0
0
Fork 0

2FA controller cleanup (#2296)

* Add spec coverage for settings/two_factor_auth area

* extract setup method for qr code

* Move otp required check to before action

* Merge method only used once

* Remove duplicate view

* Consolidate creation of @codes for backup

* Move settings/2fq#recovery_codes to settings/recovery_codes#create

* Rename settings/two_factor_auth#disable to #destroy

* Add coverage for the otp required path on 2fa#show

* Clean up the recovery codes list styles

* Move settings/two_factor_auth to settings/two_factor_authentication

* Reorganize the settings two factor auth area

Updated to use a flow like:

- settings/two_factor_authentication goes to a #show view which has a button
  either enable or disable 2fa on the account
- the disable button turns off the otp requirement for the user
- the enable button cycles the user secret and redirects to a confirmation page
- the confirmation page is a #new view which shows the QR code for user
- that page posts to #create which verifies the code, and creates the recovery
  codes
- that create action shares a view with a recovery codes controller which can be
  used separately to reset codes if needed
This commit is contained in:
Matt Jankowski 2017-04-21 22:23:17 -04:00 committed by Eugen
parent 6af21daac9
commit 67dea31b0f
38 changed files with 333 additions and 150 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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