/
wgenpass
executable file
·114 lines (98 loc) · 3.35 KB
/
wgenpass
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/usr/bin/env ruby
require "rubygems"
require "bundler"
Bundler.require
class Word
include DataMapper::Resource
property :md5sum, String, :key => true,
:unique_index => true,
:length => 32,
:default => lambda { |r, p| Digest::MD5.hexdigest(r.word) }
property :word, String, :required => true
property :length, Integer, :default => lambda {|r, p| r.word.length }
end
opts = Trollop::options do
version "wpassgen 0.0.1 (c) 2011 Pol Llovet"
banner <<-EOS
Generate a password from a database of words.
Usage:
wgenpass [options]
wgenpass --add <word>+
wgenpass --load <filename>+
where [options] are:
EOS
opt :words, "Number of words per password", :default => 4
opt :number, "Number of passwords to generate", :default => 6
opt :range, "Range of word lengths", :default => "3..5"
opt :load, "Load a file or files of words into the database"
opt :add, "Add words to the database"
opt :clear, "Clear the word database"
opt :stats, "Show word database stats"
opt :verbose, "Show verbose information"
end
if opts[:verbose]
DataMapper::Logger.new($stdout, :debug)
end
DataMapper.setup(:default, 'sqlite://./wgenpasswords.db')
DataMapper.finalize
DataMapper.auto_upgrade!
# this is much less horrifying, in fact, I can do it before making checking.
rng = opts[:range].split(/[^\d+]/)
opts[:range] = Range.new(rng.first.to_i, rng.last.to_i)
Trollop::die :number, "must be non-negative" if opts[:number] < 0
Trollop::die :range, "word length range minimum is one" unless opts[:range].min > 0
if opts[:load]
ARGV.each do |file|
begin
lines = %x{wc -l #{file}}.split.first.to_i #oh well, not platform independent!
pbar = ProgressBar.new(file, lines)
File.open(file, 'r').each_line do |line|
line.split(' ').each do |word|
begin
Word.create(:word => word.downcase)
rescue => e
# fail saves gracefully, why is DM throwing an Exception here?
DataMapper.logger << "SAVE FAILED: #{e}"
end
end
pbar.inc
end
pbar.finish
rescue Exception => e
puts "The file #{file} was not readable."
puts e
end
end
elsif opts[:add]
ARGV.each do |word|
begin
Word.create(:word => word.downcase)
rescue => e
# fail saves gracefully, why is DM throwing an Exception here?
DataMapper.logger << "SAVE FAILED: #{e}"
end
end
elsif opts[:clear]
DataMapper.auto_migrate!
elsif opts[:stats]
puts "Number of words in the database: %d" % [Word.count]
else
passwords = []
# Raw SQL, N queries
query = "SELECT `word` from words WHERE length BETWEEN %d AND %d ORDER BY RANDOM() LIMIT %d"
opts[:number].times do
q = query % [opts[:range].min, opts[:range].max, opts[:words]]
passwords << repository(:default).adapter.select(q)
end
# DataMapper, N*M queries
# count = Word.all( :length.gte => opts[:range].min,
# :length.lte => opts[:range].max).count
# opts[:number].times do
# passwords << opts[:words].times.map do
# Word.first( :length.gte => opts[:range].min,
# :length.lte => opts[:range].max,
# :offset => rand(count)).word
# end
# end
puts passwords.map{|pass| pass.join(' ') }.join("\n")
end