spass 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- spass (0.0.1)
4
+ spass (0.0.2)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
data/History.md CHANGED
@@ -1,6 +1,14 @@
1
1
  History
2
2
  =======
3
3
 
4
+ 0.0.3
5
+ -----
6
+
7
+ - Eliminate -l/--length argument
8
+ - Use -w/--words argument to specify the number of words
9
+ - Default --chars to 8 instead of 10
10
+
11
+
4
12
  0.0.2
5
13
  -----
6
14
 
data/README.md CHANGED
@@ -10,8 +10,9 @@ computer to guess.
10
10
  Prerequisites
11
11
  -------------
12
12
 
13
- Currently, spass only words on Unix-like systems, which are expected to have a
14
- `/usr/share/dict/words` file. Future versions may support other platforms.
13
+ spass assumes you have a dictionary file to use as its source of words. By
14
+ default, `/usr/share/dict/words` is used, but you can pass your own dictionary
15
+ using the `-f/--file` option.
15
16
 
16
17
 
17
18
  Installation
@@ -25,30 +26,38 @@ spass is distributed as a gem, so just do:
25
26
  Usage
26
27
  -----
27
28
 
28
- Run `spass` from the command-line to see usage notes. The first argument is the
29
- minimum passphrase length (in characters). Examples:
29
+ When run without arguments, spass generates 10 passphrases, each 4 words long,
30
+ using words up to 8 characters long. You can configure this behavior by passing
31
+ command-line arguments; run `spass -h` to see full usage notes.
30
32
 
31
- $ spass 12
32
- hive frighten
33
+ Examples:
33
34
 
34
- $ spass 24
35
- moppet castigator harvesters
35
+ $ spass -w 3 # Generate 3-word phrases
36
+ $ spass -w 5 -n 20 # Generate twenty 5-word phrases
37
+ $ spass -c 6 # Limit words to 6 characters
38
+ $ spass -d # Append a digit to each word
39
+ $ spass -f mywords.txt # Get words from mywords.txt (one per line)
36
40
 
37
- $ spass 32
38
- munificent icebound raymond clorets
39
41
 
40
- Passphrases are guaranteed to be at least as long as the given number, but
41
- may be longer. By default, the words are taken from `/usr/share/dict/words`;
42
- if you want to use words from a different dictionary, pass a second argument:
43
42
 
44
- $ spass 12 my_words.txt
43
+ Disclaimer
44
+ ----------
45
+
46
+ spass makes absolutely no guarantee that its output results in secure
47
+ passwords. If you use spass to protect your bank account or your porn
48
+ collection, I cannot be held responsible if you lose your money or marriage.
49
+ [Check your password strength](http://rumkin.com/tools/password/passchk.php)
50
+ before using it for anything important. Passwords generated with spass are
51
+ inherently vulnerable to a dictionary attack; the only thing that can make
52
+ them resistant to such attacks is their length, so always use at least three
53
+ (preferably more) words.
45
54
 
46
55
 
47
56
  Future plans
48
57
  ------------
49
58
 
50
59
  - Optional inclusion of uppercase and symbols
51
- - Avoid word repetition
60
+ - Avoid possible word repetition
52
61
 
53
62
 
54
63
  MIT License
data/bin/spass CHANGED
@@ -5,45 +5,37 @@ require 'optparse'
5
5
 
6
6
  HELP = <<EOF
7
7
 
8
- This script generates a plain-English passphrase of at least the given length
9
- (in characters), using random words from the given dictionary file
10
- (/usr/share/dict/words by default). Only lowercase letters a-z will be included
11
- in the output, making passphrases relatively easy to type (though usually
12
- nonsensical).
8
+ This script generates passphrases using random words from the given dictionary
9
+ file (default: /usr/share/dict/words). It was inspired by http://xkcd.com/936/
13
10
 
14
11
  Examples:
15
12
 
16
- $ spass -l 12
17
- hive frighten
13
+ $ spass -w 3 # Generate 3-word phrases
14
+ $ spass -w 5 -n 20 # Generate twenty 5-word phrases
15
+ $ spass -c 6 # Limit words to 6 characters
16
+ $ spass -d # Append a digit to each word
17
+ $ spass -f mywords.txt # Get words from mywords.txt (one per line)
18
18
 
19
- $ spass -l 24
20
- moppet castigator harvesters
21
-
22
- A 32-character passphrase has about 120 bits of entropy, which is overkill for
23
- most purposes. A 24-character passphrase clocks in at about 90 bits of entropy,
24
- suitable for most high-security applications like root passwords or financial
25
- records. You might want to use a password checker to verify the strength of
26
- your passphrase after generating one that you like:
27
-
28
- http://rumkin.com/tools/password/passchk.php
29
-
30
- Inspired by http://xkcd.com/936/
19
+ Passphrases generated from dictionary words are inherently vulnerable to
20
+ dictionary attacks; using more and/or longer words strengthens them against
21
+ such attacks. The default settings are intended to yield relatively strong,
22
+ easy-to-remember passphrases.
31
23
 
32
24
  EOF
33
25
 
34
26
  options = {
35
- :length => 24,
36
27
  :number => 10,
37
28
  :dict => '/usr/share/dict/words',
38
29
  :digits => false,
39
- :chars => 10,
30
+ :chars => 8,
31
+ :words => 4,
40
32
  }
41
33
 
42
34
  optparse = OptionParser.new do |opts|
43
- opts.on('-l', '--length [NUM]', Integer,
44
- "Ensure passphrases are at least NUM characters.",
45
- "Default: #{options[:length]}") do |len|
46
- options[:length] = len
35
+ opts.on('-w', '--words [NUM]', Integer,
36
+ "Ensure passphrases are at least NUM words long.",
37
+ "Default: #{options[:words]}") do |words|
38
+ options[:words] = words
47
39
  end
48
40
 
49
41
  opts.on('-n', '--number [NUM]', Integer,
@@ -59,14 +51,14 @@ optparse = OptionParser.new do |opts|
59
51
  end
60
52
 
61
53
  opts.on('-d', '--digits',
62
- "Include random numbers from 1-99.",
63
- "Default: False") do |digits|
54
+ "Append a random digit from 0-9 to each word.",
55
+ "Default: #{options[:digits]}") do |digits|
64
56
  options[:digits] = digits
65
57
  end
66
58
 
67
59
  opts.on('-c', '--chars NUM',
68
60
  "Limit words to NUM characters in length.",
69
- "Default: 10") do |chars|
61
+ "Default: #{options[:chars]}") do |chars|
70
62
  options[:chars] = chars
