<commit_before>module Devise
  module Models
    # 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])/
    #
    module SecureValidatable

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

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

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

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

            validates :password, :presence => true, :length => password_length, :confirmation => true, :if => :password_required?
          end

          # extra validations
          validates :email,    :email  => email_validation if email_validation # use rails_email_validator or similar
          validates :password, :format => { :with => password_regex, :message => :password_format }, :if => :password_required?

          # don't allow use of the same password
          # validate :current_equal_password_validation

          # Don't allow repetition of character
          validate :char_repetition_validation, :if => :password_required?
        end
      end

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

      def current_equal_password_validation
        if not self.new_record? and not self.encrypted_password_change.nil?
          dummy = self.class.new
          dummy.encrypted_password = self.encrypted_password_change.first
          dummy.password_salt = self.password_salt_change.first if self.respond_to? :password_salt_change and not self.password_salt_change.nil?
          self.errors.add(:password, :equal_to_current_password) if dummy.valid_password?(self.password)
        end
      end

      def char_repetition_validation
        if !!self.char_limitable and self.class.char_repeatable_limit > 0
          char_counts = Hash.new 0
          self.password.split('').each do |char|
            char_counts[char] += 1
            if char_counts[char] > self.class.char_repeatable_limit
              self.errors.add(:password, :char_repeated, :char_repeatable_limit => self.class.char_repeatable_limit)
              break
            end
          end
        end
      end

      protected

      # Checks whether a password is needed or not. For validations only.
      # Passwords are always required if it's a new record, or if the password
      # or confirmation are being set somewhere.
      def password_required?
        !persisted? || !password.nil? || !password_confirmation.nil?
      end

      def email_required?
        true
      end<commit_msg>TTI-3565 Char repeating limit for consecutive chars<commit_after>module Devise
  module Models
    # 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])/
    #
    module SecureValidatable

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

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

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

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

            validates :password, :presence => true, :length => password_length, :confirmation => true, :if => :password_required?
          end

          # extra validations
          validates :email,    :email  => email_validation if email_validation # use rails_email_validator or similar
          validates :password, :format => { :with => password_regex, :message => :password_format }, :if => :password_required?

          # don't allow use of the same password
          # validate :current_equal_password_validation

          # Don't allow repetition of character
          validate :char_repetition_validation, :if => :password_required?
        end
      end

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

      def current_equal_password_validation
        if not self.new_record? and not self.encrypted_password_change.nil?
          dummy = self.class.new
          dummy.encrypted_password = <PASSWORD>.encrypted_password_<PASSWORD>
          dummy.password_salt = self.password_salt_change.first if self.respond_to? :password_salt_change and not self.password_salt_change.nil?
          self.errors.add(:password, :equal_<PASSWORD>password) if dummy.valid_password?(self.password)
        end
      end

      def char_repetition_validation
        if !!self.char_limitable and self.class.char_repeatable_limit > 0
          if /(.)\1{#{self.class.char_repeatable_limit},}/ =~ self.password
              self.errors.add(:password, :char_repeated, :char_repeatable_limit => self.class.char_repeatable_limit)
              break
          end
        end
      end

      protected

      # Checks whether a password is needed or not. For validations only.
      # Passwords are always required if it's a new record, or if the password
      # or confirmation are being set somewhere.
      def password_required?
        !persisted? || !password.nil? || !password_confirmation.nil?
      end

      def email_required?
        true
      end
{'fraction_non_alphanumeric': 0.08291805094130676, 'fraction_numerical': 0.0017995570321151717, 'mean_word_length': 2.324896456511735, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3949503', 'n_tokens_mistral': 1935, 'n_tokens_neox': 1852, 'n_words': 510}