Class: PassForge::Analyzer
- Inherits:
-
Object
- Object
- PassForge::Analyzer
- Defined in:
- lib/passforge/analyzer.rb
Overview
Password strength analyzer Evaluates password security and provides recommendations
Defined Under Namespace
Classes: Result
Class Method Summary collapse
-
.analyze(password) ⇒ Result
Analyze password strength.
-
.calculate_entropy(password) ⇒ Object
Calculate password entropy (bits of randomness).
-
.calculate_score(entropy, password) ⇒ Object
Calculate numeric score (0-100).
-
.common_password?(password) ⇒ Boolean
Check if password is common.
-
.determine_charset_size(password) ⇒ Object
Determine character set size.
-
.determine_strength(entropy, password) ⇒ Object
Determine strength level.
-
.estimate_crack_time(entropy) ⇒ Object
Estimate crack time based on entropy.
-
.format_time(seconds) ⇒ Object
Format time in human-readable format.
-
.generate_suggestions(password, entropy) ⇒ Object
Generate improvement suggestions.
-
.has_all_char_types?(password) ⇒ Boolean
Check if password has all character types.
Class Method Details
.analyze(password) ⇒ Result
Analyze password strength
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/passforge/analyzer.rb', line 42 def self.analyze(password) raise ArgumentError, "Password cannot be empty" if password.nil? || password.empty? entropy = calculate_entropy(password) crack_time = estimate_crack_time(entropy) strength = determine_strength(entropy, password) score = calculate_score(entropy, password) suggestions = generate_suggestions(password, entropy) Result.new( password: password, score: score, entropy: entropy, crack_time: crack_time, strength: strength, suggestions: suggestions ) end |
.calculate_entropy(password) ⇒ Object
Calculate password entropy (bits of randomness)
63 64 65 66 67 68 69 |
# File 'lib/passforge/analyzer.rb', line 63 def self.calculate_entropy(password) charset_size = determine_charset_size(password) length = password.length # Entropy = log2(charset_size^length) Math.log2(charset_size**length) end |
.calculate_score(entropy, password) ⇒ Object
Calculate numeric score (0-100)
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/passforge/analyzer.rb', line 127 def self.calculate_score(entropy, password) base_score = [entropy * 1.5, 100].min # Penalties base_score -= 10 if password.length < 8 base_score -= 15 if common_password?(password) base_score -= 5 if password =~ /^[a-z]+$/ # All lowercase base_score -= 5 if password =~ /^[A-Z]+$/ # All uppercase base_score -= 5 if password =~ /^[0-9]+$/ # All numbers # Bonuses base_score += 5 if password.length > 12 base_score += 5 if password.length > 16 base_score += 10 if has_all_char_types?(password) [[base_score, 0].max, 100].min.to_i end |
.common_password?(password) ⇒ Boolean
Check if password is common
156 157 158 159 160 161 162 163 164 |
# File 'lib/passforge/analyzer.rb', line 156 def self.common_password?(password) common_passwords = %w[ password 123456 12345678 qwerty abc123 monkey 1234567 letmein trustno1 dragon baseball iloveyou master sunshine ashley bailey passw0rd shadow 123123 654321 superman qazwsx michael football ] common_passwords.include?(password.downcase) end |
.determine_charset_size(password) ⇒ Object
Determine character set size
73 74 75 76 77 78 79 80 |
# File 'lib/passforge/analyzer.rb', line 73 def self.determine_charset_size(password) size = 0 size += 26 if password =~ /[a-z]/ size += 26 if password =~ /[A-Z]/ size += 10 if password =~ /[0-9]/ size += 32 if password =~ /[^a-zA-Z0-9]/ size end |
.determine_strength(entropy, password) ⇒ Object
Determine strength level
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/passforge/analyzer.rb', line 107 def self.determine_strength(entropy, password) # Check for common patterns return :very_weak if common_password?(password) case entropy when 0...28 :very_weak when 28...36 :weak when 36...60 :fair when 60...128 :strong else :very_strong end end |
.estimate_crack_time(entropy) ⇒ Object
Estimate crack time based on entropy
84 85 86 87 88 89 90 |
# File 'lib/passforge/analyzer.rb', line 84 def self.estimate_crack_time(entropy) guesses_per_second = 1_000_000_000 # 1 billion guesses/sec total_guesses = 2**entropy seconds = total_guesses / guesses_per_second / 2 # Average case format_time(seconds) end |
.format_time(seconds) ⇒ Object
Format time in human-readable format
94 95 96 97 98 99 100 101 102 103 |
# File 'lib/passforge/analyzer.rb', line 94 def self.format_time(seconds) return "instant" if seconds < 1 return "#{seconds.to_i} seconds" if seconds < 60 return "#{(seconds / 60).to_i} minutes" if seconds < 3600 return "#{(seconds / 3600).to_i} hours" if seconds < 86_400 return "#{(seconds / 86_400).to_i} days" if seconds < 31_536_000 return "#{(seconds / 31_536_000).to_i} years" if seconds < 31_536_000_000 "centuries" end |
.generate_suggestions(password, entropy) ⇒ Object
Generate improvement suggestions
168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/passforge/analyzer.rb', line 168 def self.generate_suggestions(password, entropy) suggestions = [] suggestions << "Use at least 12 characters" if password.length < 12 suggestions << "Add uppercase letters" unless password =~ /[A-Z]/ suggestions << "Add lowercase letters" unless password =~ /[a-z]/ suggestions << "Add numbers" unless password =~ /[0-9]/ suggestions << "Add symbols (!@#$%^&*)" unless password =~ /[^a-zA-Z0-9]/ suggestions << "Avoid common passwords" if common_password?(password) suggestions << "Consider using a passphrase" if entropy < 50 suggestions end |
.has_all_char_types?(password) ⇒ Boolean
Check if password has all character types
147 148 149 150 151 152 |
# File 'lib/passforge/analyzer.rb', line 147 def self.has_all_char_types?(password) password =~ /[a-z]/ && password =~ /[A-Z]/ && password =~ /[0-9]/ && password =~ /[^a-zA-Z0-9]/ end |