71
63
  end
72
64
 
@@ -86,7 +78,8 @@ rescue OptionParser::InvalidOption => e
86
78
  end
87
79
 
88
80
  sp = Generator.new(options[:dict], options)
81
+ puts "Read #{sp.dict.count} words up to #{sp.chars} characters long from #{sp.file}"
89
82
  options[:number].times do
90
- puts sp.generate(options[:length], :digits=>options[:digits])
83
+ puts sp.generate(options[:words], :digits=>options[:digits])
91
84
  end
92
85
 
data/lib/spass.rb CHANGED
@@ -1,25 +1,25 @@
1
1
 
2
2
  class Generator
3
- # Create a Generator using the given word dictionary, returning
4
- # only words that match the given regular expression
5
- def initialize(dict_path='/usr/share/dict/words', options={})
6
- @dict_path = dict_path
7
- @dict = read_dict(dict_path, options)
3
+ attr_reader :dict, :chars, :allowed, :file
4
+ # Create a Generator using the given word dictionary
5
+ def initialize(file='/usr/share/dict/words', options={})
6
+ @file = file
7
+ @allowed = options[:allowed] || /^[a-z]+$/
8
+ @chars = (options[:chars] || 10).to_i
9
+ @dict = read_dict
8
10
  end
9
11
 
10
12
  # Read a word dictionary from the given file, and return an array
11
13
  # of elements that match the allowed regex. Raise an exception if
12
14
  # the given dictionary file cannot be found.
13
- def read_dict(path, options={})
14
- allowed = options[:allowed] || /^[a-z]+$/
15
- chars = (options[:chars] || 10).to_i
16
- if !File.file?(path)
17
- raise RuntimeError, "Cannot find dict file: #{path}"
15
+ def read_dict
16
+ if !File.file?(@file)
17
+ raise RuntimeError, "Cannot find dict file: #{@file}"
18
18
  end
19
19
  dict = []
20
- IO.readlines(path).each do |line|
20
+ IO.readlines(@file).each do |line|
21
21
  line.strip!
22
- if line.length <= chars && line =~ allowed
22
+ if line.length <= @chars && line =~ @allowed
23
23
  dict << line
24
24
  end
25
25
  end
@@ -31,19 +31,20 @@ class Generator
31
31
  @dict[rand(@dict.count)]
32
32
  end
33
33
 
34
- # Return a random number from 1 to 99
34
+ # Return a random number from 0 to 9
35
35
  def random_number
36
- 1 + rand(99)
36
+ rand(10)
37
37
  end
38
38
 
