haddock 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +28 -0
- data/Manifest.txt +8 -0
- data/README.txt +81 -0
- data/Rakefile +9 -0
- data/bin/ha-gen +45 -0
- data/lib/haddock.rb +81 -0
- data/test/names.txt +2 -0
- data/test/test_haddock.rb +60 -0
- metadata +73 -0
data/History.txt
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
=== 0.2.0 / 2009-03-29
|
2
|
+
|
3
|
+
* 1 major enhancement
|
4
|
+
|
5
|
+
* Changed "haddock" to "ha-gen" for Haskell compliance.
|
6
|
+
|
7
|
+
|
8
|
+
=== 0.1.1 / 2009-03-29
|
9
|
+
|
10
|
+
* 2 minor enhancements
|
11
|
+
|
12
|
+
* Add version option to command-line utility.
|
13
|
+
* Bumping up version numbers to improve credibility.
|
14
|
+
|
15
|
+
|
16
|
+
=== 0.1.0 / 2009-03-29
|
17
|
+
|
18
|
+
* 2 minor enhancements
|
19
|
+
|
20
|
+
* Friendlier command-line errors.
|
21
|
+
* General cleanup.
|
22
|
+
|
23
|
+
|
24
|
+
=== 0.0.1 / 2009-03-28
|
25
|
+
|
26
|
+
* 1 major enhancement
|
27
|
+
|
28
|
+
* Birthday!
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
= haddock
|
2
|
+
|
3
|
+
http://github.com/stephencelis/haddock
|
4
|
+
|
5
|
+
|
6
|
+
== DESCRIPTION
|
7
|
+
|
8
|
+
A more memorable password generator. Swordfish? No, I got tired of that. I
|
9
|
+
changed it.
|
10
|
+
|
11
|
+
|
12
|
+
== FEATURES/PROBLEMS
|
13
|
+
|
14
|
+
* Secure!
|
15
|
+
|
16
|
+
|
17
|
+
== SYNOPSIS
|
18
|
+
|
19
|
+
In your apps:
|
20
|
+
|
21
|
+
require "rubygems"
|
22
|
+
require "haddock"
|
23
|
+
include Haddock
|
24
|
+
Password.generate # => "bowl9&bracky"
|
25
|
+
Password.generate(30) # => "Phlebotomus2473?nonconditioned"
|
26
|
+
Password.generate(8) # => "amy7@rax"
|
27
|
+
|
28
|
+
|
29
|
+
On the command line:
|
30
|
+
|
31
|
+
% ha-gen
|
32
|
+
bowl9&bracky
|
33
|
+
% ha-gen -l31
|
34
|
+
symbolistically5<overthwartways
|
35
|
+
|
36
|
+
|
37
|
+
== REQUIREMENTS
|
38
|
+
|
39
|
+
A newline-delimited words file. By default, it uses "/usr/share/dict/words" or
|
40
|
+
"/usr/share/words".
|
41
|
+
|
42
|
+
Otherwise:
|
43
|
+
|
44
|
+
Haddock::Password.diction = "/path/to/words"
|
45
|
+
|
46
|
+
|
47
|
+
Or:
|
48
|
+
|
49
|
+
% ha-gen -f /path/to/words
|
50
|
+
|
51
|
+
|
52
|
+
== INSTALL
|
53
|
+
|
54
|
+
GitHub:
|
55
|
+
|
56
|
+
% gem install stephencelis-haddock --source=http://gems.github.com
|
57
|
+
|
58
|
+
|
59
|
+
== LICENSE
|
60
|
+
|
61
|
+
(The MIT License)
|
62
|
+
|
63
|
+
(c) 2009-* Stephen Celis, stephen@stephencelis.com.
|
64
|
+
|
65
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
66
|
+
of this software and associated documentation files (the "Software"), to deal
|
67
|
+
in the Software without restriction, including without limitation the rights
|
68
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
69
|
+
copies of the Software, and to permit persons to whom the Software is
|
70
|
+
furnished to do so, subject to the following conditions:
|
71
|
+
|
72
|
+
The above copyright notice and this permission notice shall be included in all
|
73
|
+
copies or substantial portions of the Software.
|
74
|
+
|
75
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
76
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
77
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
78
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
79
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
80
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
81
|
+
SOFTWARE.
|
data/Rakefile
ADDED
data/bin/ha-gen
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__) + "/../lib"
|
4
|
+
require "optparse"
|
5
|
+
require "haddock"
|
6
|
+
include Haddock
|
7
|
+
|
8
|
+
parser = OptionParser.new do |opts|
|
9
|
+
opts.banner = "usage: #{File.basename($0)} [options]"
|
10
|
+
|
11
|
+
opts.on("-V", "--version") do
|
12
|
+
require 'capistrano/version'
|
13
|
+
puts "#{File.basename($0)}: v#{Haddock::VERSION}"
|
14
|
+
exit
|
15
|
+
end
|
16
|
+
|
17
|
+
opts.on("-h", "--help") do
|
18
|
+
puts opts
|
19
|
+
exit
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on("-l", "--length [length]") do |value|
|
23
|
+
raise Password::LengthError, "Invalid length" if value.match(/\D/)
|
24
|
+
@length = value.to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-f", "--words [words file]") do |value|
|
28
|
+
Password.diction = value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
parser.parse!
|
34
|
+
puts @length ? Password.generate(@length) : Password.generate
|
35
|
+
rescue OptionParser::ParseError, Password::LengthError => error
|
36
|
+
warn "#{File.basename($0)}: #{error.message} " +
|
37
|
+
"(must be between #{Password::MINIMUM} and #{Password::MAXIMUM})."
|
38
|
+
puts parser
|
39
|
+
exit 1
|
40
|
+
rescue Password::NoWordsError => error
|
41
|
+
warn "#{File.basename($0)}: #{error.message}."
|
42
|
+
puts "Word lists are available here: http://wordlist.sourceforge.net"
|
43
|
+
puts parser
|
44
|
+
exit 1
|
45
|
+
end
|
data/lib/haddock.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# A more memorable password generator. Swordfish? No, I got tired of that. I
|
2
|
+
# changed it.
|
3
|
+
module Haddock
|
4
|
+
VERSION = '0.2.0'
|
5
|
+
|
6
|
+
module Password
|
7
|
+
MINIMUM = 8
|
8
|
+
MAXIMUM = 31
|
9
|
+
DEFAULT = 12
|
10
|
+
|
11
|
+
SYMBOLS = '`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?'
|
12
|
+
|
13
|
+
class << self
|
14
|
+
@@paths = %w(/usr/share/dict/words /usr/share/words)
|
15
|
+
|
16
|
+
# Generates a more memorable password. Its one optional argument
|
17
|
+
# determines the length of the generated password, and cannot be less
|
18
|
+
# than 8 or greater than 31 characters (default: 12).
|
19
|
+
#
|
20
|
+
# Password.generate # => "bowl9&bracky"
|
21
|
+
# Password.generate(30) # => "Phlebotomus2473?nonconditioned"
|
22
|
+
# Password.generate(8) # => "amy7@rax"
|
23
|
+
def generate(length = DEFAULT)
|
24
|
+
unless defined? @@diction
|
25
|
+
self.diction = @@paths.find { |path| File.exist? path }
|
26
|
+
end
|
27
|
+
|
28
|
+
raise LengthError, "Invalid length" unless length.is_a? Integer
|
29
|
+
raise LengthError, "Password length is too short" if length < MINIMUM
|
30
|
+
raise LengthError, "Password length is too long" if length > MAXIMUM
|
31
|
+
|
32
|
+
words_limit = length * 0.75 # Ensure over-proportionate word lengths.
|
33
|
+
|
34
|
+
begin
|
35
|
+
words = %W(#{random_word} #{random_symbol}#{random_word})
|
36
|
+
words_length = words.to_s.length
|
37
|
+
end until words_length < length && words_length > words_limit
|
38
|
+
|
39
|
+
words.join random_number(length - words_length)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Sets the dictionary. Uses "/usr/share/dict/words" or
|
43
|
+
# "/usr/share/words" otherwise.
|
44
|
+
#
|
45
|
+
# Password.diction = File.expand_path(__FILE__) + "/my_words.txt"
|
46
|
+
def diction=(path)
|
47
|
+
@@diction = IO.readlines path
|
48
|
+
rescue TypeError
|
49
|
+
raise NoWordsError, "No words file found"
|
50
|
+
rescue Errno::ENOENT
|
51
|
+
raise NoWordsError, "No words file at #{path.inspect}"
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def random_word
|
57
|
+
@@diction[rand(@@diction.length)].chomp
|
58
|
+
end
|
59
|
+
|
60
|
+
def random_symbol
|
61
|
+
SYMBOLS[rand(SYMBOLS.length), 1]
|
62
|
+
end
|
63
|
+
|
64
|
+
def random_number(digits)
|
65
|
+
begin
|
66
|
+
number = rand(10 ** digits).to_s
|
67
|
+
end until number.length == digits
|
68
|
+
|
69
|
+
number
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Raised if a password is generated with too few or too many characters.
|
74
|
+
class LengthError < ArgumentError
|
75
|
+
end
|
76
|
+
|
77
|
+
# Raised if no words file is found.
|
78
|
+
class NoWordsError < StandardError
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/test/names.txt
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "haddock"
|
3
|
+
|
4
|
+
class TestHaddock < Test::Unit::TestCase
|
5
|
+
include Haddock
|
6
|
+
|
7
|
+
def test_generates_password
|
8
|
+
password = Password.generate
|
9
|
+
assert_instance_of String, password
|
10
|
+
assert_equal Password::DEFAULT, password.length
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_password_format
|
14
|
+
symbols = "[#{Regexp.quote Password::SYMBOLS}]"
|
15
|
+
pattern = /^[a-z]+[0-9]+#{symbols}{1}[a-z]+/i
|
16
|
+
assert_match(pattern, Password.generate)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_generates_variable_password
|
20
|
+
assert_equal Password.generate(18).length, 18
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_accepts_alternate_wordlist
|
24
|
+
Password.diction = path = File.dirname(__FILE__) + "/names.txt"
|
25
|
+
pattern = Regexp.new File.read(path).split.join("|")
|
26
|
+
assert_match(pattern, Password.generate(14))
|
27
|
+
ensure
|
28
|
+
Password.diction = "/usr/share/dict/words"
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_fail_on_too_short
|
32
|
+
assert_raise Password::LengthError do
|
33
|
+
Password.generate(Password::MINIMUM - 1)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_fail_on_too_long
|
38
|
+
assert_raise Password::LengthError do
|
39
|
+
Password.generate(Password::MAXIMUM + 1)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_fail_on_invalid
|
44
|
+
assert_raise Password::LengthError do
|
45
|
+
Password.generate("invalid")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_fail_on_invalid_path
|
50
|
+
assert_raise Password::NoWordsError do
|
51
|
+
Password.diction = "invalid/path"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_fail_on_nil_path
|
56
|
+
assert_raise Password::NoWordsError do
|
57
|
+
Password.diction = nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: haddock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stephen Celis
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-01 00:00:00 -05:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.11.0
|
24
|
+
version:
|
25
|
+
description: A more memorable password generator. Swordfish? No, I got tired of that. I changed it.
|
26
|
+
email:
|
27
|
+
- stephen@stephencelis.com
|
28
|
+
executables:
|
29
|
+
- ha-gen
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files:
|
33
|
+
- History.txt
|
34
|
+
- Manifest.txt
|
35
|
+
- README.txt
|
36
|
+
files:
|
37
|
+
- History.txt
|
38
|
+
- Manifest.txt
|
39
|
+
- README.txt
|
40
|
+
- Rakefile
|
41
|
+
- bin/ha-gen
|
42
|
+
- lib/haddock.rb
|
43
|
+
- test/names.txt
|
44
|
+
- test/test_haddock.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/stephencelis/haddock
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --main
|
50
|
+
- README.txt
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: haddock
|
68
|
+
rubygems_version: 1.3.1
|
69
|
+
signing_key:
|
70
|
+
specification_version: 2
|
71
|
+
summary: A more memorable password generator
|
72
|
+
test_files:
|
73
|
+
- test/test_haddock.rb
|