webauthn_credentials_controller.rb 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. # frozen_string_literal: true
  2. module Settings
  3. module TwoFactorAuthentication
  4. class WebauthnCredentialsController < BaseController
  5. layout 'admin'
  6. before_action :authenticate_user!
  7. before_action :require_otp_enabled
  8. before_action :require_webauthn_enabled, only: [:index, :destroy]
  9. def new; end
  10. def index; end
  11. def options
  12. current_user.update(webauthn_id: WebAuthn.generate_user_id) unless current_user.webauthn_id
  13. options_for_create = WebAuthn::Credential.options_for_create(
  14. user: {
  15. name: current_user.account.username,
  16. display_name: current_user.account.username,
  17. id: current_user.webauthn_id,
  18. },
  19. exclude: current_user.webauthn_credentials.pluck(:external_id)
  20. )
  21. session[:webauthn_challenge] = options_for_create.challenge
  22. render json: options_for_create, status: :ok
  23. end
  24. def create
  25. webauthn_credential = WebAuthn::Credential.from_create(params[:credential])
  26. if webauthn_credential.verify(session[:webauthn_challenge])
  27. user_credential = current_user.webauthn_credentials.build(
  28. external_id: webauthn_credential.id,
  29. public_key: webauthn_credential.public_key,
  30. nickname: params[:nickname],
  31. sign_count: webauthn_credential.sign_count
  32. )
  33. if user_credential.save
  34. flash[:success] = I18n.t('webauthn_credentials.create.success')
  35. status = :ok
  36. if current_user.webauthn_credentials.size == 1
  37. UserMailer.webauthn_enabled(current_user).deliver_later!
  38. else
  39. UserMailer.webauthn_credential_added(current_user, user_credential).deliver_later!
  40. end
  41. else
  42. flash[:error] = I18n.t('webauthn_credentials.create.error')
  43. status = :internal_server_error
  44. end
  45. else
  46. flash[:error] = t('webauthn_credentials.create.error')
  47. status = :unauthorized
  48. end
  49. render json: { redirect_path: settings_two_factor_authentication_methods_path }, status: status
  50. end
  51. def destroy
  52. credential = current_user.webauthn_credentials.find_by(id: params[:id])
  53. if credential
  54. credential.destroy
  55. if credential.destroyed?
  56. flash[:success] = I18n.t('webauthn_credentials.destroy.success')
  57. if current_user.webauthn_credentials.empty?
  58. UserMailer.webauthn_disabled(current_user).deliver_later!
  59. else
  60. UserMailer.webauthn_credential_deleted(current_user, credential).deliver_later!
  61. end
  62. else
  63. flash[:error] = I18n.t('webauthn_credentials.destroy.error')
  64. end
  65. else
  66. flash[:error] = I18n.t('webauthn_credentials.destroy.error')
  67. end
  68. redirect_to settings_two_factor_authentication_methods_path
  69. end
  70. private
  71. def require_otp_enabled
  72. unless current_user.otp_enabled?
  73. flash[:error] = t('webauthn_credentials.otp_required')
  74. redirect_to settings_two_factor_authentication_methods_path
  75. end
  76. end
  77. def require_webauthn_enabled
  78. unless current_user.webauthn_enabled?
  79. flash[:error] = t('webauthn_credentials.not_enabled')
  80. redirect_to settings_two_factor_authentication_methods_path
  81. end
  82. end
  83. end
  84. end
  85. end