anyone-oslo/pages

View on GitHub
app/models/concerns/pages_core/authenticable_user.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
96%
# frozen_string_literal: true

module PagesCore
  module AuthenticableUser
    extend ActiveSupport::Concern

    included do
      has_secure_password

      validates(:otp_secret, presence: true, if: :otp_enabled?)
      validates(
        :password,
        length: {
          minimum: 8,
          maximum: ActiveModel::SecurePassword::MAX_PASSWORD_LENGTH_ALLOWED,
          allow_blank: true
        }
      )

      after_initialize { |u| u.session_token ||= u.class.random_session_token }
      before_validation :update_session_token
    end

    module ClassMethods
      def authenticate(email, password:)
        User.find_by(email:).try(:authenticate, password)
      end

      def random_session_token
        SecureRandom.hex(32)
      end
    end

    def can_login?
      activated?
    end

    def recovery_codes=(codes)
      self.hashed_recovery_codes = codes.map do |c|
        BCrypt::Password.create(c, cost: 8)
      end
    end

    def use_recovery_code!(code)
      valid_hashes = hashed_recovery_codes.select do |c|
        BCrypt::Password.new(c) == code
      end
      return false unless valid_hashes.any?

      update(hashed_recovery_codes: hashed_recovery_codes - valid_hashes)
      true
    end

    private

    def update_session_token
      return unless password_digest_changed? ||
                    otp_enabled_changed?

      self.session_token = self.class.random_session_token
    end
  end
end