passphrase 0.0.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.
@@ -0,0 +1,52 @@
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
+ attr_reader :num_words
11
+ attr_reader :odd_char
12
+ attr_reader :phrase
13
+ attr_reader :unmixed_phrase
14
+ attr_reader :words
15
+
16
+ def initialize(argv)
17
+ @options = Options.new(argv)
18
+ @num_words = @options.num_words
19
+ @words = []
20
+ end
21
+
22
+ def run
23
+ word_list = WordList.create
24
+ list_selector = Random.new(@num_words, 0, word_list.length - 1).rand_array
25
+ @num_words.times do |iword|
26
+ word_hash = Random.new(5, 1, 6).rand_array.join.to_sym
27
+ @words << word_list[list_selector[iword]][word_hash]
28
+ end
29
+ @phrase = @unmixed_phrase = @words.join(' ')
30
+ mix_odd_char if @options.mix
31
+ end
32
+
33
+ private
34
+
35
+ def mix_odd_char
36
+ odd =
37
+ %w( ~ & + : ? 4 ) +
38
+ %w( ! * [ ; / 5 ) +
39
+ %w( # \( ] " 0 6 ) +
40
+ %w( $ \) \\ ' 1 7 ) +
41
+ %w( % - { < 2 8 ) +
42
+ %w( ^ = } > 3 9 )
43
+ odd_char_index = Random.new(1, 0, odd.length - 1).rand_array.shift
44
+ word_index = Random.new(1, 0, @num_words - 1).rand_array.shift
45
+ word_length = @words[word_index].length
46
+ char_index = Random.new(1, 0, word_length - 1).rand_array.shift unless word_length.zero?
47
+ char_index ||= 0
48
+ @words[word_index][char_index] = @odd_char = odd[odd_char_index]
49
+ @phrase = @words.join(' ')
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,60 @@
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
+
15
+ def initialize(argv)
16
+ @num_words = DEFAULT_NUM_WORDS
17
+ @mix = true
18
+ parse(argv)
19
+ validate
20
+ end
21
+
22
+ private
23
+
24
+ def parse(argv)
25
+ OptionParser.new do |opts|
26
+ opts.banner = "Usage: passphrase [options]"
27
+ opts.separator "Options:"
28
+ opts.on("-n", "--num-words NUMBER", Integer,
29
+ "Desired number of words (#{NUM_WORDS_RANGE.to_s}), default #{DEFAULT_NUM_WORDS}") do |num|
30
+ @num_words = num
31
+ end
32
+ opts.on("-x", "--[no-]mix", "Mix in odd character, default mix") do |m|
33
+ @mix = m
34
+ end
35
+ opts.on_tail("-h", "--help", "Show this message") do
36
+ puts opts
37
+ exit
38
+ end
39
+ opts.on_tail("-v", "--version", "Show version") do
40
+ puts "#{$PROGRAM_NAME}, version #{Passphrase::Version::STRING}"
41
+ exit
42
+ end
43
+
44
+ begin
45
+ opts.parse!(argv)
46
+ rescue OptionParser::ParseError => e
47
+ STDERR.puts e.message, "\n", opts
48
+ exit(1)
49
+ end
50
+ end
51
+ end
52
+
53
+ def validate
54
+ unless NUM_WORDS_RANGE.include?(@num_words)
55
+ STDERR.puts "Number of words out of range: allowed #{NUM_WORD_RANGE.to_s}: specified #{@num_words}"
56
+ exit(1)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,41 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'net/http'
4
+
5
+ module Passphrase
6
+ class Random
7
+
8
+ RANDOM_ORG = "www.random.org"
9
+
10
+ attr_reader :num
11
+ attr_reader :min
12
+ attr_reader :max
13
+ attr_reader :via_random_org
14
+ attr_reader :rand_array
15
+
16
+ def initialize(num, min, max)
17
+ @num, @min, @max = num, min, max
18
+ @rand_array = []
19
+ generate_rand_array
20
+ end
21
+
22
+ private
23
+
24
+ def generate_rand_array
25
+ query = "/integers/?col=1&base=10&format=plain&rnd=new" +
26
+ "&num=#{@num}&min=#{@min}&max=#{@max}"
27
+ site = Net::HTTP.new(RANDOM_ORG)
28
+ response, data = site.get(query)
29
+ raise unless response.code == "200"
30
+ @rand_array = data.split.collect {|num| num.to_i}
31
+ @via_random_org = true
32
+ rescue
33
+ max = @max - @min + 1
34
+ offset = @min
35
+ @num.times do
36
+ @rand_array << (rand(max) + offset)
37
+ end
38
+ @via_random_org = false
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,14 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ module Passphrase
4
+ module Version
5
+
6
+ # rubygems rational versioning policy
7
+ # http://docs.rubygems.org/read/chapter/7
8
+ MAJOR = 0
9
+ MINOR = 0
10
+ BUILD = 1
11
+
12
+ STRING = [MAJOR, MINOR, BUILD].compact.join('.')
13
+ end
14
+ end
@@ -0,0 +1,30 @@
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
@@ -0,0 +1,33 @@
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
@@ -0,0 +1,17 @@
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
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: passphrase
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Edmund Sumbar
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-01-15 00:00:00 -07:00
14
+ default_executable: passphrase
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: bundler
18
+ version_requirements: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 1.0.0
24
+ requirement: *id001
25
+ prerelease: false
26
+ type: :development
27
+ - !ruby/object:Gem::Dependency
28
+ name: jeweler
29
+ version_requirements: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 1.5.2
35
+ requirement: *id002
36
+ prerelease: false
37
+ type: :development
38
+ description: |+
39
+ = passphrase
40
+
41
+ Passphrase is a command line tool written in Ruby for generating a passphrase
42
+ using the {Diceware(TM) method}[http://world.std.com/~reinhold/diceware.html].
43
+
44
+ The act of rolling dice is simulated by requesting random numbers from
45
+ {www.random.org}[http://www.random.org]. If a network error occurs or a request
46
+ fails, the program gracefully degenerates to using Ruby's global +rand+ method,
47
+ which is based on the Mersenne Twister algorithm.
48
+
49
+ Words in the generated passphrase are selected from either the Diceware list or
50
+ the alternate list edited by Alan Beale, referred to as the _Beale_ list. The
51
+ choice of list for each word is made randomly. Both lists are embedded into the
52
+ code as compressed, base64 encoded strings. No external files are referenced.
53
+
54
+ == Generating a passphrase
55
+
56
+ The command line interface is simple. You have the option to specify the number
57
+ of words in the generated passphrase within the range of 3 to 10. The default
58
+ is 5. One _odd_ character is automatically mixed into one of the words
59
+ comprising the passphrase. You can forgo mixing if desired.
60
+
61
+ Usage: passphrase [options]
62
+ Options:
63
+ -n, --num-words NUMBER Desired number of words (3..10), default 5
64
+ -x, --[no-]mix Mix in odd character, default mix
65
+ -h, --help Show this message
66
+ -v, --version Show version
67
+
68
+ == Examples
69
+
70
+ $ passphrase --num-words 3
71
+ unmixed phrase => shot elm mild
72
+ odd character => !
73
+ passphrase => shot e!m mild
74
+
75
+ $ passphrase --num-words 4 --no-mix
76
+ passphrase => humus smooth persia mz
77
+
78
+ If you don't like a generated passphrase, repeat the command.
79
+
80
+ == Contributing to passphrase
81
+
82
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
83
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
84
+ * Fork the project
85
+ * Start a feature/bugfix branch
86
+ * Commit and push until you are happy with your contribution
87
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
88
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
89
+
90
+ == Copyright
91
+
92
+ Copyright (c) 2011 Edmund Sumbar. See LICENSE.txt for
93
+ further details.
94
+
95
+ email: esumbar@gmail.com
96
+ executables:
97
+ - passphrase
98
+ extensions: []
99
+
100
+ extra_rdoc_files:
101
+ - LICENSE.txt
102
+ - README.rdoc
103
+ files:
104
+ - Gemfile
105
+ - Gemfile.lock
106
+ - LICENSE.txt
107
+ - README.rdoc
108
+ - Rakefile
109
+ - VERSION
110
+ - bin/passphrase
111
+ - lib/passphrase/data.rb
112
+ - lib/passphrase/generator.rb
113
+ - lib/passphrase/options.rb
114
+ - lib/passphrase/random.rb
115
+ - lib/passphrase/version.rb
116
+ - lib/passphrase/wordlist.rb
117
+ - test/test_options.rb
118
+ - test/test_wordlist.rb
119
+ has_rdoc: true
120
+ homepage: http://github.com/esumbar/passphrase
121
+ licenses: []
122
+
123
+ post_install_message:
124
+ rdoc_options: []
125
+
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ hash: 2
134
+ segments:
135
+ - 0
136
+ version: "0"
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: "0"
143
+ requirements: []
144
+
145
+ rubyforge_project:
146
+ rubygems_version: 1.4.1
147
+ signing_key:
148
+ specification_version: 3
149
+ summary: Generate a passphrase using the Diceware method.
150
+ test_files:
151
+ - test/test_options.rb
152
+ - test/test_wordlist.rb