39
- # Generate a passphrase of at least the given length in characters
40
- def generate(length, options={})
41
- phrase = ''
42
- while phrase.length < length + 1 # to account for trailing space
43
- phrase += "#{random_word} "
44
- phrase += "#{random_number} " if options[:digits]
39
+ # Generate a passphrase with the given number of words
40
+ def generate(num_words, options={})
41
+ words = []
42
+ num_words.times do
43
+ word = random_word
44
+ word += random_number.to_s if options[:digits]
45
+ words << word
45
46
  end
46
- return phrase.chomp
47
+ return words.join(' ')
47
48
  end
48
49
  end
49
50
 
data/spass.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "spass"
3
- s.version = "0.0.2"
3
+ s.version = "0.0.3"
4
4
  s.summary = "Generate passphrases"
5
5
  s.description = <<-EOS
6
6
  spass generates passphrases using random words
data/spec/spass_spec.rb CHANGED
@@ -3,31 +3,35 @@ require 'spass'
3
3
  TEST_DICT = File.expand_path('../data/ten_words', __FILE__)
4
4
 
5
5
  describe Generator do
6
- before(:all) do
6
+ before(:each) do
7
7
  @sp = Generator.new(TEST_DICT)
8
8
  end
9
9
 
10
10
 
11
- describe "#read_dict" do
11
+ describe "#initialize" do
12
12
  it "returns an array of lines from the given file" do
13
- @sp.read_dict(TEST_DICT).should == [
13
+ @sp = Generator.new(TEST_DICT)
14
+ @sp.dict.should == [
14
15
  'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten']
15
16
  end
16
17
 
17
18
  it "only returns words matching a regex" do
18
- @sp.read_dict(TEST_DICT, :allowed=>/^t/).should == ['two', 'three', 'ten']
19
- @sp.read_dict(TEST_DICT, :allowed=>/^f/).should == ['four', 'five']
20
- @sp.read_dict(TEST_DICT, :allowed=>/e$/).should == ['one', 'three', 'five', 'nine']
19
+ @sp = Generator.new(TEST_DICT, :allowed=>/^t/)
20
+ @sp.dict.should == ['two', 'three', 'ten']
21
+ @sp = Generator.new(TEST_DICT, :allowed=>/^f/)
22
+ @sp.dict.should == ['four', 'five']
23
+ @sp = Generator.new(TEST_DICT, :allowed=>/e$/)
24
+ @sp.dict.should == ['one', 'three', 'five', 'nine']
21
25
  end
22
26
 
23
27
  it "only returns words with N chars or fewer" do
24
- @sp.read_dict(TEST_DICT, :chars=>3).should == ['one', 'two', 'six', 'ten']
28
+ @sp = Generator.new(TEST_DICT, :chars=>3)
29
+ @sp.dict.should == ['one', 'two', 'six', 'ten']
25
30
  end
26
31
 
27
32
  it "raises an exception when the file does not exist" do
28
- path = File.expand_path('non/existent/path')
29
33
  lambda do
30
- @sp.read_dict(path)
34
+ Generator.new(File.expand_path('non/existent/path'))
31
35
  end.should raise_error(RuntimeError, /Cannot find dict file/)
32
36
  end
33
37
  end
@@ -43,28 +47,27 @@ describe Generator do
43
47
 
44
48
 
45
49
  describe "#random_number" do
46
- it "returns a number between 1 and 999" do
47
- 1000.times do
50
+ it "returns a number between 0 and 9" do
51
+ 100.times do
48
52
  num = @sp.random_number
49
- num.should be >= 1
50
- num.should be <= 99
53
+ num.should be >= 0
54
+ num.should be <= 9
51
55
  end
52
56
  end
53
57
  end
54
58
 
55
59
 
56
60
  describe "#generate" do
57
- it "is at least the given length" do
58
- [10, 15, 20, 25, 30, 35, 40].each do |len|
59
- 10.times do
60
- @sp.generate(len).length.should be >= len
61
- end
61
+ it "has the given number of words" do
62
+ [1, 2, 3, 4, 5, 6].each do |words|
63
+ phrase = @sp.generate(words)
64
+ phrase.split.count.should == words
62
65
  end
63
66
  end
64
67
 
65
68
  it "includes digits when :digits is true" do
66
69
  10.times do
67
- @sp.generate(24, :digits=>true).should =~ /^([a-z]+ [0-9]+ ?)+$/
70
+ @sp.generate(24, :digits=>true).should =~ /^([a-z]+[0-9] ?)+$/
68
71
  end
69
72
  end
70
73
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spass
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ - 3
10
+ version: 0.0.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Eric Pierce
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-11-01 00:00:00 -06:00
18
+ date: 2011-11-02 00:00:00 -06:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency