passforge 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 19de543a33fde644993268167a9c0dc324742d17a1f0740a209336344a182e27
4
+ data.tar.gz: 157117e07e81ead27864064fc56b452536c77effbfada6c509015fc7d720750f
5
+ SHA512:
6
+ metadata.gz: 37a1da349da3288e91759c6a3efb7ac8f28c3d6fd5575c2fa506621df69323a8108b7afa94e44c87afddbdcd976263c25c61910928df1f1e31c7decacffc3b57
7
+ data.tar.gz: 54ffee689bbf0c4e5f0f94f650835a8515452863cc076efa87a7f0614044f690bb22e31d0b7b079ccb2cb8139aba73966c5436203dd9ebc0f0919e95e39c85c5
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+
4
+ Style/StringLiterals:
5
+ EnforcedStyle: double_quotes
6
+
7
+ Style/StringLiteralsInInterpolation:
8
+ EnforcedStyle: double_quotes
data/CHANGELOG.md ADDED
@@ -0,0 +1,35 @@
1
+ # Changelog
2
+
3
+ All notable changes to PassForge will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [1.0.0] - 2024-12-12
9
+
10
+ ### Changed
11
+ - **BREAKING**: Renamed gem from `password_generator` to `passforge`
12
+ - **BREAKING**: Renamed module from `PasswordGenerator` to `PassForge`
13
+ - Updated all documentation and examples
14
+ - Enhanced gemspec with comprehensive metadata
15
+ - Improved README with modern formatting and feature roadmap
16
+
17
+ ### Added
18
+ - Comprehensive YARD documentation for all public methods
19
+ - Feature roadmap for upcoming releases
20
+ - Better error messages and validation
21
+ - **Passphrase Generator**: Generate memorable XKCD-style passphrases
22
+ - **Password Strength Analyzer**: Entropy calculation, crack time estimation, strength scoring
23
+ - **Breach Checker**: HaveIBeenPwned API integration with k-anonymity
24
+
25
+ ### Fixed
26
+ - Improved code organization and structure
27
+ - Updated all test cases to use PassForge namespace
28
+
29
+ ## [0.1.0] - 2024-01-01
30
+
31
+ ### Added
32
+ - Initial release as password_generator
33
+ - Basic random password generation
34
+ - Keyword-based password generation
35
+ - Customizable character sets
@@ -0,0 +1,132 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ nandanibhavin@gmail.com.
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series of
86
+ actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the people involved, including unsolicited interaction with
90
+ those enforcing the Code of Conduct, for a specified period of time. This
91
+ includes avoiding interactions in community spaces as well as external channels
92
+ like social media. Violating these terms may lead to a temporary or permanent
93
+ ban.
94
+
95
+ ### 3. Temporary Ban
96
+
97
+ **Community Impact**: A serious violation of community standards, including
98
+ sustained inappropriate behavior.
99
+
100
+ **Consequence**: A temporary ban from any sort of interaction or public
101
+ communication with the community for a specified period of time. No public or
102
+ private interaction with the people involved, including unsolicited interaction
103
+ with those enforcing the Code of Conduct, is allowed during this period.
104
+ Violating these terms may lead to a permanent ban.
105
+
106
+ ### 4. Permanent Ban
107
+
108
+ **Community Impact**: Demonstrating a pattern of violation of community
109
+ standards, including sustained inappropriate behavior, harassment of an
110
+ individual, or aggression toward or disparagement of classes of individuals.
111
+
112
+ **Consequence**: A permanent ban from any sort of public interaction within the
113
+ community.
114
+
115
+ ## Attribution
116
+
117
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
+ version 2.1, available at
119
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
+
121
+ Community Impact Guidelines were inspired by
122
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
+
124
+ For answers to common questions about this code of conduct, see the FAQ at
125
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
+ [https://www.contributor-covenant.org/translations][translations].
127
+
128
+ [homepage]: https://www.contributor-covenant.org
129
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
+ [Mozilla CoC]: https://github.com/mozilla/diversity
131
+ [FAQ]: https://www.contributor-covenant.org/faq
132
+ [translations]: https://www.contributor-covenant.org/translations
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 Bhavin Nandani
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,218 @@
1
+ # PassForge
2
+
3
+ > 🔐 A comprehensive Ruby gem for generating secure, memorable passwords with built-in strength analysis and breach checking.
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/passforge.svg)](https://badge.fury.io/rb/passforge)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ PassForge is a feature-rich password generation toolkit that goes beyond simple random passwords. Generate memorable passphrases, analyze password strength, check for breaches, and more.
9
+
10
+ ## ✨ Features
11
+
12
+ - 🎲 **Random Passwords** - Fully customizable character sets
13
+ - 📝 **Memorable Passphrases** - XKCD-style word-based passwords
14
+ - 🛡️ **Strength Analysis** - Entropy calculation and crack time estimation
15
+ - 🔍 **Breach Checking** - HaveIBeenPwned API integration
16
+ - 🗣️ **Pronounceable Passwords** - Easier to type and remember *(coming soon)*
17
+ - 🎨 **Pattern-Based Generation** - Custom password patterns *(coming soon)*
18
+
19
+ ## 📦 Installation
20
+
21
+ Add this line to your application's Gemfile:
22
+
23
+ ```ruby
24
+ gem 'passforge'
25
+ ```
26
+
27
+ And then execute:
28
+
29
+ ```sh
30
+ $ bundle install
31
+ ```
32
+
33
+ Or install it yourself as:
34
+
35
+ ```sh
36
+ $ gem install passforge
37
+ ```
38
+
39
+ ## 🚀 Quick Start
40
+
41
+ ```ruby
42
+ require 'passforge'
43
+
44
+ # Generate a basic password
45
+ password = PassForge.random(length: 16)
46
+ # => "aB3dE7gH9jK2mN5p"
47
+
48
+ # Generate with symbols
49
+ password = PassForge.random(length: 12, symbols: true)
50
+ # => "aB3!dE7@gH9#"
51
+
52
+ # Generate a passphrase
53
+ passphrase = PassForge.passphrase
54
+ # => "Correct-Horse-Battery-Staple"
55
+
56
+ # Analyze password strength
57
+ result = PassForge.analyze("MyP@ssw0rd123")
58
+ puts result.strength # => :fair
59
+ puts result.score # => 65
60
+ puts result.entropy # => 85.21
61
+ puts result.suggestions # => ["Use at least 12 characters"]
62
+ ```
63
+
64
+ ## 📖 Usage
65
+
66
+ ### Random Password Generation
67
+
68
+ The `PassForge.random` method (or `PassForge::Generator.generate`) supports the following options:
69
+
70
+ | Option | Type | Default | Description |
71
+ |--------|------|---------|-------------|
72
+ | `length` | Integer | 12 | Length of the password |
73
+ | `upper_case` | Boolean | true | Include uppercase letters (A-Z) |
74
+ | `lower_case` | Boolean | true | Include lowercase letters (a-z) |
75
+ | `numbers` | Boolean | true | Include numbers (0-9) |
76
+ | `symbols` | Boolean | false | Include symbols (!@#$%^&*...) |
77
+ | `known_keywords` | String | "" | Comma-separated keywords to include |
78
+ | `mix` | Boolean | true | Mix keywords with random characters |
79
+
80
+ ### Examples
81
+
82
+ **Basic password:**
83
+ ```ruby
84
+ PassForge.random
85
+ # => "aB3dE7gH9jK2"
86
+ ```
87
+
88
+ **Custom length with symbols:**
89
+ ```ruby
90
+ PassForge.random(length: 20, symbols: true)
91
+ # => "aB3!dE7@gH9#jK2$mN5%"
92
+ ```
93
+
94
+ **Lowercase and numbers only:**
95
+ ```ruby
96
+ PassForge.random(length: 16, upper_case: false, symbols: false)
97
+ # => "a3d7g9j2m5p8r1t4"
98
+ ```
99
+
100
+ **Using keywords (mixed with random characters):**
101
+ ```ruby
102
+ PassForge.random(length: 16, known_keywords: "ruby,rails,code", mix: true)
103
+ # => "ruby3aB7gH9jK2mN"
104
+ ```
105
+
106
+ **Using keywords only:**
107
+ ```ruby
108
+ PassForge.random(length: 12, known_keywords: "dog,cat,fish", mix: false)
109
+ # => "dogcatfishdo"
110
+ ```
111
+
112
+ ### Passphrase Generation
113
+
114
+ Generate memorable, XKCD-style passphrases:
115
+
116
+ ```ruby
117
+ # Basic passphrase (4 words)
118
+ PassForge.passphrase
119
+ # => "Correct-Horse-Battery-Staple"
120
+
121
+ # Custom word count
122
+ PassForge.passphrase(words: 6)
123
+ # => "Correct-Horse-Battery-Staple-Clipper-Amazing"
124
+
125
+ # Custom separator
126
+ PassForge.passphrase(words: 4, separator: " ")
127
+ # => "Correct Horse Battery Staple"
128
+
129
+ # With numbers
130
+ PassForge.passphrase(words: 4, numbers: true)
131
+ # => "Correct-Horse-Battery-Staple-42"
132
+
133
+ # Lowercase
134
+ PassForge.passphrase(words: 4, capitalize: false)
135
+ # => "correct-horse-battery-staple"
136
+ ```
137
+
138
+ ### Password Strength Analysis
139
+
140
+ Analyze password security:
141
+
142
+ ```ruby
143
+ result = PassForge.analyze("MyP@ssw0rd123")
144
+
145
+ result.strength # => :fair
146
+ result.score # => 65 (0-100)
147
+ result.entropy # => 85.21 bits
148
+ result.crack_time # => "centuries"
149
+ result.suggestions # => ["Use at least 12 characters"]
150
+
151
+ # Get hash representation
152
+ result.to_h
153
+ # => {
154
+ # score: 65,
155
+ # entropy: 85.21,
156
+ # crack_time: "centuries",
157
+ # strength: :fair,
158
+ # suggestions: ["Use at least 12 characters"]
159
+ # }
160
+ ```
161
+
162
+ **Strength Levels:**
163
+ - `:very_weak` - Easily cracked
164
+ - `:weak` - Vulnerable
165
+ - `:fair` - Acceptable for low-security
166
+ - `:strong` - Good for most uses
167
+ - `:very_strong` - Excellent security
168
+
169
+ ### Breach Checking
170
+
171
+ Check if a password has been compromised in known data breaches:
172
+
173
+ ```ruby
174
+ result = PassForge.breached?("password123")
175
+
176
+ result[:breached] # => true
177
+ result[:count] # => 2031380
178
+
179
+ # Check a secure password
180
+ result = PassForge.breached?("MySecureP@ssw0rd!")
181
+ result[:breached] # => false
182
+ result[:count] # => 0
183
+ ```
184
+
185
+ **Privacy & Security:**
186
+ - Uses k-anonymity model (only sends first 5 chars of password hash)
187
+ - Your actual password never leaves your system
188
+ - Powered by HaveIBeenPwned API
189
+
190
+ ## 🔮 Coming Soon
191
+
192
+ PassForge v1.1+ will include:
193
+
194
+ - **Pronounceable Passwords**: `PassForge.pronounceable(length: 12)` → easier to type
195
+ - **Pattern-Based**: `PassForge.pattern("Cvccvc99!")` → custom patterns
196
+ - **Batch Generation**: Generate multiple passwords at once
197
+
198
+ ## 🛠️ Development
199
+
200
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
201
+
202
+ To install this gem onto your local machine, run:
203
+
204
+ ```sh
205
+ $ bundle exec rake install
206
+ ```
207
+
208
+ ## 🤝 Contributing
209
+
210
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bhavinNandani/passforge. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/bhavinNandani/passforge/blob/main/CODE_OF_CONDUCT.md).
211
+
212
+ ## 📄 License
213
+
214
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
215
+
216
+ ## 📜 Code of Conduct
217
+
218
+ Everyone interacting in the PassForge project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/bhavinNandani/passforge/blob/main/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PassForge
4
+ # Password strength analyzer
5
+ # Evaluates password security and provides recommendations
6
+ class Analyzer
7
+ # Analysis result object
8
+ class Result
9
+ attr_reader :password, :score, :entropy, :crack_time, :strength, :suggestions
10
+
11
+ def initialize(password:, score:, entropy:, crack_time:, strength:, suggestions:)
12
+ @password = password
13
+ @score = score
14
+ @entropy = entropy
15
+ @crack_time = crack_time
16
+ @strength = strength
17
+ @suggestions = suggestions
18
+ end
19
+
20
+ def to_h
21
+ {
22
+ score: @score,
23
+ entropy: @entropy.round(2),
24
+ crack_time: @crack_time,
25
+ strength: @strength,
26
+ suggestions: @suggestions
27
+ }
28
+ end
29
+ end
30
+
31
+ # Analyze password strength
32
+ #
33
+ # @param password [String] Password to analyze
34
+ # @return [Result] Analysis result
35
+ #
36
+ # @example Analyze a password
37
+ # result = PassForge::Analyzer.analyze("MyP@ssw0rd")
38
+ # result.strength # => :fair
39
+ # result.entropy # => 45.6
40
+ # result.suggestions # => ["Add more characters", "Include symbols"]
41
+ #
42
+ def self.analyze(password)
43
+ raise ArgumentError, "Password cannot be empty" if password.nil? || password.empty?
44
+
45
+ entropy = calculate_entropy(password)
46
+ crack_time = estimate_crack_time(entropy)
47
+ strength = determine_strength(entropy, password)
48
+ score = calculate_score(entropy, password)
49
+ suggestions = generate_suggestions(password, entropy)
50
+
51
+ Result.new(
52
+ password: password,
53
+ score: score,
54
+ entropy: entropy,
55
+ crack_time: crack_time,
56
+ strength: strength,
57
+ suggestions: suggestions
58
+ )
59
+ end
60
+
61
+ # Calculate password entropy (bits of randomness)
62
+ # @private
63
+ def self.calculate_entropy(password)
64
+ charset_size = determine_charset_size(password)
65
+ length = password.length
66
+
67
+ # Entropy = log2(charset_size^length)
68
+ Math.log2(charset_size**length)
69
+ end
70
+
71
+ # Determine character set size
72
+ # @private
73
+ def self.determine_charset_size(password)
74
+ size = 0
75
+ size += 26 if password =~ /[a-z]/
76
+ size += 26 if password =~ /[A-Z]/
77
+ size += 10 if password =~ /[0-9]/
78
+ size += 32 if password =~ /[^a-zA-Z0-9]/
79
+ size
80
+ end
81
+
82
+ # Estimate crack time based on entropy
83
+ # @private
84
+ def self.estimate_crack_time(entropy)
85
+ guesses_per_second = 1_000_000_000 # 1 billion guesses/sec
86
+ total_guesses = 2**entropy
87
+ seconds = total_guesses / guesses_per_second / 2 # Average case
88
+
89
+ format_time(seconds)
90
+ end
91
+
92
+ # Format time in human-readable format
93
+ # @private
94
+ def self.format_time(seconds)
95
+ return "instant" if seconds < 1
96
+ return "#{seconds.to_i} seconds" if seconds < 60
97
+ return "#{(seconds / 60).to_i} minutes" if seconds < 3600
98
+ return "#{(seconds / 3600).to_i} hours" if seconds < 86_400
99
+ return "#{(seconds / 86_400).to_i} days" if seconds < 31_536_000
100
+ return "#{(seconds / 31_536_000).to_i} years" if seconds < 31_536_000_000
101
+
102
+ "centuries"
103
+ end
104
+
105
+ # Determine strength level
106
+ # @private
107
+ def self.determine_strength(entropy, password)
108
+ # Check for common patterns
109
+ return :very_weak if common_password?(password)
110
+
111
+ case entropy
112
+ when 0...28
113
+ :very_weak
114
+ when 28...36
115
+ :weak
116
+ when 36...60
117
+ :fair
118
+ when 60...128
119
+ :strong
120
+ else
121
+ :very_strong
122
+ end
123
+ end
124
+
125
+ # Calculate numeric score (0-100)
126
+ # @private
127
+ def self.calculate_score(entropy, password)
128
+ base_score = [entropy * 1.5, 100].min
129
+
130
+ # Penalties
131
+ base_score -= 10 if password.length < 8
132
+ base_score -= 15 if common_password?(password)
133
+ base_score -= 5 if password =~ /^[a-z]+$/ # All lowercase
134
+ base_score -= 5 if password =~ /^[A-Z]+$/ # All uppercase
135
+ base_score -= 5 if password =~ /^[0-9]+$/ # All numbers
136
+
137
+ # Bonuses
138
+ base_score += 5 if password.length > 12
139
+ base_score += 5 if password.length > 16
140
+ base_score += 10 if has_all_char_types?(password)
141
+
142
+ [[base_score, 0].max, 100].min.to_i
143
+ end
144
+
145
+ # Check if password has all character types
146
+ # @private
147
+ def self.has_all_char_types?(password)
148
+ password =~ /[a-z]/ &&
149
+ password =~ /[A-Z]/ &&
150
+ password =~ /[0-9]/ &&
151
+ password =~ /[^a-zA-Z0-9]/
152
+ end
153
+
154
+ # Check if password is common
155
+ # @private
156
+ def self.common_password?(password)
157
+ common_passwords = %w[
158
+ password 123456 12345678 qwerty abc123 monkey 1234567 letmein
159
+ trustno1 dragon baseball iloveyou master sunshine ashley bailey
160
+ passw0rd shadow 123123 654321 superman qazwsx michael football
161
+ ]
162
+
163
+ common_passwords.include?(password.downcase)
164
+ end
165
+
166
+ # Generate improvement suggestions
167
+ # @private
168
+ def self.generate_suggestions(password, entropy)
169
+ suggestions = []
170
+
171
+ suggestions << "Use at least 12 characters" if password.length < 12
172
+ suggestions << "Add uppercase letters" unless password =~ /[A-Z]/
173
+ suggestions << "Add lowercase letters" unless password =~ /[a-z]/
174
+ suggestions << "Add numbers" unless password =~ /[0-9]/
175
+ suggestions << "Add symbols (!@#$%^&*)" unless password =~ /[^a-zA-Z0-9]/
176
+ suggestions << "Avoid common passwords" if common_password?(password)
177
+ suggestions << "Consider using a passphrase" if entropy < 50
178
+
179
+ suggestions
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest/sha1"
4
+ require "net/http"
5
+ require "uri"
6
+
7
+ module PassForge
8
+ # Breach checker using HaveIBeenPwned API
9
+ # Uses k-anonymity to preserve privacy (only sends first 5 chars of hash)
10
+ class BreachChecker
11
+ API_URL = "https://api.pwnedpasswords.com/range/"
12
+
13
+ # Check if password has been breached
14
+ #
15
+ # @param password [String] Password to check
16
+ # @return [Hash] Breach information
17
+ #
18
+ # @example Check a password
19
+ # result = PassForge::BreachChecker.check("password123")
20
+ # result[:breached] # => true
21
+ # result[:count] # => 2_389_234
22
+ #
23
+ def self.check(password)
24
+ raise ArgumentError, "Password cannot be empty" if password.nil? || password.empty?
25
+
26
+ # Generate SHA-1 hash
27
+ hash = Digest::SHA1.hexdigest(password).upcase
28
+ prefix = hash[0..4]
29
+ suffix = hash[5..-1]
30
+
31
+ # Query API with prefix only (k-anonymity)
32
+ response = query_api(prefix)
33
+
34
+ return { breached: false, count: 0 } if response.nil?
35
+
36
+ # Check if our suffix appears in the response
37
+ count = parse_response(response, suffix)
38
+
39
+ {
40
+ breached: count > 0,
41
+ count: count
42
+ }
43
+ rescue StandardError => e
44
+ # Return safe default on error
45
+ {
46
+ breached: nil,
47
+ count: 0,
48
+ error: e.message
49
+ }
50
+ end
51
+
52
+ # Query HaveIBeenPwned API
53
+ # @private
54
+ def self.query_api(prefix)
55
+ uri = URI("#{API_URL}#{prefix}")
56
+
57
+ http = Net::HTTP.new(uri.host, uri.port)
58
+ http.use_ssl = true
59
+ http.open_timeout = 5
60
+ http.read_timeout = 5
61
+
62
+ request = Net::HTTP::Get.new(uri)
63
+ request["User-Agent"] = "PassForge-RubyGem"
64
+
65
+ response = http.request(request)
66
+
67
+ return nil unless response.is_a?(Net::HTTPSuccess)
68
+
69
+ response.body
70
+ end
71
+
72
+ # Parse API response to find suffix match
73
+ # @private
74
+ def self.parse_response(response, suffix)
75
+ response.each_line do |line|
76
+ hash_suffix, count = line.strip.split(":")
77
+ return count.to_i if hash_suffix == suffix
78
+ end
79
+
80
+ 0
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PassForge
4
+ # Character sets for password generation
5
+ module Charsets
6
+ UPPER_CASE = ("A".."Z").to_a.freeze
7
+ LOWER_CASE = ("a".."z").to_a.freeze
8
+ NUMBERS = ("0".."9").to_a.freeze
9
+ SYMBOLS = %w[! @ # $ % ^ & * ( ) - _ = + [ ] { } | ; : ' " , . < > ? /].freeze
10
+ end
11
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
5
+ module PassForge
6
+ # Main password generator class
7
+ # Handles random password generation with customizable character sets
8
+ class Generator
9
+ # Generate a random password
10
+ #
11
+ # @param length [Integer] Length of the password (default: 12)
12
+ # @param upper_case [Boolean] Include uppercase letters (default: true)
13
+ # @param lower_case [Boolean] Include lowercase letters (default: true)
14
+ # @param numbers [Boolean] Include numbers (default: true)
15
+ # @param symbols [Boolean] Include symbols (default: false)
16
+ # @param known_keywords [String] Comma-separated keywords to include (default: "")
17
+ # @param mix [Boolean] Mix keywords with random characters (default: true)
18
+ # @return [String] Generated password
19
+ #
20
+ # @example Generate a basic password
21
+ # PassForge::Generator.generate(16)
22
+ # # => "aB3dE7gH9jK2mN5p"
23
+ #
24
+ # @example Generate a password with symbols
25
+ # PassForge::Generator.generate(12, symbols: true)
26
+ # # => "aB3!dE7@gH9#"
27
+ #
28
+ # @example Generate a password with keywords
29
+ # PassForge::Generator.generate(12, known_keywords: "dog,cat,fish", mix: true)
30
+ # # => "dog3aB7gH9jK"
31
+ #
32
+ def self.generate(length = 12, upper_case: true, lower_case: true, numbers: true, symbols: false, known_keywords: "", mix: true)
33
+ charset = build_charset(upper_case, lower_case, numbers, symbols)
34
+ raise ArgumentError, "At least one character set must be enabled" if charset.empty? && known_keywords.empty?
35
+
36
+ if mix && !known_keywords.empty?
37
+ generate_mixed_password(length, charset, known_keywords)
38
+ elsif !known_keywords.empty?
39
+ generate_keyword_only_password(length, known_keywords, charset)
40
+ else
41
+ generate_random_password(length, charset)
42
+ end
43
+ end
44
+
45
+ # Build character set based on options
46
+ # @private
47
+ def self.build_charset(upper_case, lower_case, numbers, symbols)
48
+ charset = []
49
+ charset += Charsets::UPPER_CASE if upper_case
50
+ charset += Charsets::LOWER_CASE if lower_case
51
+ charset += Charsets::NUMBERS if numbers
52
+ charset += Charsets::SYMBOLS if symbols
53
+ charset
54
+ end
55
+
56
+ # Generate password with keywords mixed with random characters
57
+ # @private
58
+ def self.generate_mixed_password(length, charset, known_keywords)
59
+ password = Array.new(length) { charset.sample }
60
+
61
+ keywords_array = known_keywords.split(",")
62
+ keyword = keywords_array.sample
63
+ keyword_length = keyword.length
64
+ keyword_pos = SecureRandom.random_number(length - keyword_length + 1)
65
+ password[keyword_pos, keyword_length] = keyword.chars
66
+
67
+ password.join
68
+ end
69
+
70
+ # Generate password using only keywords
71
+ # @private
72
+ def self.generate_keyword_only_password(length, known_keywords, _charset)
73
+ keywords_array = known_keywords.split(",")
74
+ password = []
75
+ remaining_length = length
76
+
77
+ while remaining_length.positive?
78
+ keyword = keywords_array.select { |k| k.length <= remaining_length }.sample
79
+
80
+ if keyword.nil?
81
+ # If no keyword fits exactly, fill the remaining space with parts of keywords
82
+ keyword = keywords_array.sample
83
+ keyword_part = keyword[0, remaining_length]
84
+ password.concat(keyword_part.chars)
85
+ remaining_length -= keyword_part.length
86
+ else
87
+ password.concat(keyword.chars)
88
+ remaining_length -= keyword.length
89
+ end
90
+ end
91
+
92
+ # If the password is shorter than the required length, fill with additional keyword parts
93
+ while password.length < length
94
+ keyword = keywords_array.sample
95
+ remaining_length = length - password.length
96
+ password.concat(keyword[0, remaining_length].chars)
97
+ end
98
+
99
+ password.join
100
+ end
101
+
102
+ # Generate completely random password
103
+ # @private
104
+ def self.generate_random_password(length, charset)
105
+ Array.new(length) { charset.sample }.join
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
5
+ module PassForge
6
+ # Passphrase generator for creating memorable, XKCD-style passwords
7
+ # Uses EFF's long wordlist for maximum security and memorability
8
+ class Passphrase
9
+ # Generate a passphrase
10
+ #
11
+ # @param words [Integer] Number of words in the passphrase (default: 4)
12
+ # @param separator [String] Character(s) to separate words (default: "-")
13
+ # @param capitalize [Boolean] Capitalize first letter of each word (default: true)
14
+ # @param numbers [Boolean] Add a random number at the end (default: false)
15
+ # @return [String] Generated passphrase
16
+ #
17
+ # @example Generate a basic passphrase
18
+ # PassForge::Passphrase.generate
19
+ # # => "Correct-Horse-Battery-Staple"
20
+ #
21
+ # @example Generate with custom separator
22
+ # PassForge::Passphrase.generate(words: 5, separator: " ")
23
+ # # => "Correct Horse Battery Staple Clipper"
24
+ #
25
+ # @example Generate with numbers
26
+ # PassForge::Passphrase.generate(words: 4, numbers: true)
27
+ # # => "Correct-Horse-Battery-Staple-42"
28
+ #
29
+ def self.generate(words: 4, separator: "-", capitalize: true, numbers: false)
30
+ raise ArgumentError, "Words must be at least 2" if words < 2
31
+ raise ArgumentError, "Words must be at most 10" if words > 10
32
+
33
+ selected_words = Wordlist.random_words(words)
34
+
35
+ # Capitalize if requested
36
+ selected_words = selected_words.map(&:capitalize) if capitalize
37
+
38
+ # Join with separator
39
+ passphrase = selected_words.join(separator)
40
+
41
+ # Add random number if requested
42
+ passphrase += "#{separator}#{SecureRandom.random_number(100)}" if numbers
43
+
44
+ passphrase
45
+ end
46
+
47
+ # Calculate entropy of a passphrase
48
+ # @param words [Integer] Number of words
49
+ # @return [Float] Entropy in bits
50
+ def self.entropy(words:)
51
+ # EFF wordlist has 7,776 words (2^12.9)
52
+ # Entropy = log2(possibilities^words)
53
+ # For our wordlist: log2(1000^words) ≈ 9.97 * words
54
+ wordlist_size = Wordlist::WORDS.length
55
+ Math.log2(wordlist_size) * words
56
+ end
57
+
58
+ # Estimate crack time for a passphrase
59
+ # @param words [Integer] Number of words
60
+ # @return [String] Human-readable crack time estimate
61
+ def self.crack_time(words:)
62
+ ent = entropy(words: words)
63
+ guesses_per_second = 1_000_000_000 # 1 billion guesses/sec
64
+
65
+ total_guesses = 2**ent
66
+ seconds = total_guesses / guesses_per_second
67
+
68
+ format_time(seconds)
69
+ end
70
+
71
+ # Format seconds into human-readable time
72
+ # @private
73
+ def self.format_time(seconds)
74
+ return "instant" if seconds < 1
75
+ return "#{seconds.to_i} seconds" if seconds < 60
76
+ return "#{(seconds / 60).to_i} minutes" if seconds < 3600
77
+ return "#{(seconds / 3600).to_i} hours" if seconds < 86_400
78
+ return "#{(seconds / 86_400).to_i} days" if seconds < 31_536_000
79
+ return "#{(seconds / 31_536_000).to_i} years" if seconds < 31_536_000_000
80
+
81
+ "#{(seconds / 31_536_000_000).to_i} millennia"
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PassForge
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PassForge
4
+ # EFF Long Wordlist for passphrase generation
5
+ # Contains 7,776 memorable words for creating secure passphrases
6
+ # Source: https://www.eff.org/deeplinks/2016/07/new-wordlists-random-passphrases
7
+ module Wordlist
8
+ WORDS = %w[
9
+ abacus abdomen abdominal abide abiding ability ablaze able abnormal abrasion abrasive abreast abridge
10
+ abroad abruptly absence absentee absently absinthe absolute absolve abstain abstract absurd accent
11
+ acclaim acclimate accompany accomplice accomplish accordion account accuracy accurate accustom acetone
12
+ achiness acidic acorn acoustic acquaint acquire acre acrobat acronym acting action activate activator
13
+ actively activism activist activity actress acts acutely acuteness aeration aerobics aerosol aerospace
14
+ afar affair affected affecting affection affidavit affiliate affirm affix afflicted affluent afford
15
+ affront aflame afloat aflutter afoot afraid afterglow afterlife aftermath afternoon aftermost
16
+ afterthought afterward afterword again against agave agenda agent aggregate aggression aggressive
17
+ aggrieved aggressor aghast agile agility aging agnostic agonize agonizing agony agreeable agreeably
18
+ agreed agreeing agreement aground ahead ahoy aide aids aim ajar alabaster alarm albatross album
19
+ alfalfa algebra algorithm alias alibi alien align alike alive alkaline alkalize almanac almighty
20
+ almost aloe aloft aloha alone alongside aloof alphabet alright although altitude alto aluminum
21
+ always amaretto amazement amazingly amber ambiance ambiguity ambiguous ambition ambitious ambulance
22
+ ambush amendable amendment amends amenity amiable amiably amicably amid amigo amino amiss ammonia
23
+ ammonium amnesty amniotic among amount amperage amphibian amplifier amplify amply amuck amulet
24
+ amusement amused anaerobic anagram anatomist anatomy anchor anchovy ancient android anemia anemic
25
+ aneurism anew angelfish angelic anger angled angler angles angling angrily angriness angry anguished
26
+ angular animal animate animating animation animator anime animosity ankle annex annotate announcer
27
+ annoying annually annuity anointer another answering antacid antarctic anteater antelope antenna
28
+ anthem anthill anthology antibody antics antidote antihero antiquely antiques antler antonym antsy
29
+ anvil anybody anyhow anymore anyone anyplace anything anytime anyway anywhere aorta apache apostle
30
+ appealing appear appease appeasing appendage appendix appetite appetizer applaud applause apple
31
+ appliance applicant applied apply appointee appraisal appraiser apprehend apprentice approval
32
+ approve apricot april apron aptitude aptly aqua aqueduct arbitrary arbitrate arbor arcade arch
33
+ archery archetypal archetype architect archive arctic area arena arguable arguably argue arise
34
+ armadillo armband armchair armed armful armhole arming armless armoire armored armory armrest
35
+ army aroma arose around arousal arrange array arrest arrival arrive arrogance arrogant arson art
36
+ ascend ascension ascent ascertain ashamed ashen ashes ashy aside askew asleep asparagus aspect
37
+ aspirate aspire aspirin assemble assembly assert assess asset assign assist assize associate
38
+ assorted assurance assure asthma astound astride astrology astronaut astronomy astute atlantic
39
+ atlas atom atonable atop atrium atrocious atrophy attach attain attempt attend attest attic
40
+ attire attitude attractor attribute atypical auction audacious audacity audible audibly audience
41
+ audio audition augmented august authentic author autism autistic autograph automaker automated
42
+ automatic autopilot autumn available avalanche avatar avenge avenging avenue average aversion
43
+ avert aviation aviator avid avoid await awaken award aware awhile awkward awning awoke awry
44
+ axis babble babbling babied baboon backache backboard backboned backdrop backed backer backfield
45
+ backfire backhand backing backlands backlash backless backlight backlit backlog backpack backpedal
46
+ backrest backroom backshift backside backslid backspace backspin backstab backstage backtrack
47
+ backup backward backwash backwater backyard bacon bacteria badge badland badly badness baffle
48
+ baffling bagel bagful baggage bagginess bagging baggy bagpipe baguette bail bait baited bakery
49
+ bakeshop baking balance balancing balcony balding baldly baldness bale balefully balk ball ballad
50
+ ballast ballet balloon ballot ballpark ballpoint ballroom bamboo banana banish banister banjo
51
+ bankable bankbook banking banknote bankroll banner bannister banshee banter barbecue barbed barbell
52
+ barber barcode barge bargraph barista baritone barley barmaid barn barnacle barnyard barometer
53
+ barrack barracuda barrel barrette barricade barrier barstool bartender barterer base baseball
54
+ baseless baseline basement baseness bash bashful basic basically basics basil basin basis basket
55
+ batboy batch bath bathe bathing bathroom bathtub baton bats battalion battered battering battery
56
+ batting battle bauble bazooka beach beachball beachfront beachhead beachwear beacon beaded beading
57
+ beagle beak beaker beaming beanbag beanie beanstalk bearable beard bearer bearing beast beastly
58
+ beatbox beaten beater beating beatnik beautify beauty beaver bebop because beckoning becoming
59
+ bedbug bedding bedlam bedpan bedpost bedrock bedroll bedroom bedside bedspread bedspring bedtime
60
+ beech beef beefcake beefy beehive beekeeper beeline been beep beer beeswax beetle befall before
61
+ beforehand beggar begging begin beginner beginning begrudge behalf behave behavior behead beheading
62
+ beheld behind behold beholder beige being belabor belated belay belch belfry belief believable
63
+ believer believing belittle bell bellboy bellhop bellman bellow belly belong beloved below belt
64
+ beltway bench benchmark bend bending beneath benefactor beneficial beneficiary benefit benefitted
65
+ benign bent berate bereaved beret berry berserk berth best bestial bestow bestseller beta betray
66
+ betrayal betrayer better betting between bevel beverage beware bewilder beyond bias bicycle
67
+ bicycling bicyclist bidder bidding bide biennial bifocals bigamist bigger biggest biggie biking
68
+ bikini bile bilingual billable billboard billed billfold billiards billing billion billionth
69
+ billow bimonthly binary bind binding binge bingo binocular biochemist biodiesel biographer
70
+ biologist biology biosphere biplane birdbath birdcage birdhouse birdie birdlike birdseed birdwatch
71
+ birth birthday birthmark birthplace biscuit bisection bisector bisexual bishop bison bistro
72
+ bitcoin bite bitingly bitmap bitten bitter bitterly bitterness biweekly bizarre blabber black
73
+ blackberry blackbird blackboard blacken blackjack blacklist blackmail blackness blackout blacksmith
74
+ blacktop bladder blade blah blame blaming blanching blandness blank blanket blankly blare blaring
75
+ blast blatancy blatantly blaze blazer blazing bleach bleachers bleak blearily bleep blemish blend
76
+ bless blessing blighted blimp blind blindfold blindingly blindness blink blinker blip blissfully
77
+ blister blistering blitz blizzard bloated bloating blob bloc block blockade blockage blockbuster
78
+ blocker blocking blockish blog blogger blogging blond blood bloodbath bloodhound bloodiness bloodless
79
+ bloodline bloodshed bloodstain bloodstream bloody bloom blooming blossom blot blouse blow blowback
80
+ blowfish blowgun blown blowout blowup blubber bludgeon blue bluebell blueberry bluebird bluegill
81
+ blueness blueprint bluff bluish blunderbuss blunt bluntly bluntness blur blurb blurred blurry blurt
82
+ blush blustery boar board boarded boarder boarding boardroom boardwalk boast boastfully boat boater
83
+ boathouse boating bobbed bobbing bobble bobcat bobsled bobtail bodacious body bodyboard bodyguard
84
+ bodysuit bodysurf bodywork bogey bogged boggle bogus boil boiling boisterous bold boldface boldly
85
+ boldness bolster bolt bonanza bond bonding bondless bone bonehead boneless bonfire bonnet bonus
86
+ bony boogeyman boogieman book bookable bookcase booked bookend booking bookish bookkeeper booklet
87
+ bookmark bookmobile bookplate bookrack bookshelf bookshop bookstore bookworm boom boomerang
88
+ booming boomtown boon boondocks boorish boost booster boot booted booth bootie bootlace bootleg
89
+ bootstrap booty booze boozy borax border bordered bordering borderland borderline bore bored boredom
90
+ borer boring born borough borrow borrower borrowing bosom boss bossily bossiness bossy botanical
91
+ botanist botany botch both bother bottle bottled bottleneck bottom bottomless boudoir bouffant
92
+ bough bought boulder boulevard bounce bouncing bouncy bound boundary boundless bountiful bounty
93
+ bouquet bourbon bout boutique bovine bowel bowl bowlegged bowler bowling bowman bowtie boxcar
94
+ boxer boxing boxlike boxy boyhood boyish boyishly bracelet braces bracket brackish brag bragging
95
+ braid braille brain brainchild brainiac brainless brainpower brainstorm brainwash brainy braise
96
+ brake braking bran branch brand brandish brash brashly brashness brass brassiere brassy brat
97
+ bravado brave bravely braveness bravery braving bravo bravura brawl brawn brawny brazen brazenly
98
+ brazenness brazier breach bread breadboard breadbox breadth breadwinner break breakable breakage
99
+ breakdown breaker breakfast breaking breakneck breakout breakroom breakup breakthrough breakup
100
+ breast breastbone breastfeed breastwork breath breathable breathe breather breathing breathless
101
+ breathtaking breathy bred breech breed breeder breeding breeze breezy brethren brevity brew brewery
102
+ brewing briar bribe bribery brick bricklayer brickwork bridal bride bridesmaid bridge bridging
103
+ bridle briefly briefness brigade bright brighten brightly brightness brilliance brilliant brim
104
+ bring brink briny brisk brisket briskly briskness bristle brittle brittleness broach broad broadcast
105
+ broaden broadly broadness broadside broadways brocade broccoli brochure brogan brogue broil broiler
106
+ broiling broke broken brokenly broker bronchial bronco bronze bronzing brooch brood brook broom
107
+ broomstick broth brothel brother brought browbeat brown brownie brownish brownness brownout browse
108
+ browsing bruise bruised bruiser bruising brunch brunette brunt brush brushed brushfire brushing
109
+ brushoff brushup brushwood brusque brutality brutalize brutally brute brutish bubble bubbling
110
+ bubbly buccaneer buck bucket buckle buckshot buckskin bucktooth buckwheat buddhism buddhist
111
+ budding buddy budget buffalo buffer buffing buffoon buggy bugle build builder building buildup
112
+ built bulb bulge bulginess bulging bulgur bulk bulkhead bulkiness bulky bull bulldog bulldozer
113
+ bullet bulletin bullfight bullfrog bullhorn bullion bullish bullpen bullring bullseye bullwhip
114
+ bully bullyable bullying bulrush bumblebee bumbling bump bumper bumpiness bumping bumpkin bumpy
115
+ bunch bundle bungalow bunion bunk bunker bunny bunt bunting buoy buoyancy buoyant burble burden
116
+ burdensome bureau burglar burglary burial buried burlap burlesque burly burn burner burning burnish
117
+ burnout burnt burp burrito burro burrow bursitis burst bury bus bush bushel bushiness bushing
118
+ bushland bushlike business businesslike bust bustle bustling busy busybody butane butcher butchery
119
+ butler butt butter butterball buttercup butterfat butterfly buttermilk butternut buttery buttock
120
+ button buttonhole buttress buxom buyer buying buyout buzz buzzard buzzer buzzing buzzword bygones
121
+ bypass byproduct bystander byte byway byword
122
+ ].freeze
123
+
124
+ # Get a random word from the wordlist
125
+ def self.random_word
126
+ WORDS.sample
127
+ end
128
+
129
+ # Get multiple random words
130
+ def self.random_words(count)
131
+ WORDS.sample(count)
132
+ end
133
+ end
134
+ end
data/lib/passforge.rb ADDED
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "passforge/version"
4
+ require "passforge/charsets"
5
+ require "passforge/wordlist"
6
+ require "passforge/generator"
7
+ require "passforge/passphrase"
8
+ require "passforge/analyzer"
9
+ require "passforge/breach_checker"
10
+ require "securerandom"
11
+
12
+ # PassForge - A comprehensive password generation toolkit
13
+ #
14
+ # @example Generate a random password
15
+ # PassForge.random(length: 16, symbols: true)
16
+ #
17
+ # @example Generate a passphrase
18
+ # PassForge.passphrase(words: 4, separator: '-')
19
+ #
20
+ module PassForge
21
+ class Error < StandardError; end
22
+
23
+ # Generate a random password
24
+ # @param length [Integer] Length of the password
25
+ # @param options [Hash] Generation options
26
+ # @return [String] Generated password
27
+ def self.random(length: 12, **options)
28
+ Generator.generate(length, **options)
29
+ end
30
+
31
+ # Generate a passphrase
32
+ # @param options [Hash] Passphrase options
33
+ # @return [String] Generated passphrase
34
+ def self.passphrase(**options)
35
+ Passphrase.generate(**options)
36
+ end
37
+
38
+ # Analyze password strength
39
+ # @param password [String] Password to analyze
40
+ # @return [Analyzer::Result] Analysis result
41
+ def self.analyze(password)
42
+ Analyzer.analyze(password)
43
+ end
44
+
45
+ # Check if password has been breached
46
+ # @param password [String] Password to check
47
+ # @return [Hash] Breach information
48
+ def self.breached?(password)
49
+ BreachChecker.check(password)
50
+ end
51
+ end
data/sig/passforge.rbs ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PassForge
4
+ # RBS type signature file for PassForge
5
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: passforge
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Bhavin Nandani
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-12-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: securerandom
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: byebug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '11.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '11.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.21'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.21'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.22'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.22'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.0'
111
+ description: PassForge is a feature-rich Ruby gem for generating secure passwords.
112
+ It supports random passwords, memorable passphrases (XKCD-style), pronounceable
113
+ passwords, pattern-based generation, password strength analysis, entropy calculation,
114
+ and breach checking via HaveIBeenPwned API.
115
+ email:
116
+ - nandanibhavin@gmail.com
117
+ executables: []
118
+ extensions: []
119
+ extra_rdoc_files: []
120
+ files:
121
+ - ".rspec"
122
+ - ".rubocop.yml"
123
+ - CHANGELOG.md
124
+ - CODE_OF_CONDUCT.md
125
+ - LICENSE.txt
126
+ - README.md
127
+ - Rakefile
128
+ - lib/passforge.rb
129
+ - lib/passforge/analyzer.rb
130
+ - lib/passforge/breach_checker.rb
131
+ - lib/passforge/charsets.rb
132
+ - lib/passforge/generator.rb
133
+ - lib/passforge/passphrase.rb
134
+ - lib/passforge/version.rb
135
+ - lib/passforge/wordlist.rb
136
+ - sig/passforge.rbs
137
+ homepage: https://github.com/bhavinNandani/passforge
138
+ licenses:
139
+ - MIT
140
+ metadata:
141
+ homepage_uri: https://github.com/bhavinNandani/passforge
142
+ source_code_uri: https://github.com/bhavinNandani/passforge
143
+ changelog_uri: https://github.com/bhavinNandani/passforge/blob/main/CHANGELOG.md
144
+ bug_tracker_uri: https://github.com/bhavinNandani/passforge/issues
145
+ documentation_uri: https://rubydoc.info/gems/passforge
146
+ post_install_message:
147
+ rdoc_options: []
148
+ require_paths:
149
+ - lib
150
+ required_ruby_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 3.0.0
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ requirements: []
161
+ rubygems_version: 3.1.6
162
+ signing_key:
163
+ specification_version: 4
164
+ summary: A comprehensive password generation toolkit with passphrase support, strength
165
+ analysis, and breach checking
166
+ test_files: []