altpass 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 +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +177 -0
- data/Rakefile +10 -0
- data/altpass.gemspec +24 -0
- data/bin/altpass.rb +71 -0
- data/lib/altpass/version.rb +4 -0
- data/lib/altpass.rb +92 -0
- data/test/test_altpass.rb +66 -0
- data/test/test_helper.rb +4 -0
- metadata +63 -0
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Alex Batko
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
Altpass
|
2
|
+
=======
|
3
|
+
|
4
|
+
A Ruby gem and command-line utility for *generating passwords* derived from *hand-alternating*, *visually unambiguous*, *alphanumeric characters*.
|
5
|
+
|
6
|
+
Example
|
7
|
+
-------
|
8
|
+
|
9
|
+
`nXH3ix9w`
|
10
|
+
|
11
|
+
General Characteristics
|
12
|
+
-----------------------
|
13
|
+
|
14
|
+
* alternates hands (currently only supports `QWERTY` [keyboard layout](http://en.wikipedia.org/wiki/Keyboard_layout))
|
15
|
+
* always starts with a lower-case character (left-hand first for odd-length passwords; right if even)
|
16
|
+
* always ends with a left-hand character (so that the right-hand can finalize the hand alternation by hitting `Enter`/`Return`)
|
17
|
+
* all characters are alphanumeric; there are no symbols (so the passwords highlight when double-clicked)
|
18
|
+
* all characters are visually unambigous (some fonts make it difficult/impossible to distinguish *zero* and *capital 'o'*, or *one* and *lowercase 'L'*, and *uppercase i*, etc. so such characters are purposely not used)
|
19
|
+
|
20
|
+
The "memorizable" pattern
|
21
|
+
-------------------------
|
22
|
+
|
23
|
+
* the "memorizable" pattern is: lower, UPPER, UPPER, *number*, lower, lower, *number*, lower
|
24
|
+
* this pattern repeats for longer passwords
|
25
|
+
|
26
|
+
At a glance, a password such as `nXH3ix9w` looks incredibly difficult to memorize, but practicing it 5-10 times usually does the trick, particularly after first taking note of the pattern.
|
27
|
+
|
28
|
+
Options
|
29
|
+
-------
|
30
|
+
|
31
|
+
* make passwords of any *length* (`:length => [0-9]+`)
|
32
|
+
* use the *memorizable* pattern or not (`:memorizable => true|false`)
|
33
|
+
* show the sample sets and number of *permutations* (`:permutations => [vvv]`) (more `v`'s increase verbosity)
|
34
|
+
|
35
|
+
Defaults
|
36
|
+
--------
|
37
|
+
|
38
|
+
* `:length => 8`
|
39
|
+
* `:memorizable => true`
|
40
|
+
|
41
|
+
Examples of Gem Usage
|
42
|
+
---------------------
|
43
|
+
|
44
|
+
Return a *default* password:
|
45
|
+
|
46
|
+
Altpass.generate
|
47
|
+
=> "uGL4ox7f"
|
48
|
+
|
49
|
+
Return an *odd-length* password, not using the memorizable pattern:
|
50
|
+
|
51
|
+
Altpass.generate(:length => 15, :memorizable => false)
|
52
|
+
=> "cH5L3jwyw9XPw8V"
|
53
|
+
|
54
|
+
Return an *even-length* password, not using the memorizable pattern:
|
55
|
+
|
56
|
+
Altpass.generate(:length => 16, :memorizable => false)
|
57
|
+
=> "uV7AhspqySkBUwhs"
|
58
|
+
|
59
|
+
Return the *number of permutations*:
|
60
|
+
|
61
|
+
Altpass.permutations(:length => 16, :memorizable => false)
|
62
|
+
=> 2869959681148181529600
|
63
|
+
|
64
|
+
Print the *sample sets* and *permutation calculation* of a default password, and return the *number of permutations*:
|
65
|
+
|
66
|
+
Altpass.permutations(:length => 8, :memorizable => true, :permutations => 'vvv')
|
67
|
+
sample sets:
|
68
|
+
["y", "u", "i", "o", "p", "h", "j", "k", "n", "m"]
|
69
|
+
["Q", "W", "E", "R", "T", "A", "S", "D", "F", "G", "Z", "X", "C", "V", "B"]
|
70
|
+
["Y", "U", "P", "H", "J", "K", "L", "N", "M"]
|
71
|
+
["2", "3", "4", "5"]
|
72
|
+
["y", "u", "i", "o", "p", "h", "j", "k", "n", "m"]
|
73
|
+
["q", "w", "e", "r", "t", "a", "s", "d", "f", "g", "z", "x", "c", "v"]
|
74
|
+
["7", "8", "9"]
|
75
|
+
["q", "w", "e", "r", "t", "a", "s", "d", "f", "g", "z", "x", "c", "v"]
|
76
|
+
10 * 15 * 9 * 4 * 10 * 14 * 3 * 14 permutations
|
77
|
+
=> 31752000
|
78
|
+
|
79
|
+
Installation
|
80
|
+
------------
|
81
|
+
|
82
|
+
Add this line to your application's Gemfile:
|
83
|
+
|
84
|
+
gem 'altpass'
|
85
|
+
|
86
|
+
And then execute:
|
87
|
+
|
88
|
+
$ bundle
|
89
|
+
|
90
|
+
**Or** install it yourself:
|
91
|
+
|
92
|
+
$ gem install altpass
|
93
|
+
|
94
|
+
The Command-Line Utility
|
95
|
+
========================
|
96
|
+
|
97
|
+
The command-line utility, `altpass.rb`, is built into the gem.
|
98
|
+
|
99
|
+
Example
|
100
|
+
--------
|
101
|
+
|
102
|
+
$ altpass.rb
|
103
|
+
nF7zHTNrjtYRmxod
|
104
|
+
|
105
|
+
Options
|
106
|
+
-------
|
107
|
+
|
108
|
+
Usage: altpass.rb [options]
|
109
|
+
-l, --length [INTEGER>0] Password length
|
110
|
+
-m, --memorizable [true|false] Use the memorizable pattern or not
|
111
|
+
-p, --permutations [vvv] Show permutation size; verbosity increases with v's
|
112
|
+
-s, --switches Show password switches
|
113
|
+
-h, --help Show this message
|
114
|
+
|
115
|
+
Configuration
|
116
|
+
-------------
|
117
|
+
|
118
|
+
### Program defaults
|
119
|
+
|
120
|
+
The program itself comes with the following defaults:
|
121
|
+
|
122
|
+
options[:length] = 8
|
123
|
+
options[:memorizable] = true
|
124
|
+
options[:permutations] = false
|
125
|
+
options[:switches] = false
|
126
|
+
|
127
|
+
### File override
|
128
|
+
|
129
|
+
Overrides program defaults.
|
130
|
+
|
131
|
+
cat ~/.altpass.yaml
|
132
|
+
:length: 16
|
133
|
+
:memorizable: false
|
134
|
+
|
135
|
+
### Command-line override
|
136
|
+
|
137
|
+
Command-line options override everything mentioned above. See *Command-line Options* above.
|
138
|
+
|
139
|
+
Examples of Command-Line Usage
|
140
|
+
------------------------------
|
141
|
+
|
142
|
+
These examples assume the above mentioned *Configuration* section is in effect.
|
143
|
+
|
144
|
+
$ altpass.rb
|
145
|
+
nF7zHTNrjtYRmxod
|
146
|
+
|
147
|
+
$ altpass.rb -p
|
148
|
+
oDKfhfYznFN3j4Nv
|
149
|
+
2,869,959,681,148,181,529,600 permutations
|
150
|
+
|
151
|
+
$ altpass.rb --length 8 --memorizable true
|
152
|
+
kSU5yx9e
|
153
|
+
|
154
|
+
$ altpass.rb -l8 -mt -pvvv -s
|
155
|
+
jXJ3oc7z
|
156
|
+
sample sets:
|
157
|
+
["y", "u", "i", "o", "p", "h", "j", "k", "n", "m"]
|
158
|
+
["Q", "W", "E", "R", "T", "A", "S", "D", "F", "G", "Z", "X", "C", "V", "B"]
|
159
|
+
["Y", "U", "P", "H", "J", "K", "L", "N", "M"]
|
160
|
+
["2", "3", "4", "5"]
|
161
|
+
["y", "u", "i", "o", "p", "h", "j", "k", "n", "m"]
|
162
|
+
["q", "w", "e", "r", "t", "a", "s", "d", "f", "g", "z", "x", "c", "v"]
|
163
|
+
["7", "8", "9"]
|
164
|
+
["q", "w", "e", "r", "t", "a", "s", "d", "f", "g", "z", "x", "c", "v"]
|
165
|
+
10 * 15 * 9 * 4 * 10 * 14 * 3 * 14 permutations
|
166
|
+
31,752,000 permutations
|
167
|
+
--length 8 --memorizable true
|
168
|
+
|
169
|
+
Contributing
|
170
|
+
============
|
171
|
+
|
172
|
+
1. Fork it
|
173
|
+
2. Create your feature branch (`git checkout -b my_new_feature`)
|
174
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
175
|
+
4. Push to the branch (`git push origin my_new_feature`)
|
176
|
+
5. Create new Pull Request
|
177
|
+
|
data/Rakefile
ADDED
data/altpass.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'altpass/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = 'altpass'
|
7
|
+
gem.version = Altpass::VERSION
|
8
|
+
|
9
|
+
gem.authors = ['Alex Batko']
|
10
|
+
gem.email = ['alexbatko@gmail.com']
|
11
|
+
|
12
|
+
gem.summary = %q{Generate passwords derived from hand-alternating, visually unambiguous, alphanumeric characters}
|
13
|
+
gem.description = "#{gem.summary}. This is a Ruby gem and command-line utility. Formerly known as 'alexpass'."
|
14
|
+
|
15
|
+
gem.homepage = 'https://github.com/abatko/altpass'
|
16
|
+
|
17
|
+
gem.files = `git ls-files`.split($/)
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
19
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
+
gem.require_paths = ['lib']
|
21
|
+
|
22
|
+
gem.license = 'MIT'
|
23
|
+
end
|
24
|
+
|
data/bin/altpass.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'altpass' # for actually generating the Altpass passwords
|
4
|
+
require 'optparse' # for command-line options parsing
|
5
|
+
require 'yaml' # for loading the YAML configuration file, if present
|
6
|
+
|
7
|
+
# defaults
|
8
|
+
options = {}
|
9
|
+
options[:length] = 8
|
10
|
+
options[:memorizable] = true
|
11
|
+
options[:permutations] = false
|
12
|
+
options[:switches] = false
|
13
|
+
|
14
|
+
# YAML configuration file overrides the defaults below
|
15
|
+
CONFIGURATION_FILE = "#{ENV['HOME']}/.altpass.yaml"
|
16
|
+
yaml_defaults = YAML.load_file(CONFIGURATION_FILE) if File.exist?(CONFIGURATION_FILE) && File.readable?(CONFIGURATION_FILE)
|
17
|
+
options = options.merge(yaml_defaults) unless yaml_defaults.nil?
|
18
|
+
|
19
|
+
# command-line options override yaml_defaults
|
20
|
+
OptionParser.new do |opts|
|
21
|
+
opts.banner = 'Usage: altpass.rb [options]'
|
22
|
+
|
23
|
+
opts.on('-l', '--length [INTEGER>0]', OptionParser::DecimalInteger, 'Password length') do |l|
|
24
|
+
unless l > 0
|
25
|
+
puts 'argument to -l must be > 0'
|
26
|
+
puts opts ; exit
|
27
|
+
end
|
28
|
+
options[:length] = l
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on('-m [t|f]', '--memorizable [true|false]', 'Use the memorizable pattern or not') do |m|
|
32
|
+
case m
|
33
|
+
when /^(t|true)\Z/
|
34
|
+
options[:memorizable] = true
|
35
|
+
when /^(f|false)\Z/
|
36
|
+
options[:memorizable] = false
|
37
|
+
else
|
38
|
+
puts 'argument to -m must be [true|t|false|f]'
|
39
|
+
puts opts ; exit
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on('-p', '--permutations [vvv]', 'Show permutation size; verbosity increases with v\'s') do |p|
|
44
|
+
if !p.nil? && p !~ /^v+\Z/
|
45
|
+
puts 'argument to -p must be v\'s'
|
46
|
+
puts opts ; exit
|
47
|
+
end
|
48
|
+
options[:permutations] = p.nil? ? 'v' : p+'v'
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on('-s', '--switches', 'Show password switches') do |s|
|
52
|
+
options[:switches] = s
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
56
|
+
puts opts ; exit
|
57
|
+
end
|
58
|
+
end.parse!
|
59
|
+
|
60
|
+
def show_permutations(options)
|
61
|
+
permutations = Altpass.permutations(options)
|
62
|
+
# print the number of permutations after adding commas to it
|
63
|
+
puts permutations.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(',').reverse + ' permutations'
|
64
|
+
end
|
65
|
+
|
66
|
+
puts Altpass.generate(:length => options[:length], :memorizable => options[:memorizable])
|
67
|
+
|
68
|
+
show_permutations(options) if options[:permutations]
|
69
|
+
|
70
|
+
puts "--length #{options[:length]} --memorizable #{options[:memorizable]}" if options[:switches]
|
71
|
+
|
data/lib/altpass.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'altpass/version'
|
2
|
+
|
3
|
+
module Altpass
|
4
|
+
|
5
|
+
DEFAULT_LENGTH = 8
|
6
|
+
DEFAULT_OPTIONS = {:length => DEFAULT_LENGTH, :memorizable => true}
|
7
|
+
|
8
|
+
# character sets divided by touch typing hands
|
9
|
+
LN = '12345'.split('') # Left-hand Numbers
|
10
|
+
RN = '67890' .split('') # Right ''
|
11
|
+
LL = ('qwert'+'asdfg'+'zxcvb').split('') # Left-hand Lowercase letters
|
12
|
+
RL = ('yuiop'+'hjkl'+'nm').split('') # Right '' ''
|
13
|
+
LU = LL.collect {|c| c.capitalize} # Left-hand Uppercase letters
|
14
|
+
RU = RL.collect {|c| c.capitalize} # Right '' ''
|
15
|
+
|
16
|
+
AMBIGUOUS =
|
17
|
+
'1lI0O' + # visually ambiguous
|
18
|
+
'6b' # left/right ambiguous
|
19
|
+
|
20
|
+
# patterns for even and odd length passwords;
|
21
|
+
# alternating hands, with the last always being on the left;
|
22
|
+
# only the first in each subset takes part in the "memorizable" pattern: LUUNLLNL
|
23
|
+
@pattern_even = [[RL], [LU, LN, LL], [RU, RN, RL], [LN, LL, LU], [RL, RU, RN], [LL, LU, LN], [RN, RL, RU], [LL]]
|
24
|
+
|
25
|
+
@pattern_odd = [[LL], [RU, RN, RL], [LU, LN, LL], [RN, RL, RU], [LL, LU, LN], [RL, RU, RN], [LN, LL, LU], [RL]]
|
26
|
+
|
27
|
+
# return a password
|
28
|
+
def self.generate(options={})
|
29
|
+
options = self._verify_options(options)
|
30
|
+
password = ''
|
31
|
+
iterations = options[:length]/DEFAULT_LENGTH + 1
|
32
|
+
iterations.times { password += self._generate(options) }
|
33
|
+
password.slice(0...options[:length])
|
34
|
+
end
|
35
|
+
|
36
|
+
# return the number of permutations,
|
37
|
+
# and additionally print out details when options[:permutations] contains v's
|
38
|
+
def self.permutations(options={})
|
39
|
+
options = self._verify_options(options)
|
40
|
+
p = 1
|
41
|
+
pattern = options[:length].even? ? @pattern_even : @pattern_odd
|
42
|
+
plen = pattern.length
|
43
|
+
samples = []
|
44
|
+
(0...options[:length]).each { |i|
|
45
|
+
samples[i] = (options[:memorizable] ? pattern[i%plen][0] : pattern[i%plen].flatten).reject{|c| AMBIGUOUS.include?(c)}
|
46
|
+
p *= samples[i].length # take the product of all sample sizes to get the total number of permutations
|
47
|
+
}
|
48
|
+
if options[:permutations] =~ /^v{3,}\Z/
|
49
|
+
puts 'sample sets:'
|
50
|
+
samples.each {|s|
|
51
|
+
puts s.inspect
|
52
|
+
}
|
53
|
+
end
|
54
|
+
puts "#{samples.collect {|s| s.length}.join(' * ')} permutations" if options[:permutations] =~ /^v{2,}\Z/
|
55
|
+
p
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# verify and return an options hash, after merging the default options with the incoming ones
|
61
|
+
def self._verify_options(options=nil)
|
62
|
+
raise ArgumentError, "expected a Hash, but got: #{options.inspect}" unless options.kind_of?(Hash)
|
63
|
+
options = DEFAULT_OPTIONS.merge(options)
|
64
|
+
raise ArgumentError, "expected :memorizable to be boolean, but got: #{options[:memorizable].inspect}" unless options[:memorizable].kind_of?(TrueClass) || options[:memorizable].kind_of?(FalseClass)
|
65
|
+
raise ArgumentError, "expected :length to be a Fixnum, but got: #{options[:length].inspect}" unless options[:length].kind_of?(Fixnum)
|
66
|
+
raise ArgumentError, "expected :length > 0, but got: #{options[:length]}" unless options[:length] > 0
|
67
|
+
options
|
68
|
+
end
|
69
|
+
|
70
|
+
# generate and return a string, having a parity-appropriate pattern, where each character is sampled from the appropriate character set (depending on whether :memorizable is true or false)
|
71
|
+
def self._generate(options={})
|
72
|
+
options = self._verify_options(options)
|
73
|
+
pattern = options[:length].even? ? @pattern_even : @pattern_odd
|
74
|
+
return pattern.collect { |i|
|
75
|
+
s =''
|
76
|
+
loop do
|
77
|
+
s = _sample(i[options[:memorizable] ? 0 : rand(i.length)])
|
78
|
+
break unless AMBIGUOUS.include?(s)
|
79
|
+
end
|
80
|
+
s
|
81
|
+
}.join.slice(0..-1)
|
82
|
+
end
|
83
|
+
|
84
|
+
# pick a random element from the given array
|
85
|
+
def self._sample(a=[])
|
86
|
+
raise ArgumentError, "expected an Array, but got: #{a.class}" unless a.kind_of?(Array)
|
87
|
+
raise ArgumentError, 'expected a non-empty Array, but got an empty one' unless a.length > 0
|
88
|
+
a[rand(a.length)]
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class AltpassTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test__generate__default_length
|
7
|
+
assert_equal Altpass::DEFAULT_LENGTH, Altpass.generate.length
|
8
|
+
end
|
9
|
+
|
10
|
+
def test__generate__random_length
|
11
|
+
random_length = rand(20)+1
|
12
|
+
assert_equal random_length, Altpass.generate(:length=>random_length).length
|
13
|
+
end
|
14
|
+
|
15
|
+
def test__generate__raise_exception_for_non_hash_argument
|
16
|
+
non_hash_argument = 10
|
17
|
+
exception = assert_raise(ArgumentError) { Altpass.generate(non_hash_argument) }
|
18
|
+
assert_equal "expected a Hash, but got: #{non_hash_argument}", exception.message
|
19
|
+
end
|
20
|
+
|
21
|
+
def test__generate__raise_exception_for_bad_memorizable_hash_value_type
|
22
|
+
non_boolean = {:memorizable => 10}
|
23
|
+
exception = assert_raise(ArgumentError) { Altpass.generate(non_boolean) }
|
24
|
+
assert_equal "expected :memorizable to be boolean, but got: #{non_boolean[:memorizable].inspect}", exception.message
|
25
|
+
end
|
26
|
+
|
27
|
+
def test__generate__raise_exception_for_bad_length_hash_value_type
|
28
|
+
non_fixnum = {:length => 'A'}
|
29
|
+
exception = assert_raise(ArgumentError) { Altpass.generate(non_fixnum) }
|
30
|
+
assert_equal "expected :length to be a Fixnum, but got: #{non_fixnum[:length].inspect}", exception.message
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_raise_exception_for_fixnum_argument_less_than_one_to_generate_to_length
|
34
|
+
fixnum_argument = {:length => 0}
|
35
|
+
exception = assert_raise(ArgumentError) { Altpass.generate(fixnum_argument) }
|
36
|
+
assert_equal "expected :length > 0, but got: #{fixnum_argument[:length].inspect}", exception.message
|
37
|
+
end
|
38
|
+
|
39
|
+
def test__sample
|
40
|
+
assert_equal 'a', Altpass._sample(['a'])
|
41
|
+
assert_equal 'a', Altpass._sample(['a', 'a', 'a'])
|
42
|
+
random_element = Altpass._sample(['a', 'b', 'c'])
|
43
|
+
assert_equal String, random_element.class
|
44
|
+
assert_equal 1, random_element.length
|
45
|
+
end
|
46
|
+
|
47
|
+
def test__sample_raise_exception_for_non_array_argument
|
48
|
+
exception = assert_raise(ArgumentError) { Altpass._sample({}) }
|
49
|
+
assert_equal "expected an Array, but got: Hash", exception.message
|
50
|
+
end
|
51
|
+
|
52
|
+
def test__sample_raise_exception_for_empty_array_argument
|
53
|
+
exception = assert_raise(ArgumentError) { Altpass._sample([]) }
|
54
|
+
assert_equal "expected a non-empty Array, but got an empty one", exception.message
|
55
|
+
end
|
56
|
+
|
57
|
+
def test__permutations
|
58
|
+
# these hardcoded values will need to be updated if/when the character set lengths change
|
59
|
+
assert_equal 31752000, Altpass.permutations
|
60
|
+
assert_equal 53572004640, Altpass.permutations(:memorizable => false)
|
61
|
+
assert_equal 60011280000, Altpass.permutations(:memorizable => true, :length => 11)
|
62
|
+
assert_equal 544505855160960, Altpass.permutations(:memorizable => false, :length => 11)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: altpass
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alex Batko
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-14 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: Generate passwords derived from hand-alternating, visually unambiguous,
|
15
|
+
alphanumeric characters. This is a Ruby gem and command-line utility. Formerly known
|
16
|
+
as 'alexpass'.
|
17
|
+
email:
|
18
|
+
- alexbatko@gmail.com
|
19
|
+
executables:
|
20
|
+
- altpass.rb
|
21
|
+
extensions: []
|
22
|
+
extra_rdoc_files: []
|
23
|
+
files:
|
24
|
+
- .gitignore
|
25
|
+
- Gemfile
|
26
|
+
- LICENSE.txt
|
27
|
+
- README.md
|
28
|
+
- Rakefile
|
29
|
+
- altpass.gemspec
|
30
|
+
- bin/altpass.rb
|
31
|
+
- lib/altpass.rb
|
32
|
+
- lib/altpass/version.rb
|
33
|
+
- test/test_altpass.rb
|
34
|
+
- test/test_helper.rb
|
35
|
+
homepage: https://github.com/abatko/altpass
|
36
|
+
licenses:
|
37
|
+
- MIT
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
none: false
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 1.8.10
|
57
|
+
signing_key:
|
58
|
+
specification_version: 3
|
59
|
+
summary: Generate passwords derived from hand-alternating, visually unambiguous, alphanumeric
|
60
|
+
characters
|
61
|
+
test_files:
|
62
|
+
- test/test_altpass.rb
|
63
|
+
- test/test_helper.rb
|