keepass-password-generator 0.1.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.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ .yardoc
4
+ Gemfile.lock
5
+ doc
6
+ pkg
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format documentation
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --markup markdown
2
+ lib/**/*.rb
3
+ README.md MIT-LICENSE.txt
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ ## Version 0.1.0 / 2011-03-22
2
+
3
+ * updated license
4
+ * bumped version to 0.1.0
5
+
6
+ ## Version 0.0.1 / 2011-02-19
7
+
8
+ * initial release
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011 John Nishinaga and Pat Deegan, PhD & Associates, LLC.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # keepass-password-generator
2
+
3
+ Generate passwords using KeePass password generator patterns.
4
+
5
+ ## RubyGems installation
6
+
7
+ gem install keepass-password-generator
8
+
9
+ ## Bundler installation
10
+
11
+ In your `Gemfile`:
12
+
13
+ gem 'keepass-password-generator'
14
+
15
+ Install bundled gems:
16
+
17
+ bundle
18
+
19
+ ## Usage
20
+
21
+ require 'keepass/password'
22
+
23
+ KeePass::Password.generate('A{6}s')
24
+ #=> "Un2hd#t"
25
+
26
+ See <http://keepass.info/help/base/pwgenerator.html> for information about KeePass patterns.
27
+
28
+ ## Examples
29
+
30
+ A 40-bit WEP key:
31
+
32
+ KeePass::Password.generate('h{10}')
33
+ #=> "ae6929dc0e"
34
+
35
+ A random MAC address:
36
+
37
+ KeePass::Password.generate('HH\-HH\-HH\-HH\-HH\-HH', :permute => false)
38
+ #=> "0D-4D-32-64-EB-7D"
39
+
40
+ A password with 10 alphanumeric characters, where at least 2 are upper case and at least are 2 lower case characters:
41
+
42
+ KeePass::Password.generate('uullA{6}')
43
+ #=> "us2j1nTIQT"
44
+
45
+ A password with 20 alphanumeric and symbol characters, without any lookalike characters (e.g., I and |):
46
+
47
+ KeePass::Password.generate('[As]{20}', :remove_lookalikes => true)
48
+ #=> "-2~[+Rze{hZezk(\\nZ-W"
49
+
50
+ Invalid patterns raise an exception:
51
+
52
+ KeePass::Password.generate('[\I\|]{3}', :remove_lookalikes => true)
53
+ #=> KeePass::Password::InvalidPatternError: empty character set for token 1 for "[\\I\\|]{3}"
54
+
55
+ ## Related gems
56
+
57
+ * <https://github.com/dmke/simple-password-gen>
58
+ * <http://rubygems.org/gems/ruby-password>
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'yard'
7
+ YARD::Rake::YardocTask.new
8
+
9
+ require 'rspec/core/rake_task'
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ task :default => :spec
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "keepass/password/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "keepass-password-generator"
7
+ s.version = KeePass::Password::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["John Nishinaga"]
10
+ s.email = ["jingoro@casa-z.org"]
11
+ s.homepage = "https://github.com/patdeegan/keepass-password-generator"
12
+ s.summary = "keepass-password-generator-#{KeePass::Password::VERSION}"
13
+ s.description = "Generate passwords using KeePass password generator patterns"
14
+
15
+ s.rubyforge_project = "keepass-password-generator"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency 'activesupport', '>= 2.2.0'
23
+
24
+ s.add_development_dependency 'yard'
25
+ s.add_development_dependency 'bluecloth'
26
+ s.add_development_dependency 'rspec'
27
+
28
+ end
@@ -0,0 +1 @@
1
+ require 'keepass/password'
@@ -0,0 +1,58 @@
1
+ require 'keepass/password/char_set'
2
+ require 'keepass/password/generator'
3
+ require 'keepass/password/version'
4
+
5
+ module KeePass
6
+
7
+ module Password
8
+
9
+ # Returns a generated password.
10
+ #
11
+ # @param [String] pattern the pattern
12
+ # @param [Hash] options the options
13
+ # @option options [Boolean] :permute (true) whether or not to randomly permute generated passwords
14
+ # @option options [Boolean] :remove_lookalikes (false) whether or not to remove lookalike characters
15
+ # @option options [Hash] :charset_mapping (CharSet::DEFAULT_MAPPING) the KeePass character set ID mapping
16
+ # @return [String] the new password
17
+ # @raise [InvalidPatternError] if `pattern` is invalid
18
+ def self.generate(pattern, options = {})
19
+ Generator.new(pattern, options).generate
20
+ end
21
+
22
+ # Returns whether or not the pattern is valid.
23
+ #
24
+ # @param [String] pattern the pattern
25
+ # @param [Hash] options the options
26
+ # @option options [Boolean] :permute (true) whether or not to randomly permute generated passwords
27
+ # @option options [Boolean] :remove_lookalikes (false) whether or not to remove lookalike characters
28
+ # @option options [Hash] :charset_mapping (CharSet::DEFAULT_MAPPING) the KeePass character set ID mapping
29
+ # @return [Boolean] whether or not the pattern is valid
30
+ def self.validate_pattern(pattern, options = {})
31
+ begin
32
+ generate(pattern, options)
33
+ true
34
+ rescue InvalidPatternError
35
+ false
36
+ end
37
+ end
38
+
39
+ # Returns an entropy estimate of a password.
40
+ #
41
+ # @param [String] test the password to test
42
+ # @see http://en.wikipedia.org/wiki/Password_strength
43
+ def self.estimate_entropy(test)
44
+ chars = 0
45
+ chars += 26 if test =~ LOWERCASE_TEST_RE
46
+ chars += 26 if test =~ UPPERCASE_TEST_RE
47
+ chars += 10 if test =~ DIGITS_TEST_RE
48
+ chars += CharSet::PRINTABLE_ASCII_SPECIAL.size if test =~ SPECIAL_TEST_RE
49
+ if chars == 0
50
+ 0
51
+ else
52
+ (test.size * Math.log(chars) / Math.log(2)).to_i
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,91 @@
1
+ require 'set'
2
+
3
+ module KeePass
4
+
5
+ module Password
6
+
7
+ class InvalidCharSetIDError < RuntimeError; end
8
+
9
+ # Character sets for the KeePass password generator.
10
+ #
11
+ # @see http://keepass.info/help/base/pwgenerator.html#pattern
12
+ class CharSet < Set
13
+
14
+ UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
15
+ LOWERCASE = "abcdefghijklmnopqrstuvwxyz"
16
+ DIGITS = "0123456789"
17
+ UPPER_CONSONANTS = "BCDFGHJKLMNPQRSTVWXYZ"
18
+ LOWER_CONSONANTS = "bcdfghjklmnpqrstvwxyz"
19
+ UPPER_VOWELS = "AEIOU"
20
+ LOWER_VOWELS = "aeiou"
21
+ PUNCTUATION = ",.;:"
22
+ BRACKETS = "[]{}()<>"
23
+ PRINTABLE_ASCII_SPECIAL = "!\"#\$%&'()*+,-./:;<=>?[\\]^_{|}~"
24
+ UPPER_HEX = "0123456789ABCDEF"
25
+ LOWER_HEX = "0123456789abcdef"
26
+ HIGH_ANSI = (0x7f..0xfe).map { |i| i.chr }.join
27
+
28
+ DEFAULT_MAPPING = {
29
+ 'a' => [LOWERCASE, DIGITS],
30
+ 'A' => [LOWERCASE, UPPERCASE, DIGITS],
31
+ 'U' => [UPPERCASE, DIGITS],
32
+ 'c' => [LOWER_CONSONANTS],
33
+ 'C' => [LOWER_CONSONANTS, UPPER_CONSONANTS],
34
+ 'z' => [UPPER_CONSONANTS],
35
+ 'd' => [DIGITS],
36
+ 'h' => [LOWER_HEX],
37
+ 'H' => [UPPER_HEX],
38
+ 'l' => [LOWERCASE],
39
+ 'L' => [LOWERCASE, UPPERCASE],
40
+ 'u' => [UPPERCASE],
41
+ 'p' => [PUNCTUATION],
42
+ 'b' => [BRACKETS],
43
+ 's' => [PRINTABLE_ASCII_SPECIAL],
44
+ 'S' => [UPPERCASE, LOWERCASE, DIGITS, PRINTABLE_ASCII_SPECIAL],
45
+ 'v' => [LOWER_VOWELS],
46
+ 'V' => [LOWER_VOWELS, UPPER_VOWELS],
47
+ 'Z' => [UPPER_VOWELS],
48
+ 'x' => [HIGH_ANSI],
49
+ }
50
+
51
+ ASCII_MAPPING = DEFAULT_MAPPING.reject { |k, v| k == 'x' }
52
+
53
+ # @return [Hash] the KeePass character set ID mapping
54
+ attr_accessor :mapping
55
+
56
+ # Instantiates a new CharSet object.
57
+ #
58
+ # @see Set#new
59
+ def initialize(*args)
60
+ @mapping = DEFAULT_MAPPING
61
+ super
62
+ end
63
+
64
+ # Adds several characters according to the KeePass character class.
65
+ #
66
+ # @see http://keepass.info/help/base/pwgenerator.html#pattern
67
+ # @param [String] char_set_id the KeePass character set ID
68
+ # @raise [InvalidCharSetIDError] if mapping does not contain `char_set_id`
69
+ # @return [CharSet] self
70
+ def add_from_char_set_id(char_set_id)
71
+ if strings = mapping[char_set_id]
72
+ add_from_strings *strings
73
+ else
74
+ raise InvalidCharSetIDError, "no such char set ID #{char_set_id.inspect}"
75
+ end
76
+ end
77
+
78
+ # Adds each character from one or more strings.
79
+ #
80
+ # @param [Array] *strings one or more strings to add
81
+ # @return [CharSet] self
82
+ def add_from_strings(*strings)
83
+ strings.each { |s| merge Set.new(s.split('')) }
84
+ self
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,111 @@
1
+ require 'keepass/password/char_set'
2
+ require 'keepass/random'
3
+
4
+ module KeePass
5
+
6
+ module Password
7
+
8
+ class InvalidPatternError < RuntimeError; end
9
+
10
+ # Generate passwords using KeePass password generator patterns.
11
+ #
12
+ # @see http://keepass.info/help/base/pwgenerator.html
13
+ class Generator
14
+
15
+ # Available character sets
16
+ CHARSET_IDS = CharSet::DEFAULT_MAPPING.keys.join
17
+
18
+ # ASCII printables regular expression
19
+ LITERALS_RE = /[\x20-\x7e]/
20
+ CHAR_TOKEN_RE = Regexp.new("([#{CHARSET_IDS}])|\\\\(#{LITERALS_RE.source})")
21
+ GROUP_TOKEN_RE = Regexp.new("(#{CHAR_TOKEN_RE.source}|" +
22
+ "\\[((#{CHAR_TOKEN_RE.source})*?)\\])" +
23
+ "(\\{(\\d+)\\})?")
24
+ VALIDATOR_RE = Regexp.new("\\A(#{GROUP_TOKEN_RE.source})+\\Z")
25
+
26
+ LOOKALIKE = "O0l1I|"
27
+ LOOKALIKE_CHARSET = CharSet.new.add_from_strings LOOKALIKE
28
+
29
+ # @return [String] the pattern
30
+ attr_reader :pattern
31
+
32
+ # @return [Array<CharSet>] the character sets from the pattern
33
+ attr_reader :char_sets
34
+
35
+ # @return [Boolean] whether or not to permute the password
36
+ attr_accessor :permute
37
+
38
+ # Instantiates a new PasswordGenerator object.
39
+ #
40
+ # @param [String] pattern the pattern
41
+ # @param [Hash] options the options
42
+ # @option options [Boolean] :permute (true) whether or not to randomly permute generated passwords
43
+ # @option options [Boolean] :remove_lookalikes (false) whether or not to remove lookalike characters
44
+ # @option options [Hash] :charset_mapping (CharSet::DEFAULT_MAPPING) the KeePass character set ID mapping
45
+ # @return [PasswordGenerator] self
46
+ # @raise [InvalidPatternError] if `pattern` is invalid
47
+ def initialize(pattern, options = {})
48
+ @permute = options.has_key?(:permute) ? options[:permute] : true
49
+ @pattern = pattern
50
+ @char_sets = pattern_to_char_sets(pattern, options)
51
+ end
52
+
53
+ # Returns a new password.
54
+ #
55
+ # @return [String] a new password
56
+ def generate
57
+ result = char_sets.map { |c| Random.sample_array(c.to_a) }
58
+ result = Random.shuffle_array(result) if permute
59
+ result.join
60
+ end
61
+
62
+ private
63
+
64
+ def pattern_to_char_sets(pattern, options) #:nodoc:
65
+ remove_lookalikes = options[:remove_lookalikes] || false
66
+ mapping = options[:charset_mapping] || CharSet::DEFAULT_MAPPING
67
+ char_sets = []
68
+ i = 1
69
+ pattern.scan(GROUP_TOKEN_RE) do |x1, char, bs_char, char_group, x5, x6, x7, x8, repeat|
70
+ char_set = CharSet.new
71
+ char_set.mapping = mapping
72
+ begin
73
+ if char
74
+ char_set.add_from_char_set_id(char)
75
+ elsif bs_char
76
+ char_set.add(bs_char)
77
+ else
78
+ char_group.scan(CHAR_TOKEN_RE) do |c, e|
79
+ if c
80
+ char_set.add_from_char_set_id(c)
81
+ else
82
+ char_set.add(e)
83
+ end
84
+ end
85
+ end
86
+ rescue InvalidCharSetIDError => e
87
+ raise InvalidPatternError, e.message
88
+ end
89
+ char_set -= LOOKALIKE_CHARSET if remove_lookalikes
90
+ if char_set.empty?
91
+ raise InvalidPatternError, "empty character set for token #{i} for #{pattern.inspect}"
92
+ end
93
+ (repeat ? repeat.to_i : 1).times { char_sets << char_set }
94
+ i += 1
95
+ end
96
+
97
+ if char_sets.any?
98
+ char_sets
99
+ else
100
+ raise InvalidPatternError, "no char sets from #{pattern.inspect}"
101
+ end
102
+
103
+ end
104
+
105
+ # private
106
+
107
+ end
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,5 @@
1
+ module KeePass
2
+ module Password
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,38 @@
1
+ require 'active_support/secure_random'
2
+
3
+ module KeePass
4
+
5
+ module Random
6
+
7
+ # If `n` is a positive integer, then returns a random
8
+ # integer `r` such that 0 <= `r` < `n`.
9
+ #
10
+ # If `n` is 0 or unspecified, then returns a random
11
+ # float `r` such that 0 <= `r` < 1.
12
+ #
13
+ # @param [Integer] n the upper bound
14
+ # @return [Integer|Float] the random number
15
+ # @see ActiveSupport::SecureRandom#random_number
16
+ def self.random_number(n = 0)
17
+ ActiveSupport::SecureRandom.random_number(n)
18
+ end
19
+
20
+ # Returns a randomly sampled item from the array.
21
+ #
22
+ # @param [Array] array the array to sample from
23
+ # @return [Object] random item or nil if no items exist
24
+ def self.sample_array(array)
25
+ array[random_number(array.size)]
26
+ end
27
+
28
+ # Returns the array shuffled randomly.
29
+ #
30
+ # @param [Array] array the array to shuffle
31
+ # @return [Array] the shuffled array
32
+ def self.shuffle_array(array)
33
+ array.sort_by { random_number }
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe KeePass::Password::CharSet do
4
+
5
+ describe "#add_from_strings" do
6
+
7
+ it "should add from multiple arguments" do
8
+ subject.add_from_strings('abc', 'cde', 'QQ')
9
+ subject.should == Set.new(%w(a b c d e Q))
10
+ end
11
+
12
+ end
13
+
14
+ describe "#add_from_char_set_id" do
15
+
16
+ it "should add the digits" do
17
+ subject.add_from_char_set_id('d')
18
+ subject.should == Set.new('0'..'9')
19
+ end
20
+
21
+ it "should support chaining" do
22
+ subject.add_from_char_set_id('l').add_from_char_set_id('u')
23
+ subject.should == (Set.new('a'..'z') + Set.new('A'..'Z'))
24
+ end
25
+
26
+ it "should allow x with default mapping" do
27
+ subject.add_from_char_set_id('x')
28
+ subject.should include(0x7f.chr)
29
+ end
30
+
31
+ it "should raise an error with ASCII mapping" do
32
+ subject.mapping = KeePass::Password::CharSet::ASCII_MAPPING
33
+ expect { subject.add_from_char_set_id('x') }.to raise_error(KeePass::Password::InvalidCharSetIDError)
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+
3
+ describe KeePass::Password::Generator do
4
+
5
+ def char_set(*ids)
6
+ char_set = KeePass::Password::CharSet.new
7
+ ids.each { |id| char_set.add_from_char_set_id(id) }
8
+ char_set
9
+ end
10
+
11
+ subject { described_class.new(pattern, options) }
12
+ let(:options) { { } }
13
+ let(:random_class) { KeePass::Random }
14
+
15
+ describe "pattern 'h{10}' (40-bit WEP key)" do
16
+
17
+ let(:pattern) { 'h{10}' }
18
+
19
+ its(:pattern) { should == 'h{10}' }
20
+ its(:permute) { should be_true }
21
+ its(:char_sets) { should have(10).items }
22
+
23
+ it "should generate 10 hex digits " do
24
+ random_class.should_receive(:sample_array) do |array|
25
+ array.sort.should == char_set('h').to_a.sort
26
+ '0'
27
+ end.exactly(10).times
28
+ random_class.should_receive(:shuffle_array) do |array|
29
+ array.sort
30
+ end.once
31
+ subject.generate.should == '0000000000'
32
+ end
33
+
34
+ end
35
+
36
+ describe "pattern 'HH\-HH\-HH\-HH\-HH\-HH', :permute => false" do
37
+
38
+ let(:pattern) { 'HH\-HH\-HH\-HH\-HH\-HH' }
39
+ let(:options) { { :permute => false } }
40
+
41
+ its(:pattern) { should == 'HH\-HH\-HH\-HH\-HH\-HH' }
42
+ its(:permute) { should be_false }
43
+ its(:char_sets) { should have(17).items }
44
+
45
+ it "should generate a MAC address" do
46
+ random_class.should_receive(:sample_array) do |array|
47
+ if array == ['-']
48
+ '-'
49
+ else
50
+ array.sort.should == char_set('H').to_a.sort
51
+ '0'
52
+ end
53
+ end.exactly(17).times
54
+ random_class.should_not_receive(:shuffle_array)
55
+ subject.generate.should == '00-00-00-00-00-00'
56
+ end
57
+
58
+ end
59
+
60
+ describe "pattern 'uullA{6}'" do
61
+
62
+ let(:pattern) { 'uullA{6}' }
63
+
64
+ its(:pattern) { should == 'uullA{6}' }
65
+ its(:permute) { should be_true }
66
+ its(:char_sets) { should have(10).items }
67
+
68
+ it "should generate a 10-character alphanumeric password" do
69
+ random_class.should_receive(:sample_array) do |array|
70
+ array.sort.first
71
+ end.exactly(10).times
72
+ random_class.should_receive(:shuffle_array) do |array|
73
+ array.sort
74
+ end.once
75
+ subject.generate.should == '000000AAaa'
76
+ end
77
+
78
+ end
79
+
80
+ describe "pattern '[As]{20}', :remove_lookalikes => true" do
81
+
82
+ let(:pattern) { '[As]{20}' }
83
+ let(:options) { { :remove_lookalikes => true } }
84
+
85
+ its(:pattern) { should == '[As]{20}' }
86
+ its(:permute) { should be_true }
87
+ its(:char_sets) { should have(20).items }
88
+
89
+ it "should generate a 20-character password" do
90
+ test_set = (char_set('A', 's') - Set.new(%w(O 0 l 1 I |))).to_a.sort
91
+ i = 0
92
+ random_class.should_receive(:sample_array) do |array|
93
+ array.sort.should == test_set
94
+ result = array.sort[i]
95
+ i += 1
96
+ result
97
+ end.exactly(20).times
98
+ random_class.should_receive(:shuffle_array) do |array|
99
+ array.sort
100
+ end.once
101
+ subject.generate.should == '!"#$%&\'()*+,-./23456'
102
+ end
103
+
104
+ end
105
+
106
+ describe "pattern '[\\I\\|]{3}', :remove_lookalikes => true" do
107
+
108
+ let(:pattern) { '[\I\|]{3}' }
109
+ let(:options) { { :remove_lookalikes => true } }
110
+
111
+ it "should raise an error" do
112
+ expect { subject }.to raise_error(KeePass::Password::InvalidPatternError)
113
+ end
114
+
115
+ end
116
+
117
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe KeePass::Random do
4
+
5
+ describe "#random_number" do
6
+
7
+ it "should use ActiveSupport::SecureRandom" do
8
+ ActiveSupport::SecureRandom.should_receive(:random_number).once.with(12)
9
+ described_class.random_number(12)
10
+ end
11
+
12
+ it "should accept default argument" do
13
+ ActiveSupport::SecureRandom.should_receive(:random_number).with(0)
14
+ described_class.random_number
15
+ end
16
+
17
+ end
18
+
19
+ describe "#sample_array" do
20
+
21
+ it "should call random_number with the array size" do
22
+ described_class.should_receive(:random_number).with(6).and_return(3)
23
+ described_class.sample_array(%w(a b c d e f)).should == 'd'
24
+ end
25
+
26
+ it "should return expected values for deterministic random number" do
27
+ described_class.stub(:random_number) { |arg| 0 }
28
+ described_class.sample_array(%w(a b c)).should == 'a'
29
+ described_class.sample_array(%w(b a c)).should == 'b'
30
+ described_class.sample_array(%w(c b a)).should == 'c'
31
+ end
32
+
33
+ end
34
+
35
+ describe "#shuffle_array" do
36
+
37
+ it "should call random_number with no parameters" do
38
+ described_class.should_receive(:random_number).with().at_least(5).times.and_return(0.5)
39
+ described_class.shuffle_array(%w(a b c d e))
40
+ end
41
+
42
+ it "should return the same elements" do
43
+ described_class.stub(:random_number) { 0.5 }
44
+ described_class.shuffle_array(%w(a b c d e)).sort.should == %w(a b c d e)
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,32 @@
1
+ $:.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'rspec'
4
+ require 'keepass/password/generator'
5
+
6
+ # module DeterministicRandomness
7
+ #
8
+ # def deterministic_random_number(&block)
9
+ # ActiveSupport::SecureRandom.stub(:random_number) do |arg|
10
+ # if block
11
+ # block.call(arg)
12
+ # else
13
+ # 0
14
+ # end
15
+ # end
16
+ # end
17
+ #
18
+ # # def deterministic_shuffle
19
+ # # Array.any_instance.stub(:shuffle!)
20
+ # # end
21
+ #
22
+ # end
23
+ #
24
+ # RSpec.configure do |config|
25
+ # config.include DeterministicRandomness
26
+ # end
27
+
28
+ # RSpec::Matchers.define :have_char_set_length_of do |expected|
29
+ # match do |actual|
30
+ # actual.char_sets.size == expected
31
+ # end
32
+ # end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: keepass-password-generator
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - John Nishinaga
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-22 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ prerelease: false
23
+ type: :runtime
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 2
32
+ - 2
33
+ - 0
34
+ version: 2.2.0
35
+ name: activesupport
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ prerelease: false
39
+ type: :development
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ name: yard
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ prerelease: false
53
+ type: :development
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ name: bluecloth
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ prerelease: false
67
+ type: :development
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ name: rspec
78
+ version_requirements: *id004
79
+ description: Generate passwords using KeePass password generator patterns
80
+ email:
81
+ - jingoro@casa-z.org
82
+ executables: []
83
+
84
+ extensions: []
85
+
86
+ extra_rdoc_files: []
87
+
88
+ files:
89
+ - .gitignore
90
+ - .rspec
91
+ - .yardopts
92
+ - CHANGELOG.md
93
+ - Gemfile
94
+ - MIT-LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - keepass-password-generator.gemspec
98
+ - lib/keepass-password-generator.rb
99
+ - lib/keepass/password.rb
100
+ - lib/keepass/password/char_set.rb
101
+ - lib/keepass/password/generator.rb
102
+ - lib/keepass/password/version.rb
103
+ - lib/keepass/random.rb
104
+ - spec/char_set_spec.rb
105
+ - spec/generator_spec.rb
106
+ - spec/random_spec.rb
107
+ - spec/spec_helper.rb
108
+ has_rdoc: true
109
+ homepage: https://github.com/patdeegan/keepass-password-generator
110
+ licenses: []
111
+
112
+ post_install_message:
113
+ rdoc_options: []
114
+
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 3
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
135
+ requirements: []
136
+
137
+ rubyforge_project: keepass-password-generator
138
+ rubygems_version: 1.5.2
139
+ signing_key:
140
+ specification_version: 3
141
+ summary: keepass-password-generator-0.1.0
142
+ test_files:
143
+ - spec/char_set_spec.rb
144
+ - spec/generator_spec.rb
145
+ - spec/random_spec.rb
146
+ - spec/spec_helper.rb