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", ... }, ...]

Masking for Display

Philiprehberger::Password.mask("hunter2")                 # => "*******"
Philiprehberger::Password.mask("hunter2", visible: 2)     # => "*****r2"
Philiprehberger::Password.mask("hunter2", mask: "")      # => "•••••••"

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
.mask(password, visible: 0, mask: '*') Redact password for display; reveals trailing visible characters

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