pawgen 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
- data/GPL-2 +339 -0
- data/GPL-3 +674 -0
- data/Manifest.txt +7 -0
- data/README +149 -0
- data/bin/pawgen +208 -0
- data/lib/pawgen.rb +412 -0
- data/pawgen.gemspec +18 -0
- metadata +54 -0
data/lib/pawgen.rb
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
|
|
3
|
+
class PawGen
|
|
4
|
+
DIGITS = '0123456789'.freeze
|
|
5
|
+
UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.freeze
|
|
6
|
+
LOWERCASE = 'abcdefghijklmnopqrstuvwxyz'.freeze
|
|
7
|
+
SYMBOLS = '!"#$%&\'()*+,-./:<=>?@[\\]^_`{|}~'.freeze
|
|
8
|
+
AMBIGUOUS = 'B8G6I1l0OQDS5Z2'.freeze
|
|
9
|
+
VOWELS = '01aeiouyAEIOUY'.freeze
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
super()
|
|
13
|
+
# The original defaulted the length to 8, but it's a bit too
|
|
14
|
+
# short to be the default length these days -- especially
|
|
15
|
+
# considering that phonemic password construction shrinks
|
|
16
|
+
# the password space.
|
|
17
|
+
@length = 12
|
|
18
|
+
@include_uppercase = true
|
|
19
|
+
@include_digits = true
|
|
20
|
+
@include_symbols = false
|
|
21
|
+
@exclude_ambiguous = false
|
|
22
|
+
@exclude_vowels = false
|
|
23
|
+
@mode = method :anglophonemic
|
|
24
|
+
return
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def include_uppercase?
|
|
28
|
+
return @include_uppercase
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def include_uppercase!
|
|
32
|
+
@include_uppercase = true
|
|
33
|
+
return self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def no_uppercase!
|
|
37
|
+
@include_uppercase = false
|
|
38
|
+
return self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def include_digits?
|
|
42
|
+
return @include_digits
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def include_digits!
|
|
46
|
+
@include_digits = true
|
|
47
|
+
return self
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def no_digits!
|
|
51
|
+
@include_digits = false
|
|
52
|
+
return self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def include_symbols?
|
|
56
|
+
return @include_symbols
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def include_symbols!
|
|
60
|
+
@include_symbols = true
|
|
61
|
+
return self
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def no_symbols!
|
|
65
|
+
@include_symbols = false
|
|
66
|
+
return self
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def exclude_ambiguous?
|
|
70
|
+
return @exclude_ambiguous
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def exclude_ambiguous!
|
|
74
|
+
@exclude_ambiguous = true
|
|
75
|
+
return self
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def do_not_exclude_ambiguous!
|
|
79
|
+
@exclude_ambiguous = false
|
|
80
|
+
return self
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
alias_method :dont_exclude_ambiguous!,
|
|
84
|
+
:do_not_exclude_ambiguous!
|
|
85
|
+
|
|
86
|
+
def exclude_vowels?
|
|
87
|
+
return @exclude_vowels
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def exclude_vowels!
|
|
91
|
+
@exclude_vowels = true
|
|
92
|
+
return self
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def do_not_exclude_vowels!
|
|
96
|
+
@exclude_vowels = false
|
|
97
|
+
return self
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
alias_method :dont_exclude_vowels!, :do_not_exclude_vowels!
|
|
101
|
+
|
|
102
|
+
attr_reader :length
|
|
103
|
+
|
|
104
|
+
def length= new_length
|
|
105
|
+
set_length! new_length
|
|
106
|
+
return new_length
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def set_length! new_length
|
|
110
|
+
raise 'invalid length' \
|
|
111
|
+
unless new_length.is_a? Integer and new_length >= 1
|
|
112
|
+
@length = new_length
|
|
113
|
+
return self
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def use_structureless_generator!
|
|
117
|
+
@mode = method :structureless
|
|
118
|
+
return
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def use_anglophonemic_generator!
|
|
122
|
+
@mode = method :anglophonemic
|
|
123
|
+
return
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def use_kanaphonemic_generator!
|
|
127
|
+
@mode = method :kanaphonemic
|
|
128
|
+
return
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def generate
|
|
132
|
+
return @mode.call
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def self::random_bool probability_of_true
|
|
136
|
+
return SecureRandom.random_number < probability_of_true
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def self::random_item array
|
|
140
|
+
return array[SecureRandom.random_number array.length]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def structureless
|
|
144
|
+
charset = LOWERCASE
|
|
145
|
+
charset += DIGITS if include_digits?
|
|
146
|
+
charset += SYMBOLS if include_symbols?
|
|
147
|
+
charset = charset.split('')
|
|
148
|
+
charset -= AMBIGUOUS.split('') if exclude_ambiguous?
|
|
149
|
+
charset -= VOWELS.split('') if exclude_vowels?
|
|
150
|
+
return (0 ... @length).
|
|
151
|
+
map{PawGen.random_item charset}.
|
|
152
|
+
join ''
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Phoneme flags
|
|
156
|
+
PHF_CONSONANT = 0x01
|
|
157
|
+
PHF_VOWEL = 0x02
|
|
158
|
+
PHF_DIPTHONG = 0x04
|
|
159
|
+
PHF_NOT_FIRST = 0x08
|
|
160
|
+
|
|
161
|
+
ANGLOPHONEMES = [
|
|
162
|
+
['a', PHF_VOWEL],
|
|
163
|
+
['ae', PHF_VOWEL | PHF_DIPTHONG],
|
|
164
|
+
['ah', PHF_VOWEL | PHF_DIPTHONG],
|
|
165
|
+
['ai', PHF_VOWEL | PHF_DIPTHONG],
|
|
166
|
+
['b', PHF_CONSONANT],
|
|
167
|
+
['c', PHF_CONSONANT],
|
|
168
|
+
['ch', PHF_CONSONANT | PHF_DIPTHONG],
|
|
169
|
+
['d', PHF_CONSONANT],
|
|
170
|
+
['e', PHF_VOWEL],
|
|
171
|
+
['ee', PHF_VOWEL | PHF_DIPTHONG],
|
|
172
|
+
['ei', PHF_VOWEL | PHF_DIPTHONG],
|
|
173
|
+
['f', PHF_CONSONANT],
|
|
174
|
+
['g', PHF_CONSONANT],
|
|
175
|
+
['gh', PHF_CONSONANT | PHF_DIPTHONG | PHF_NOT_FIRST],
|
|
176
|
+
['h', PHF_CONSONANT],
|
|
177
|
+
['i', PHF_VOWEL],
|
|
178
|
+
['ie', PHF_VOWEL | PHF_DIPTHONG],
|
|
179
|
+
['j', PHF_CONSONANT],
|
|
180
|
+
['k', PHF_CONSONANT],
|
|
181
|
+
['l', PHF_CONSONANT],
|
|
182
|
+
['m', PHF_CONSONANT],
|
|
183
|
+
['n', PHF_CONSONANT],
|
|
184
|
+
['ng', PHF_CONSONANT | PHF_DIPTHONG | PHF_NOT_FIRST],
|
|
185
|
+
['o', PHF_VOWEL],
|
|
186
|
+
['oh', PHF_VOWEL | PHF_DIPTHONG],
|
|
187
|
+
['oo', PHF_VOWEL | PHF_DIPTHONG],
|
|
188
|
+
['p', PHF_CONSONANT],
|
|
189
|
+
['ph', PHF_CONSONANT | PHF_DIPTHONG],
|
|
190
|
+
['qu', PHF_CONSONANT | PHF_DIPTHONG],
|
|
191
|
+
['r', PHF_CONSONANT],
|
|
192
|
+
['s', PHF_CONSONANT],
|
|
193
|
+
['sh', PHF_CONSONANT | PHF_DIPTHONG],
|
|
194
|
+
['t', PHF_CONSONANT],
|
|
195
|
+
['th', PHF_CONSONANT | PHF_DIPTHONG],
|
|
196
|
+
['u', PHF_VOWEL],
|
|
197
|
+
['v', PHF_CONSONANT],
|
|
198
|
+
['w', PHF_CONSONANT],
|
|
199
|
+
['x', PHF_CONSONANT],
|
|
200
|
+
['y', PHF_CONSONANT],
|
|
201
|
+
['z', PHF_CONSONANT],
|
|
202
|
+
]
|
|
203
|
+
|
|
204
|
+
ANGLOPHONEMES.each do |entry|
|
|
205
|
+
entry.first.freeze
|
|
206
|
+
entry.freeze
|
|
207
|
+
end
|
|
208
|
+
ANGLOPHONEMES.freeze
|
|
209
|
+
|
|
210
|
+
ANGLOVOWELS = ANGLOPHONEMES.
|
|
211
|
+
select{|entry| (entry[1] & PHF_VOWEL) != 0}.
|
|
212
|
+
freeze
|
|
213
|
+
ANGLOCONSONANTS = ANGLOPHONEMES.
|
|
214
|
+
select{|entry| (entry[1] & PHF_CONSONANT) != 0}.
|
|
215
|
+
freeze
|
|
216
|
+
|
|
217
|
+
# Requirement flags
|
|
218
|
+
REQ_UPPERCASE = 0x01
|
|
219
|
+
REQ_DIGITS = 0x02
|
|
220
|
+
REQ_SYMBOLS = 0x04
|
|
221
|
+
|
|
222
|
+
def anglophonemic
|
|
223
|
+
raise 'unable to generate such a ' +
|
|
224
|
+
'short anglophonemic password' \
|
|
225
|
+
unless length >= 5
|
|
226
|
+
raise 'unable to generate an ' +
|
|
227
|
+
'anglophonemic password with no vowels' \
|
|
228
|
+
if exclude_vowels?
|
|
229
|
+
|
|
230
|
+
reqs = 0
|
|
231
|
+
reqs |= REQ_UPPERCASE if include_uppercase?
|
|
232
|
+
reqs |= REQ_DIGITS if include_digits?
|
|
233
|
+
reqs |= REQ_SYMBOLS if include_symbols?
|
|
234
|
+
result, unmet_reqs = [] # declare local variables
|
|
235
|
+
begin
|
|
236
|
+
unmet_reqs = reqs
|
|
237
|
+
first = true
|
|
238
|
+
# also re-set after a digit (but not after a symbol)
|
|
239
|
+
result = ''
|
|
240
|
+
prev_phoneme_flags = 0
|
|
241
|
+
should_be = nil
|
|
242
|
+
while result.length < length do
|
|
243
|
+
should_be ||=
|
|
244
|
+
PawGen.random_item [ANGLOVOWELS, ANGLOCONSONANTS]
|
|
245
|
+
phoneme, phoneme_flags = PawGen.random_item should_be
|
|
246
|
+
next if first and (phoneme_flags & PHF_NOT_FIRST) != 0
|
|
247
|
+
# block a vowel followed by a vowel-dipthong
|
|
248
|
+
next if (prev_phoneme_flags & PHF_VOWEL) != 0 and
|
|
249
|
+
(phoneme_flags & PHF_VOWEL) != 0 and
|
|
250
|
+
(phoneme_flags & PHF_DIPTHONG) != 0
|
|
251
|
+
next if result.length + phoneme.length > length
|
|
252
|
+
|
|
253
|
+
if include_uppercase? and
|
|
254
|
+
(first or (phoneme_flags & PHF_CONSONANT) != 0) and
|
|
255
|
+
PawGen.random_bool 0.2 then
|
|
256
|
+
phoneme = phoneme.capitalize
|
|
257
|
+
unmet_reqs &= ~REQ_UPPERCASE
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Note that the unambiguous lowercase 'o' can become the
|
|
261
|
+
# ambiguous 'O' through capitalisation. Contrariwise,
|
|
262
|
+
# the ambiguous lowercase 'l' can become the unambiguous
|
|
263
|
+
# uppercase 'L'.
|
|
264
|
+
next if exclude_ambiguous? and
|
|
265
|
+
phoneme.split('').any?{|c| AMBIGUOUS.include? c}
|
|
266
|
+
|
|
267
|
+
# All the checks for the phoneme passed. Let's add it.
|
|
268
|
+
result << phoneme
|
|
269
|
+
|
|
270
|
+
break if result.length == length
|
|
271
|
+
|
|
272
|
+
# Checking against the [[first]] flag here means
|
|
273
|
+
# requiring at least _two_ phonemes before the digit can
|
|
274
|
+
# appear, because if we just applied the first phoneme,
|
|
275
|
+
# [[first]] is still true.
|
|
276
|
+
if include_digits? and
|
|
277
|
+
!first and
|
|
278
|
+
PawGen.random_bool 0.3 then
|
|
279
|
+
choice = DIGITS.split ''
|
|
280
|
+
choice -= AMBIGUOUS.split '' if exclude_ambiguous?
|
|
281
|
+
result << PawGen.random_item(choice)
|
|
282
|
+
unmet_reqs &= ~REQ_DIGITS
|
|
283
|
+
first = true
|
|
284
|
+
prev_phoneme_flags = 0
|
|
285
|
+
should_be = nil # pick next [[should_be]] at random
|
|
286
|
+
next
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
if include_symbols? and
|
|
290
|
+
!first and
|
|
291
|
+
PawGen.random_bool 0.2 then
|
|
292
|
+
choice = SYMBOLS.split ''
|
|
293
|
+
# Our [[AMBIGUOUS]] does not actually contain any
|
|
294
|
+
# symbols in the current version. This may be a
|
|
295
|
+
# problem, considering [['`]] and [[!/1l|]] and [[&8]]
|
|
296
|
+
# and [[-_]] and [[^~]] and maybe even [[.,]] and
|
|
297
|
+
# [[:;]] and [[()l|]] so we're excluding [[AMBIGUOUS]]
|
|
298
|
+
# anyway in anticipation of a future version
|
|
299
|
+
# mentioning some of those.
|
|
300
|
+
choice -= AMBIGUOUS.split '' if exclude_ambiguous?
|
|
301
|
+
result << PawGen.random_item(choice)
|
|
302
|
+
unmet_reqs &= ~REQ_SYMBOLS
|
|
303
|
+
# not resetting [[first]]; not [[next]]ing
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
if should_be.object_id == ANGLOCONSONANTS.object_id then
|
|
307
|
+
should_be = ANGLOVOWELS
|
|
308
|
+
else
|
|
309
|
+
if (prev_phoneme_flags & PHF_VOWEL) != 0 or
|
|
310
|
+
(phoneme_flags & PHF_DIPTHONG) != 0 or
|
|
311
|
+
PawGen.random_bool(0.6) then
|
|
312
|
+
should_be = ANGLOCONSONANTS
|
|
313
|
+
else
|
|
314
|
+
should_be = ANGLOVOWELS
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
prev_phoneme_flags = phoneme_flags
|
|
318
|
+
first = false
|
|
319
|
+
end
|
|
320
|
+
end until unmet_reqs.zero?
|
|
321
|
+
return result
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# Real kana includes signs to prolongate a preceding vowel or
|
|
325
|
+
# a following consonant. We're not including these, based on
|
|
326
|
+
# the wild-assed guess that the advantage in memorability is
|
|
327
|
+
# outweighed by the disadvantage in reduced password space.
|
|
328
|
+
#
|
|
329
|
+
# Similarly, we're not indicating palatalisation: we'll use
|
|
330
|
+
# 'ti' rather than 'chi', 'tu' rather than 'tsu', and so on.
|
|
331
|
+
KANA_MORAE = ([''] + %w{k g s z t d n h b p m y r w}).
|
|
332
|
+
map{|c| %w{a i u e o}.map{|v| c + v}}.
|
|
333
|
+
flatten + %w{n} - %w{yi ye wu}
|
|
334
|
+
KANA_MORAE.each &:freeze
|
|
335
|
+
KANA_MORAE.freeze
|
|
336
|
+
|
|
337
|
+
def kanaphonemic
|
|
338
|
+
raise 'unable to generate such a ' +
|
|
339
|
+
'short kanaphonemic password' \
|
|
340
|
+
unless length >= 5
|
|
341
|
+
raise 'unable to generate an ' +
|
|
342
|
+
'kanaphonemic password with no vowels' \
|
|
343
|
+
if exclude_vowels?
|
|
344
|
+
|
|
345
|
+
reqs = 0
|
|
346
|
+
reqs |= REQ_UPPERCASE if include_uppercase?
|
|
347
|
+
reqs |= REQ_DIGITS if include_digits?
|
|
348
|
+
reqs |= REQ_SYMBOLS if include_symbols?
|
|
349
|
+
result, unmet_reqs = [] # declare local variables
|
|
350
|
+
begin
|
|
351
|
+
unmet_reqs = reqs
|
|
352
|
+
first = true
|
|
353
|
+
# also re-set after a digit (but not after a symbol)
|
|
354
|
+
result = ''
|
|
355
|
+
while result.length < length do
|
|
356
|
+
phoneme = PawGen.random_item KANA_MORAE
|
|
357
|
+
next if result.length + phoneme.length > length
|
|
358
|
+
|
|
359
|
+
if include_uppercase? and
|
|
360
|
+
PawGen.random_bool 0.2 then
|
|
361
|
+
phoneme = phoneme.capitalize
|
|
362
|
+
unmet_reqs &= ~REQ_UPPERCASE
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
# Note that the unambiguous lowercase 'o' can become the
|
|
366
|
+
# ambiguous 'O' through capitalisation.
|
|
367
|
+
next if exclude_ambiguous? and
|
|
368
|
+
phoneme.split('').any?{|c| AMBIGUOUS.include? c}
|
|
369
|
+
|
|
370
|
+
# All the checks for the phoneme passed. Let's add it.
|
|
371
|
+
result << phoneme
|
|
372
|
+
|
|
373
|
+
break if result.length == length
|
|
374
|
+
|
|
375
|
+
# Checking against the [[first]] flag here means
|
|
376
|
+
# requiring at least _two_ phonemes before the digit can
|
|
377
|
+
# appear, because if we just applied the first phoneme,
|
|
378
|
+
# [[first]] is still true.
|
|
379
|
+
if include_digits? and
|
|
380
|
+
!first and
|
|
381
|
+
PawGen.random_bool 0.3 then
|
|
382
|
+
choice = DIGITS.split ''
|
|
383
|
+
choice -= AMBIGUOUS.split '' if exclude_ambiguous?
|
|
384
|
+
result << PawGen.random_item(choice)
|
|
385
|
+
unmet_reqs &= ~REQ_DIGITS
|
|
386
|
+
first = true
|
|
387
|
+
next
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
if include_symbols? and
|
|
391
|
+
!first and
|
|
392
|
+
PawGen.random_bool 0.2 then
|
|
393
|
+
choice = SYMBOLS
|
|
394
|
+
# Our [[AMBIGUOUS]] does not actually contain any
|
|
395
|
+
# symbols in the current version. This may be a
|
|
396
|
+
# problem, considering [['`]] and [[!/1l|]] and [[&8]]
|
|
397
|
+
# and [[-_]] and [[^~]] and maybe even [[.,]] and
|
|
398
|
+
# [[:;]] and [[()l|]] so we're excluding [[AMBIGUOUS]]
|
|
399
|
+
# anyway in anticipation of a future version
|
|
400
|
+
# mentioning some of those.
|
|
401
|
+
choice -= AMBIGUOUS.split '' if exclude_ambiguous?
|
|
402
|
+
result << PawGen.random_item(choice)
|
|
403
|
+
unmet_reqs &= ~REQ_SYMBOLS
|
|
404
|
+
# not resetting [[first]]; not [[next]]ing
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
first = false
|
|
408
|
+
end
|
|
409
|
+
end until unmet_reqs.zero?
|
|
410
|
+
return result
|
|
411
|
+
end
|
|
412
|
+
end
|
data/pawgen.gemspec
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = 'pawgen'
|
|
3
|
+
s.version = '1.0.0'
|
|
4
|
+
s.date = '2014-10-20'
|
|
5
|
+
s.homepage = 'https://github.com/digwuren/pawgen'
|
|
6
|
+
s.summary = 'A password generator'
|
|
7
|
+
s.author = 'Andres Soolo'
|
|
8
|
+
s.email = 'dig@mirky.net'
|
|
9
|
+
s.files = File.read('Manifest.txt').split(/\n/)
|
|
10
|
+
s.executables << 'pawgen'
|
|
11
|
+
s.license = 'GPL-2'
|
|
12
|
+
s.description = <<EOD
|
|
13
|
+
Pawgen is a password generation tool inspired by Theodore Ts'o's
|
|
14
|
+
pwgen. Generates anglophonemic, kanaphonemic, or syntaxless
|
|
15
|
+
passwords. Implemented in pure Ruby.
|
|
16
|
+
EOD
|
|
17
|
+
s.has_rdoc = false
|
|
18
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: pawgen
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andres Soolo
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-10-20 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: |
|
|
14
|
+
Pawgen is a password generation tool inspired by Theodore Ts'o's
|
|
15
|
+
pwgen. Generates anglophonemic, kanaphonemic, or syntaxless
|
|
16
|
+
passwords. Implemented in pure Ruby.
|
|
17
|
+
email: dig@mirky.net
|
|
18
|
+
executables:
|
|
19
|
+
- pawgen
|
|
20
|
+
extensions: []
|
|
21
|
+
extra_rdoc_files: []
|
|
22
|
+
files:
|
|
23
|
+
- GPL-2
|
|
24
|
+
- GPL-3
|
|
25
|
+
- Manifest.txt
|
|
26
|
+
- README
|
|
27
|
+
- bin/pawgen
|
|
28
|
+
- lib/pawgen.rb
|
|
29
|
+
- pawgen.gemspec
|
|
30
|
+
homepage: https://github.com/digwuren/pawgen
|
|
31
|
+
licenses:
|
|
32
|
+
- GPL-2
|
|
33
|
+
metadata: {}
|
|
34
|
+
post_install_message:
|
|
35
|
+
rdoc_options: []
|
|
36
|
+
require_paths:
|
|
37
|
+
- lib
|
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - '>='
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '0'
|
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - '>='
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
requirements: []
|
|
49
|
+
rubyforge_project:
|
|
50
|
+
rubygems_version: 2.0.14
|
|
51
|
+
signing_key:
|
|
52
|
+
specification_version: 4
|
|
53
|
+
summary: A password generator
|
|
54
|
+
test_files: []
|