You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

65 lines
1.7 KiB

  1. # frozen_string_literal: true
  2. # This concern is inspired by "sudo mode" on GitHub. It
  3. # is a way to re-authenticate a user before allowing them
  4. # to see or perform an action.
  5. #
  6. # Add `before_action :require_challenge!` to actions you
  7. # want to protect.
  8. #
  9. # The user will be shown a page to enter the challenge (which
  10. # is either the password, or just the username when no
  11. # password exists). Upon passing, there is a grace period
  12. # during which no challenge will be asked from the user.
  13. #
  14. # Accessing challenge-protected resources during the grace
  15. # period will refresh the grace period.
  16. module ChallengableConcern
  17. extend ActiveSupport::Concern
  18. CHALLENGE_TIMEOUT = 1.hour.freeze
  19. def require_challenge!
  20. return if skip_challenge?
  21. if challenge_passed_recently?
  22. session[:challenge_passed_at] = Time.now.utc
  23. return
  24. end
  25. @challenge = Form::Challenge.new(return_to: request.url)
  26. if params.key?(:form_challenge)
  27. if challenge_passed?
  28. session[:challenge_passed_at] = Time.now.utc
  29. return
  30. else
  31. flash.now[:alert] = I18n.t('challenge.invalid_password')
  32. render_challenge
  33. end
  34. else
  35. render_challenge
  36. end
  37. end
  38. def render_challenge
  39. @body_classes = 'lighter'
  40. render template: 'auth/challenges/new', layout: 'auth'
  41. end
  42. def challenge_passed?
  43. current_user.valid_password?(challenge_params[:current_password])
  44. end
  45. def skip_challenge?
  46. current_user.encrypted_password.blank?
  47. end
  48. def challenge_passed_recently?
  49. session[:challenge_passed_at].present? && session[:challenge_passed_at] >= CHALLENGE_TIMEOUT.ago
  50. end
  51. def challenge_params
  52. params.require(:form_challenge).permit(:current_password, :return_to)
  53. end
  54. end