passphrase 0.1.0 → 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 +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +1 -0
- data/CHANGELOG.md +35 -0
- data/LICENSE +19 -0
- data/README.md +178 -0
- data/bin/passphrase +3 -10
- data/lib/passphrase.rb +11 -0
- data/lib/passphrase/CLI.rb +76 -0
- data/lib/passphrase/default.rb +15 -0
- data/lib/passphrase/diceware_method.rb +67 -0
- data/lib/passphrase/diceware_random.rb +117 -0
- data/lib/passphrase/language_query.rb +26 -0
- data/lib/passphrase/passphrase.rb +80 -0
- data/lib/passphrase/version.rb +3 -12
- data/lib/passphrase/word_query.rb +21 -0
- data/lib/passphrase/wordlist/words.sqlite3 +0 -0
- data/spec/passphrase/cli_spec.rb +47 -0
- data/spec/passphrase/diceware_method_spec.rb +61 -0
- data/spec/passphrase/diceware_random_spec.rb +124 -0
- data/spec/passphrase/language_query_spec.rb +48 -0
- data/spec/passphrase/passphrase_spec.rb +118 -0
- data/spec/passphrase/word_query_spec.rb +30 -0
- data/spec/spec_helper.rb +91 -0
- metadata +168 -148
- metadata.gz.sig +0 -0
- data/Gemfile +0 -14
- data/Gemfile.lock +0 -16
- data/LICENSE.txt +0 -20
- data/README.rdoc +0 -62
- data/Rakefile +0 -33
- data/VERSION +0 -1
- data/lib/passphrase/data.rb +0 -1632
- data/lib/passphrase/generator.rb +0 -81
- data/lib/passphrase/options.rb +0 -65
- data/lib/passphrase/random.rb +0 -56
- data/lib/passphrase/wordlist.rb +0 -30
- data/test/test_options.rb +0 -33
- data/test/test_wordlist.rb +0 -17
data/lib/passphrase/generator.rb
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
require File.join(File.dirname(__FILE__), 'options')
|
4
|
-
require File.join(File.dirname(__FILE__), 'wordlist')
|
5
|
-
require File.join(File.dirname(__FILE__), 'random')
|
6
|
-
|
7
|
-
module Passphrase
|
8
|
-
class Generator
|
9
|
-
|
10
|
-
NON_ALPHANUM_REGEX = /[~!#\$%\^&\*\(\)\-=\+\[\]\\\{\}:;"'<>\?\/]/
|
11
|
-
NON_ALPHANUM_ARRAY = %w( ~ ! # $ % ^ & * \( \) - = + [ ] \\ { } : ; " ' < > ? / )
|
12
|
-
|
13
|
-
attr_reader :phrase
|
14
|
-
attr_reader :unmixed_phrase
|
15
|
-
|
16
|
-
def initialize(argv)
|
17
|
-
@options = Options.new(argv)
|
18
|
-
@words = []
|
19
|
-
Random.use_local if @options.local
|
20
|
-
end
|
21
|
-
|
22
|
-
def run
|
23
|
-
num_words = @options.num_words
|
24
|
-
word_list = WordList.create
|
25
|
-
list_selector = Random.new(num_words, 0, word_list.length - 1).to_array
|
26
|
-
num_words.times do |iword|
|
27
|
-
word_hash = Random.new(5, 1, 6).to_array.join.to_sym
|
28
|
-
@words << word_list[list_selector[iword]][word_hash]
|
29
|
-
end
|
30
|
-
@unmixed_phrase = @words.join(" ")
|
31
|
-
@phrase = @unmixed_phrase.clone
|
32
|
-
mix_phrase if mix?
|
33
|
-
end
|
34
|
-
|
35
|
-
def mix?
|
36
|
-
@options.mix
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
|
41
|
-
def mix_phrase
|
42
|
-
mixin_capital unless @phrase =~ /[A-Z]/
|
43
|
-
mixin_number unless @phrase =~ /\d/
|
44
|
-
mixin_nonalphanum unless @phrase =~ NON_ALPHANUM_REGEX
|
45
|
-
end
|
46
|
-
|
47
|
-
def mixin_capital
|
48
|
-
index, character = make_character_selection
|
49
|
-
@phrase[index] = character.upcase
|
50
|
-
end
|
51
|
-
|
52
|
-
def mixin_number
|
53
|
-
index, character = make_character_selection
|
54
|
-
numbers = ("0".."9").to_a
|
55
|
-
number = numbers[one_random_number(numbers.length - 1)]
|
56
|
-
@phrase[index] = number
|
57
|
-
end
|
58
|
-
|
59
|
-
def mixin_nonalphanum
|
60
|
-
index, character = make_character_selection
|
61
|
-
len = NON_ALPHANUM_ARRAY.length
|
62
|
-
non_alphanum = NON_ALPHANUM_ARRAY[one_random_number(len - 1)]
|
63
|
-
@phrase[index] = non_alphanum
|
64
|
-
end
|
65
|
-
|
66
|
-
def make_character_selection
|
67
|
-
return [] unless @phrase =~ /[a-z]/
|
68
|
-
index = one_random_number(@phrase.length - 1)
|
69
|
-
character = @phrase.slice(index, 1)
|
70
|
-
until character =~ /[a-z]/
|
71
|
-
index = index.succ.modulo(@phrase.length)
|
72
|
-
character = @phrase.slice(index, 1)
|
73
|
-
end
|
74
|
-
[index, character]
|
75
|
-
end
|
76
|
-
|
77
|
-
def one_random_number(max)
|
78
|
-
Random.new(1, 0, max).to_array.shift
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
data/lib/passphrase/options.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'optparse'
|
4
|
-
require File.join(File.dirname(__FILE__), 'version')
|
5
|
-
|
6
|
-
module Passphrase
|
7
|
-
class Options
|
8
|
-
|
9
|
-
NUM_WORDS_RANGE = (3..10)
|
10
|
-
DEFAULT_NUM_WORDS = 5
|
11
|
-
|
12
|
-
attr_reader :num_words
|
13
|
-
attr_reader :mix
|
14
|
-
attr_reader :local
|
15
|
-
|
16
|
-
def initialize(argv)
|
17
|
-
@num_words = DEFAULT_NUM_WORDS
|
18
|
-
@mix = true
|
19
|
-
@local = false
|
20
|
-
parse(argv)
|
21
|
-
validate
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def parse(argv)
|
27
|
-
OptionParser.new do |opts|
|
28
|
-
opts.banner = "Usage: passphrase [options]"
|
29
|
-
opts.separator "Options:"
|
30
|
-
opts.on("-n", "--num-words NUMBER", Integer,
|
31
|
-
"Desired number of words (#{NUM_WORDS_RANGE.to_s}), default #{DEFAULT_NUM_WORDS}") do |num|
|
32
|
-
@num_words = num
|
33
|
-
end
|
34
|
-
opts.on("-x", "--[no-]mix", "Mix in cap, num, non-alphanum, default mix") do |m|
|
35
|
-
@mix = m
|
36
|
-
end
|
37
|
-
opts.on("-l", "--local", "Force use of local random number generator") do |l|
|
38
|
-
@local = l
|
39
|
-
end
|
40
|
-
opts.on_tail("-h", "--help", "Show this message and exit") do
|
41
|
-
puts opts
|
42
|
-
exit
|
43
|
-
end
|
44
|
-
opts.on_tail("-v", "--version", "Show version and exit") do
|
45
|
-
puts "#{File.basename($PROGRAM_NAME)}, version #{Passphrase::Version::STRING}"
|
46
|
-
exit
|
47
|
-
end
|
48
|
-
|
49
|
-
begin
|
50
|
-
opts.parse!(argv)
|
51
|
-
rescue OptionParser::ParseError => e
|
52
|
-
STDERR.puts e.message, "\n", opts
|
53
|
-
exit(1)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def validate
|
59
|
-
unless NUM_WORDS_RANGE.include?(@num_words)
|
60
|
-
STDERR.puts "Number of words out of range: allowed #{NUM_WORDS_RANGE.to_s}: specified #{@num_words}"
|
61
|
-
exit(1)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
data/lib/passphrase/random.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'net/http'
|
4
|
-
require 'securerandom'
|
5
|
-
|
6
|
-
module Passphrase
|
7
|
-
class Random
|
8
|
-
|
9
|
-
@@use_random_org = true
|
10
|
-
|
11
|
-
def initialize(num, min, max)
|
12
|
-
@num, @min, @max = num, min, max
|
13
|
-
@array_of_rands = []
|
14
|
-
@via_random_org = true
|
15
|
-
generate_array_of_rands
|
16
|
-
end
|
17
|
-
|
18
|
-
def via_random_org?
|
19
|
-
@via_random_org
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_array
|
23
|
-
@array_of_rands
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.use_local
|
27
|
-
@@use_random_org = false
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def generate_array_of_rands
|
33
|
-
if @@use_random_org
|
34
|
-
query = "/integers/?col=1&base=10&format=plain&rnd=new" +
|
35
|
-
"&num=#{@num}&min=#{@min}&max=#{@max}"
|
36
|
-
site = Net::HTTP.new("www.random.org")
|
37
|
-
response, data = site.get(query)
|
38
|
-
raise unless response.code == "200"
|
39
|
-
@array_of_rands = data.split.collect {|num| num.to_i}
|
40
|
-
else
|
41
|
-
local_rands
|
42
|
-
end
|
43
|
-
rescue
|
44
|
-
local_rands
|
45
|
-
end
|
46
|
-
|
47
|
-
def local_rands
|
48
|
-
max = @max - @min + 1
|
49
|
-
offset = @min
|
50
|
-
@num.times do
|
51
|
-
@array_of_rands << (SecureRandom.random_number(max) + offset)
|
52
|
-
end
|
53
|
-
@via_random_org = false
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
data/lib/passphrase/wordlist.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'zlib'
|
4
|
-
require 'base64'
|
5
|
-
require File.join(File.dirname(__FILE__), 'data')
|
6
|
-
|
7
|
-
module Passphrase
|
8
|
-
module WordList
|
9
|
-
|
10
|
-
def self.create
|
11
|
-
decoded_wordlists
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def self.decoded_wordlists
|
17
|
-
Data::ENCODED.collect {|encoded_list| self.decode(encoded_list) }
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.decode(encoded_list)
|
21
|
-
decoded_list = {}
|
22
|
-
lines = Zlib::Inflate.inflate(Base64.decode64(encoded_list)).split(/\n/)
|
23
|
-
lines.grep(/^\d{5}/).each do |line|
|
24
|
-
key, value = line.chomp.split
|
25
|
-
decoded_list[key.to_sym] = value
|
26
|
-
end
|
27
|
-
decoded_list
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/test/test_options.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'options'
|
5
|
-
|
6
|
-
class TestOptions < Test::Unit::TestCase
|
7
|
-
|
8
|
-
def test_000_empty_args
|
9
|
-
opts = Passphrase::Options.new([])
|
10
|
-
assert_equal Passphrase::Options::DEFAULT_NUM_WORDS, opts.num_words
|
11
|
-
assert opts.mix
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_001_specify_num_words
|
15
|
-
num = Passphrase::Options::DEFAULT_NUM_WORDS - 1
|
16
|
-
opts = Passphrase::Options.new(%W{--num-words #{num}})
|
17
|
-
assert_equal num, opts.num_words
|
18
|
-
assert opts.mix
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_002_specify_mix
|
22
|
-
opts = Passphrase::Options.new(%W{--no-mix})
|
23
|
-
assert_equal Passphrase::Options::DEFAULT_NUM_WORDS, opts.num_words
|
24
|
-
assert !opts.mix
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_003_specify_num_words_and_mix
|
28
|
-
num = Passphrase::Options::DEFAULT_NUM_WORDS - 1
|
29
|
-
opts = Passphrase::Options.new(%W{--num-words #{num} --no-mix})
|
30
|
-
assert_equal num, opts.num_words
|
31
|
-
assert !opts.mix
|
32
|
-
end
|
33
|
-
end
|
data/test/test_wordlist.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'wordlist'
|
5
|
-
|
6
|
-
class TestOptions < Test::Unit::TestCase
|
7
|
-
|
8
|
-
def setup
|
9
|
-
@wordlist = Passphrase::WordList.create
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_000_sample_words
|
13
|
-
assert_equal 2, @wordlist.length
|
14
|
-
assert_equal "embalm", @wordlist[0][:'24356']
|
15
|
-
assert_equal "potato", @wordlist[1][:'46132']
|
16
|
-
end
|
17
|
-
end
|