66 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			66 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			Ruby
		
	
	
	
# frozen_string_literal: true
 | 
						|
 | 
						|
# This concern is inspired by "sudo mode" on GitHub. It
 | 
						|
# is a way to re-authenticate a user before allowing them
 | 
						|
# to see or perform an action.
 | 
						|
#
 | 
						|
# Add `before_action :require_challenge!` to actions you
 | 
						|
# want to protect.
 | 
						|
#
 | 
						|
# The user will be shown a page to enter the challenge (which
 | 
						|
# is either the password, or just the username when no
 | 
						|
# password exists). Upon passing, there is a grace period
 | 
						|
# during which no challenge will be asked from the user.
 | 
						|
#
 | 
						|
# Accessing challenge-protected resources during the grace
 | 
						|
# period will refresh the grace period.
 | 
						|
module ChallengableConcern
 | 
						|
  extend ActiveSupport::Concern
 | 
						|
 | 
						|
  CHALLENGE_TIMEOUT = 1.hour.freeze
 | 
						|
 | 
						|
  def require_challenge!
 | 
						|
    return if skip_challenge?
 | 
						|
 | 
						|
    if challenge_passed_recently?
 | 
						|
      session[:challenge_passed_at] = Time.now.utc
 | 
						|
      return
 | 
						|
    end
 | 
						|
 | 
						|
    @challenge = Form::Challenge.new(return_to: request.url)
 | 
						|
 | 
						|
    if params.key?(:form_challenge)
 | 
						|
      if challenge_passed?
 | 
						|
        session[:challenge_passed_at] = Time.now.utc
 | 
						|
        return
 | 
						|
      else
 | 
						|
        flash.now[:alert] = I18n.t('challenge.invalid_password')
 | 
						|
        render_challenge
 | 
						|
      end
 | 
						|
    else
 | 
						|
      render_challenge
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def render_challenge
 | 
						|
    @body_classes = 'lighter'
 | 
						|
    render template: 'auth/challenges/new', layout: 'auth'
 | 
						|
  end
 | 
						|
 | 
						|
  def challenge_passed?
 | 
						|
    current_user.valid_password?(challenge_params[:current_password])
 | 
						|
  end
 | 
						|
 | 
						|
  def skip_challenge?
 | 
						|
    current_user.encrypted_password.blank?
 | 
						|
  end
 | 
						|
 | 
						|
  def challenge_passed_recently?
 | 
						|
    session[:challenge_passed_at].present? && session[:challenge_passed_at] >= CHALLENGE_TIMEOUT.ago
 | 
						|
  end
 | 
						|
 | 
						|
  def challenge_params
 | 
						|
    params.require(:form_challenge).permit(:current_password, :return_to)
 | 
						|
  end
 | 
						|
end
 |