Module: Devise::Models::SecureValidatable

Includes:
Compatibility
Defined in:
lib/devise-security/models/secure_validatable.rb

Overview

SecureValidatable creates better validations with more validation for security

Options

SecureValidatable adds the following options to devise_for:

* +email_regexp+: the regular expression used to validate e-mails;
* +password_length+: a range expressing password length. Defaults from devise
* +password_regex+: need strong password. Defaults to /(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.assert_secure_validations_api!(base) ⇒ Object



83
84
85
# File 'lib/devise-security/models/secure_validatable.rb', line 83

def self.assert_secure_validations_api!(base)
  raise "Could not use SecureValidatable on #{base}" unless base.respond_to?(:validates)
end

.included(base) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/devise-security/models/secure_validatable.rb', line 21

def self.included(base)
  base.extend ClassMethods
  assert_secure_validations_api!(base)

  base.class_eval do
    already_validated_email = false

    # validate login in a strict way if not yet validated
    unless has_uniqueness_validation_of_login?
      validation_condition = "#{}_changed?".to_sym

      validates , uniqueness: {
                                    scope:          authentication_keys[1..-1],
                                    case_sensitive: !!case_insensitive_keys
                                  },
                                  if: validation_condition

      already_validated_email = .to_s == 'email'
    end

    unless devise_validation_enabled?
      validates :email, presence: true, if: :email_required?
      unless already_validated_email
        validates :email, uniqueness: true, allow_blank: true, if: :email_changed? # check uniq for email ever
      end

      validates_presence_of :password, if: :password_required?
      validates_confirmation_of :password, if: :password_required?

      validate if: :password_required? do |record|
        validates_with ActiveModel::Validations::LengthValidator,
                       attributes: :password,
                       allow_blank: true,
                       in: record.password_length
      end
    end

    # extra validations
    # see https://github.com/devise-security/devise-security/blob/master/README.md#e-mail-validation
    validate do |record|
      if email_validation
        validates_with(
          EmailValidator, { attributes: :email }
        )
      end
    end

    validate if: :password_required? do |record|
      validates_with(
        record.password_complexity_validator.is_a?(Class) ? record.password_complexity_validator : record.password_complexity_validator.classify.constantize,
        { attributes: :password }.merge(record.password_complexity)
      )
    end

    # don't allow use same password
    validate :current_equal_password_validation

    # don't allow email to equal password
    validate :email_not_equal_password_validation
  end
end

Instance Method Details

#current_equal_password_validationObject



87
88
89
90
91
92
93
# File 'lib/devise-security/models/secure_validatable.rb', line 87

def current_equal_password_validation
  return if new_record? || !will_save_change_to_encrypted_password? || password.blank?
  dummy = self.class.new(encrypted_password: encrypted_password_was).tap do |user|
    user.password_salt = password_salt_was if respond_to?(:password_salt)
  end
  self.errors.add(:password, :equal_to_current_password) if dummy.valid_password?(password)
end

#email_not_equal_password_validationObject



95
96
97
98
99
100
101
102
103
# File 'lib/devise-security/models/secure_validatable.rb', line 95

def email_not_equal_password_validation
  return if allow_passwords_equal_to_email

  return if password.blank? || email.blank? || (!new_record? && !will_save_change_to_encrypted_password?)

  return unless Devise.secure_compare(password.downcase.strip, email.downcase.strip)

  errors.add(:password, :equal_to_email)
end