diff options
author | Starfall <us@starfall.systems> | 2020-08-31 12:28:25 -0500 |
---|---|---|
committer | Starfall <us@starfall.systems> | 2020-08-31 12:28:25 -0500 |
commit | c5bb91194f0df90ea9c59ea6af1bd985b295fb30 (patch) | |
tree | 47b303b2c64ff1920fb19d01093a08dc9fd20ac8 /app/controllers/settings | |
parent | 27ee0fc8c4c13c53f81ca3db781b9d0783b877e5 (diff) | |
parent | f715e8b51612820a18fa307e4465eb0c1a088f86 (diff) |
Merge branch 'glitch' into main
Diffstat (limited to 'app/controllers/settings')
5 files changed, 189 insertions, 57 deletions
diff --git a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb index ef4df3339..9f23011a7 100644 --- a/app/controllers/settings/two_factor_authentication/confirmations_controller.rb +++ b/app/controllers/settings/two_factor_authentication/confirmations_controller.rb @@ -18,18 +18,21 @@ module Settings end def create - if current_user.validate_and_consume_otp!(confirmation_params[:otp_attempt]) + if current_user.validate_and_consume_otp!(confirmation_params[:otp_attempt], otp_secret: session[:new_otp_secret]) flash.now[:notice] = I18n.t('two_factor_authentication.enabled_success') current_user.otp_required_for_login = true + current_user.otp_secret = session[:new_otp_secret] @recovery_codes = current_user.generate_otp_backup_codes! current_user.save! UserMailer.two_factor_enabled(current_user).deliver_later! + session.delete(:new_otp_secret) + render 'settings/two_factor_authentication/recovery_codes/index' else - flash.now[:alert] = I18n.t('two_factor_authentication.wrong_code') + flash.now[:alert] = I18n.t('otp_authentication.wrong_code') prepare_two_factor_form render :new end @@ -43,12 +46,15 @@ module Settings 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) + @new_otp_secret = session[:new_otp_secret] + @provision_url = current_user.otp_provisioning_uri(current_user.email, + otp_secret: @new_otp_secret, + issuer: Rails.configuration.x.local_domain) @qrcode = RQRCode::QRCode.new(@provision_url) end def ensure_otp_secret - redirect_to settings_two_factor_authentication_path unless current_user.otp_secret + redirect_to settings_otp_authentication_path if session[:new_otp_secret].blank? end end end diff --git a/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb b/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb new file mode 100644 index 000000000..6836f7ef6 --- /dev/null +++ b/app/controllers/settings/two_factor_authentication/otp_authentication_controller.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Settings + module TwoFactorAuthentication + class OtpAuthenticationController < BaseController + include ChallengableConcern + + layout 'admin' + + before_action :authenticate_user! + before_action :verify_otp_not_enabled, only: [:show] + before_action :require_challenge!, only: [:create] + + skip_before_action :require_functional! + + def show + @confirmation = Form::TwoFactorConfirmation.new + end + + def create + session[:new_otp_secret] = User.generate_otp_secret(32) + + redirect_to new_settings_two_factor_authentication_confirmation_path + end + + private + + def confirmation_params + params.require(:form_two_factor_confirmation).permit(:otp_attempt) + end + + def verify_otp_not_enabled + redirect_to settings_two_factor_authentication_methods_path if current_user.otp_enabled? + end + + def acceptable_code? + current_user.validate_and_consume_otp!(confirmation_params[:otp_attempt]) || + current_user.invalidate_otp_backup_code!(confirmation_params[:otp_attempt]) + end + end + end +end diff --git a/app/controllers/settings/two_factor_authentication/webauthn_credentials_controller.rb b/app/controllers/settings/two_factor_authentication/webauthn_credentials_controller.rb new file mode 100644 index 000000000..ee5392785 --- /dev/null +++ b/app/controllers/settings/two_factor_authentication/webauthn_credentials_controller.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +module Settings + module TwoFactorAuthentication + class WebauthnCredentialsController < BaseController + layout 'admin' + + before_action :authenticate_user! + before_action :require_otp_enabled + before_action :require_webauthn_enabled, only: [:index, :destroy] + + def new; end + + def index; end + + def options + current_user.update(webauthn_id: WebAuthn.generate_user_id) unless current_user.webauthn_id + + options_for_create = WebAuthn::Credential.options_for_create( + user: { + name: current_user.account.username, + display_name: current_user.account.username, + id: current_user.webauthn_id, + }, + exclude: current_user.webauthn_credentials.pluck(:external_id) + ) + + session[:webauthn_challenge] = options_for_create.challenge + + render json: options_for_create, status: :ok + end + + def create + webauthn_credential = WebAuthn::Credential.from_create(params[:credential]) + + if webauthn_credential.verify(session[:webauthn_challenge]) + user_credential = current_user.webauthn_credentials.build( + external_id: webauthn_credential.id, + public_key: webauthn_credential.public_key, + nickname: params[:nickname], + sign_count: webauthn_credential.sign_count + ) + + if user_credential.save + flash[:success] = I18n.t('webauthn_credentials.create.success') + status = :ok + + if current_user.webauthn_credentials.size == 1 + UserMailer.webauthn_enabled(current_user).deliver_later! + else + UserMailer.webauthn_credential_added(current_user, user_credential).deliver_later! + end + else + flash[:error] = I18n.t('webauthn_credentials.create.error') + status = :internal_server_error + end + else + flash[:error] = t('webauthn_credentials.create.error') + status = :unauthorized + end + + render json: { redirect_path: settings_two_factor_authentication_methods_path }, status: status + end + + def destroy + credential = current_user.webauthn_credentials.find_by(id: params[:id]) + if credential + credential.destroy + if credential.destroyed? + flash[:success] = I18n.t('webauthn_credentials.destroy.success') + + if current_user.webauthn_credentials.empty? + UserMailer.webauthn_disabled(current_user).deliver_later! + else + UserMailer.webauthn_credential_deleted(current_user, credential).deliver_later! + end + else + flash[:error] = I18n.t('webauthn_credentials.destroy.error') + end + else + flash[:error] = I18n.t('webauthn_credentials.destroy.error') + end + redirect_to settings_two_factor_authentication_methods_path + end + + private + + def set_pack + use_pack 'auth' + end + + def require_otp_enabled + unless current_user.otp_enabled? + flash[:error] = t('webauthn_credentials.otp_required') + redirect_to settings_two_factor_authentication_methods_path + end + end + + def require_webauthn_enabled + unless current_user.webauthn_enabled? + flash[:error] = t('webauthn_credentials.not_enabled') + redirect_to settings_two_factor_authentication_methods_path + end + end + end + end +end diff --git a/app/controllers/settings/two_factor_authentication_methods_controller.rb b/app/controllers/settings/two_factor_authentication_methods_controller.rb new file mode 100644 index 000000000..224d3a45c --- /dev/null +++ b/app/controllers/settings/two_factor_authentication_methods_controller.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Settings + class TwoFactorAuthenticationMethodsController < BaseController + include ChallengableConcern + + layout 'admin' + + before_action :authenticate_user! + before_action :require_challenge!, only: :disable + before_action :require_otp_enabled + + skip_before_action :require_functional! + + def index; end + + def disable + current_user.disable_two_factor! + UserMailer.two_factor_disabled(current_user).deliver_later! + + redirect_to settings_otp_authentication_path, flash: { notice: I18n.t('two_factor_authentication.disabled_success') } + end + + private + + def require_otp_enabled + redirect_to settings_otp_authentication_path unless current_user.otp_enabled? + end + end +end diff --git a/app/controllers/settings/two_factor_authentications_controller.rb b/app/controllers/settings/two_factor_authentications_controller.rb deleted file mode 100644 index 9118a7933..000000000 --- a/app/controllers/settings/two_factor_authentications_controller.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -module Settings - class TwoFactorAuthenticationsController < BaseController - include ChallengableConcern - - layout 'admin' - - before_action :authenticate_user! - before_action :verify_otp_required, only: [:create] - before_action :require_challenge!, only: [:create] - - skip_before_action :require_functional! - - def show - @confirmation = Form::TwoFactorConfirmation.new - 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 - if acceptable_code? - current_user.otp_required_for_login = false - current_user.save! - UserMailer.two_factor_disabled(current_user).deliver_later! - redirect_to settings_two_factor_authentication_path - else - flash.now[:alert] = I18n.t('two_factor_authentication.wrong_code') - @confirmation = Form::TwoFactorConfirmation.new - render :show - end - end - - private - - def confirmation_params - params.require(:form_two_factor_confirmation).permit(:otp_attempt) - end - - def verify_otp_required - redirect_to settings_two_factor_authentication_path if current_user.otp_required_for_login? - end - - def acceptable_code? - current_user.validate_and_consume_otp!(confirmation_params[:otp_attempt]) || - current_user.invalidate_otp_backup_code!(confirmation_params[:otp_attempt]) - end - end -end |