class PasswordStrength::Base

Constants

GOOD
INVALID
MULTIPLE_NUMBERS_RE
MULTIPLE_SYMBOLS_RE
STRONG
SYMBOL_RE
UPPERCASE_LOWERCASE_RE
WEAK

Attributes

exclude[RW]

Set what characters cannot be present on password. Can be a regular expression or array.

strength = PasswordStrength.test("john", "password with whitespaces", :exclude => [" ", "asdf"])
strength = PasswordStrength.test("john", "password with whitespaces", :exclude => /\s/)

Then you can check the test result:

strength.valid?(:weak)
#=> false

strength.status
#=> :invalid
password[RW]

The password that will be tested.

record[R]

The ActiveRecord instance. It only makes sense if you’re creating a custom ActiveRecord validator.

score[R]

The score for the latest test. Will be nil if the password has not been tested.

status[R]

The current test status. Can be :weak, :good, :strong or :invalid.

username[RW]

Hold the username that will be matched against password.

Public Class Methods

common_words() click to toggle source

Return an array of strings that represents common passwords. The default list is taken from several online sources (just Google for ‘most common passwords’).

Notable sources:

The current list has 3.6KB and its load into memory just once.

# File lib/password_strength/base.rb, line 54
def self.common_words
  @common_words ||= begin
    file = File.open(File.expand_path("../../../support/common.txt", __FILE__))
    words = file.each_line.to_a.map(&:chomp)
    file.close
    words
  end
end
new(username, password, options = {}) click to toggle source
# File lib/password_strength/base.rb, line 63
def initialize(username, password, options = {})
  @username = username.to_s
  @password = password.to_s
  @score = 0
  @exclude = options[:exclude]
  @record = options[:record]
end

Public Instance Methods

contain_invalid_repetion?() click to toggle source
# File lib/password_strength/base.rb, line 228
def contain_invalid_repetion?
  char = password.to_s.chars.first
  return unless char
  regex = /^#{Regexp.escape(char)}+$/i
  password.to_s =~ regex
end
good!() click to toggle source

Mark password as good.

# File lib/password_strength/base.rb, line 110
def good!
  @status = GOOD
end
good?() click to toggle source

Check if the password has been detected as good.

# File lib/password_strength/base.rb, line 105
def good?
  status == GOOD
end
invalid!() click to toggle source

Mark password as invalid.

# File lib/password_strength/base.rb, line 120
def invalid!
  @status = INVALID
end
invalid?() click to toggle source

Check if password has invalid characters based on PasswordStrength::Base#exclude.

# File lib/password_strength/base.rb, line 115
def invalid?
  status == INVALID
end
score_for(name) click to toggle source

Return the score for the specified rule. Available rules:

  • :password_size

  • :numbers

  • :symbols

  • :uppercase_lowercase

  • :numbers_chars

  • :numbers_symbols

  • :symbols_chars

  • :only_chars

  • :only_numbers

  • :username

  • :sequences

# File lib/password_strength/base.rb, line 138
def score_for(name)
  score = 0

  case name
  when :password_size then
    if password.size < 6
      score = -100
    else
      score = password.size * 4
    end
  when :numbers then
    score = 5 if password =~ MULTIPLE_NUMBERS_RE
  when :symbols then
    score = 5 if password =~ MULTIPLE_SYMBOLS_RE
  when :uppercase_lowercase then
    score = 10 if password =~ UPPERCASE_LOWERCASE_RE
  when :numbers_chars then
    score = 15 if password =~ /[a-z]/i && password =~ /[0-9]/
  when :numbers_symbols then
    score = 15 if password =~ /[0-9]/ && password =~ SYMBOL_RE
  when :symbols_chars then
    score = 15 if password =~ /[a-z]/i && password =~ SYMBOL_RE
  when :only_chars then
    score = -15 if password =~ /^[a-z]+$/i
  when :only_numbers then
    score = -15 if password =~ /^\d+$/
  when :username then
    if password == username
      score = -100
    else
      score = -15 if password =~ /#{Regexp.escape(username)}/
    end
  when :sequences then
    score = -15 * sequences(password)
    score += -15 * sequences(password.to_s.reverse)
  when :repetitions then
    score += -(repetitions(password, 2) * 4)
    score += -(repetitions(password, 3) * 3)
    score += -(repetitions(password, 4) * 2)
  end

  score
end
strong!() click to toggle source

Mark password as strong.

# File lib/password_strength/base.rb, line 90
def strong!
  @status = STRONG
end
strong?() click to toggle source

Check if the password has been detected as strong.

# File lib/password_strength/base.rb, line 85
def strong?
  status == STRONG
end
test() click to toggle source

Run all tests on password and return the final score.

# File lib/password_strength/base.rb, line 183
def test
  @score = 0

  if contain_invalid_matches?
    invalid!
  elsif common_word?
    invalid!
  elsif contain_invalid_repetion?
    invalid!
  else
    @score += score_for(:password_size)
    @score += score_for(:numbers)
    @score += score_for(:symbols)
    @score += score_for(:uppercase_lowercase)
    @score += score_for(:numbers_chars)
    @score += score_for(:numbers_symbols)
    @score += score_for(:symbols_chars)
    @score += score_for(:only_chars)
    @score += score_for(:only_numbers)
    @score += score_for(:username)
    @score += score_for(:sequences)
    @score += score_for(:repetitions)

    @score = 0 if score < 0
    @score = 100 if score > 100

    weak!   if score < 35
    good!   if score >= 35 && score < 70
    strong! if score >= 70
  end

  score
end
valid?(level = GOOD) click to toggle source

Check if the password has the specified score. Level can be :weak, :good or :strong.

# File lib/password_strength/base.rb, line 73
def valid?(level = GOOD)
  case level
  when STRONG then
    strong?
  when GOOD then
    good? || strong?
  else
    !invalid?
  end
end
weak!() click to toggle source

Mark password as weak.

# File lib/password_strength/base.rb, line 100
def weak!
  @status = WEAK
end
weak?() click to toggle source

Check if the password has been detected as weak.

# File lib/password_strength/base.rb, line 95
def weak?
  status == WEAK
end