philiprehberger-password

Tests Gem Version Last updated

Password strength checking, policy validation, pattern detection, hashing, and secure generation

Requirements

  • Ruby >= 3.1
  • bcrypt gem (optional, for password hashing only)

Installation

Add to your Gemfile:

gem "philiprehberger-password"

Or install directly:

gem install philiprehberger-password

Usage

Strength Scoring

require "philiprehberger/password"

result = Philiprehberger::Password.strength("MyP@ssw0rd!")
result[:score]    # => 3
result[:label]    # => :strong
result[:entropy]  # => 72.08

Entropy Estimate

Estimated password entropy in bits — length * log2(pool_size) where the pool is inferred from the character classes present:

Philiprehberger::Password.entropy("aaaaaa")       # => 28.20
Philiprehberger::Password.entropy("MyP@ssw0rd!")  # => 72.08
Philiprehberger::Password.entropy("")             # => 0.0

Common Password Check

Philiprehberger::Password.common?("password")   # => true
Philiprehberger::Password.common?("xK9#mZ2!pQ") # => false

Policy Validation

policy = Philiprehberger::Password::Policy.new(
  min_length: 12,
  require_uppercase: true,
  require_digit: true,
  require_symbol: true,
  reject_common: true,
  custom_passwords: ["companyname", "internalpass"]
)

result = policy.validate("short")
result.valid?  # => false
result.errors  # => ["must be at least 12 characters", ...]
result.score   # => 0

Context-Aware Validation

policy = Philiprehberger::Password::Policy.new

result = policy.validate("johndoe2024!", context: {
  username: "johndoe",
  email: "johndoe@example.com",
  app_name: "myapp"
})
result.valid?  # => false
result.errors  # => ["must not contain your username", "must not contain your email username"]

Keyboard Pattern Detection

patterns = Philiprehberger::Password.keyboard_patterns("qwertyaaa123456")
# => [
#   { type: :keyboard_row, token: "qwerty", start: 0, length: 6, direction: :forward },
#   { type: :repeated, token: "aaa", start: 6, length: 3, repeated_char: "a" },
#   { type: :sequence, token: "123456", start: 9, length: 6, sequence_type: :numeric, direction: :ascending }
# ]

Password Hashing

# Requires bcrypt gem: gem install bcrypt
hash = Philiprehberger::Password.hash("my-secret-password", cost: 12)
# => "$2a$12$..."

Philiprehberger::Password.verify("my-secret-password", hash)
# => true

Philiprehberger::Password.verify("wrong-password", hash)
# => false

Password Generation

# Random password
Philiprehberger::Password.generate(length: 20)
# => "kX9#mZ2!pQ7@wR4bN5&j"

# Passphrase (200+ word list)
Philiprehberger::Password.generate(style: :passphrase, words: 4, separator: "-")
# => "correct-horse-battery-staple"

# PIN
Philiprehberger::Password.generate(style: :pin, length: 6)
# => "482917"

zxcvbn-Style Strength Estimation

result = Philiprehberger::Password.zxcvbn("p@ssw0rd123")
result[:score]              # => 1
result[:crack_time_display] # => "minutes"
result[:patterns]           # => [{ type: :leet, token: "p@ssw0rd", ... }, ...]

API

Philiprehberger::Password

Method Description
.common?(password) Returns true if password is in the common password dictionary
.strength(password) Returns hash with :score (0-4), :label, :entropy
.entropy(password) Estimated entropy in bits (Float)
.generate(**options) Generate a password (see options below)
.keyboard_patterns(password) Returns array of detected keyboard/sequence/repeat patterns
.hash(password, cost: 12) Hash password with bcrypt (requires bcrypt gem)
.verify(password, hash) Verify password against bcrypt hash (requires bcrypt gem)
.zxcvbn(password) Returns hash with :score (0-4), :patterns, :crack_time_display

Generate Options

Option Default Description
length 16 Password length
uppercase true Include uppercase letters
lowercase true Include lowercase letters
digits true Include digits
symbols true Include symbols
style nil :passphrase or :pin for alternative styles
words 4 Word count for passphrase style
separator "-" Separator for passphrase style

Philiprehberger::Password::Policy

Method Description
.new(**options) Create policy (min_length, max_length, require_uppercase, require_lowercase, require_digit, require_symbol, reject_common, custom_passwords)
#validate(password, context: {}) Returns Result with .valid?, .errors, .score. Context accepts :username, :email, :app_name

Strength Labels

Score Label Entropy
0 :terrible < 28 bits
1 :weak < 36 bits
2 :fair < 60 bits
3 :strong < 80 bits
4 :excellent >= 80 bits

zxcvbn Pattern Types

Type Description
:dictionary Common password or known word detected
:leet L33t-speak substitution of a known word
:spatial QWERTY keyboard adjacency pattern
:date Date pattern (yyyy, mm/dd/yyyy, etc.)
:sequence Alphabetic or numeric sequence
:repeated Repeated characters

Development

bundle install
bundle exec rspec
bundle exec rubocop

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT