alexpass 0.1.0 → 0.1.1
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/lib/alexpass.rb +6 -80
- data/test/test_alexpass.rb +2 -57
- metadata +5 -6
data/lib/alexpass.rb
CHANGED
@@ -1,90 +1,16 @@
|
|
1
1
|
class Alexpass
|
2
2
|
|
3
|
-
VERSION = '0.1.
|
3
|
+
VERSION = '0.1.1'
|
4
|
+
DEPRECATED = 'Sorry, but this gem has been replaced by Altpass: https://github.com/abatko/altpass'
|
4
5
|
|
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 = '1lI0O' + # visually ambiguous
|
17
|
-
'6b' # left/right ambiguous
|
18
|
-
|
19
|
-
# patterns for even and odd length passwords;
|
20
|
-
# alternating hands, with the last always being on the left;
|
21
|
-
# only the first in each subset takes part in the "memorizable" pattern: LUUNLLNL
|
22
|
-
@pattern_even = [[RL], [LU, LN, LL], [RU, RN, RL], [LN, LL, LU], [RL, RU, RN], [LL, LU, LN], [RN, RL, RU], [LL]]
|
23
|
-
|
24
|
-
@pattern_odd = [[LL], [RU, RN, RL], [LU, LN, LL], [RN, RL, RU], [LL, LU, LN], [RL, RU, RN], [LN, LL, LU], [RL]]
|
25
|
-
|
26
|
-
# return a password
|
27
6
|
def self.generate(options={})
|
28
|
-
|
29
|
-
|
30
|
-
iterations = options[:length]/DEFAULT_LENGTH + 1
|
31
|
-
iterations.times { password += self._generate(options) }
|
32
|
-
password.slice(0...options[:length])
|
7
|
+
warn DEPRECATED
|
8
|
+
DEPRECATED
|
33
9
|
end
|
34
10
|
|
35
|
-
# return the number of permutations,
|
36
|
-
# and additionally print out details when options[:permutations] contains v's
|
37
11
|
def self.permutations(options={})
|
38
|
-
|
39
|
-
|
40
|
-
pattern = options[:length].even? ? @pattern_even : @pattern_odd
|
41
|
-
plen = pattern.length
|
42
|
-
samples = []
|
43
|
-
(0...options[:length]).each { |i|
|
44
|
-
samples[i] = (options[:memorizable] ? pattern[i%plen][0] : pattern[i%plen].flatten).reject{|c| AMBIGUOUS.include?(c)}
|
45
|
-
p *= samples[i].length # take the product of all sample sizes to get the total number of permutations
|
46
|
-
}
|
47
|
-
if options[:permutations] =~ /^v{3,}\Z/
|
48
|
-
puts "sample sets:"
|
49
|
-
samples.each {|s|
|
50
|
-
puts s.inspect
|
51
|
-
}
|
52
|
-
end
|
53
|
-
puts "#{samples.collect {|s| s.length}.join(' * ')} permutations" if options[:permutations] =~ /^v{2,}\Z/
|
54
|
-
p
|
55
|
-
end
|
56
|
-
|
57
|
-
private
|
58
|
-
|
59
|
-
# verify and return an options hash, after merging the default options with the incoming ones
|
60
|
-
def self._verify_options(options=nil)
|
61
|
-
raise ArgumentError, "expected a Hash, but got: #{options.inspect}" unless options.kind_of?(Hash)
|
62
|
-
options = DEFAULT_OPTIONS.merge(options)
|
63
|
-
raise ArgumentError, "expected :memorizable to be boolean, but got: #{options[:memorizable].inspect}" unless options[:memorizable].kind_of?(TrueClass) || options[:memorizable].kind_of?(FalseClass)
|
64
|
-
raise ArgumentError, "expected :length to be a Fixnum, but got: #{options[:length].inspect}" unless options[:length].kind_of?(Fixnum)
|
65
|
-
raise ArgumentError, "expected :length > 0, but got: #{options[:length]}" unless options[:length] > 0
|
66
|
-
options
|
67
|
-
end
|
68
|
-
|
69
|
-
# 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)
|
70
|
-
def self._generate(options={})
|
71
|
-
options = self._verify_options(options)
|
72
|
-
pattern = options[:length].even? ? @pattern_even : @pattern_odd
|
73
|
-
return pattern.collect { |i|
|
74
|
-
s =''
|
75
|
-
loop do
|
76
|
-
s = _sample(i[options[:memorizable] ? 0 : rand(i.length)])
|
77
|
-
break unless AMBIGUOUS.include?(s)
|
78
|
-
end
|
79
|
-
s
|
80
|
-
}.join.slice(0..-1)
|
81
|
-
end
|
82
|
-
|
83
|
-
# pick a random element from the given array
|
84
|
-
def self._sample(a=[])
|
85
|
-
raise ArgumentError, "expected an Array, but got: #{a.class}" unless a.kind_of?(Array)
|
86
|
-
raise ArgumentError, "expected a non-empty Array, but got an empty one" unless a.length > 0
|
87
|
-
a[rand(a.length)]
|
12
|
+
warn DEPRECATED
|
13
|
+
DEPRECATED
|
88
14
|
end
|
89
15
|
|
90
16
|
end
|
data/test/test_alexpass.rb
CHANGED
@@ -3,63 +3,8 @@ require 'test_helper'
|
|
3
3
|
|
4
4
|
class AlexpassTest < Test::Unit::TestCase
|
5
5
|
|
6
|
-
def
|
7
|
-
assert_equal Alexpass::
|
8
|
-
end
|
9
|
-
|
10
|
-
def test__generate__random_length
|
11
|
-
random_length = rand(20)+1
|
12
|
-
assert_equal random_length, Alexpass.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) { Alexpass.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) { Alexpass.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) { Alexpass.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) { Alexpass.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', Alexpass._sample(['a'])
|
41
|
-
assert_equal 'a', Alexpass._sample(['a', 'a', 'a'])
|
42
|
-
random_element = Alexpass._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) { Alexpass._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) { Alexpass._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, Alexpass.permutations
|
60
|
-
assert_equal 53572004640, Alexpass.permutations(:memorizable => false)
|
61
|
-
assert_equal 60011280000, Alexpass.permutations(:memorizable => true, :length => 11)
|
62
|
-
assert_equal 544505855160960, Alexpass.permutations(:memorizable => false, :length => 11)
|
6
|
+
def test__deprecated
|
7
|
+
assert_equal Alexpass::DEPRECATED, Alexpass.generate
|
63
8
|
end
|
64
9
|
|
65
10
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alexpass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,10 +9,10 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-14 00:00:00.000000000Z
|
13
13
|
dependencies: []
|
14
|
-
description:
|
15
|
-
|
14
|
+
description: ! 'Sorry, but this gem has been replaced by Altpass: https://github.com/abatko/altpass
|
15
|
+
(sorry!)'
|
16
16
|
email:
|
17
17
|
- alexbatko@gmail.com
|
18
18
|
executables: []
|
@@ -46,8 +46,7 @@ rubyforge_project:
|
|
46
46
|
rubygems_version: 1.8.10
|
47
47
|
signing_key:
|
48
48
|
specification_version: 3
|
49
|
-
summary:
|
50
|
-
characters
|
49
|
+
summary: ! 'Sorry, but this gem has been replaced by Altpass: https://github.com/abatko/altpass'
|
51
50
|
test_files:
|
52
51
|
- test/test_alexpass.rb
|
53
52
|
- test/test_helper.rb
|