Subversion Repositories pub

Compare Revisions

No changes between revisions

Ignore whitespace Rev 198 → Rev 199

/relevation/trunk/devtools/genpw.py
0,0 → 1,125
#!/usr/bin/env python
 
"""
Simplistic Password Generator.
"""
 
# This file is released under the CC0 license (CC equivalent of Public Domain).
#
# License details:
# http://creativecommons.org/publicdomain/zero/1.0/legalcode
 
import random
import string
import locale
import sys
 
try:
import checkpw
DO_CHECK=True
except ImportError:
DO_CHECK=False
 
DEFAULT_RESULTS = 20
DEFAULT_LENGTH = 8
#Letters and digits are repeated to favour them
FAVOURED_SET = string.lowercase + string.digits #string.letters
STDSET = string.uppercase + string.punctuation
DEFAULT_CSET = FAVOURED_SET * 8 + STDSET
 
REJECTS_SET = [ 'l', '1', 'I', '0', 'O' ] # FIXME: What else?
DEFAULT_FORCE = '*' # Symbolic
 
def pwgen(length=DEFAULT_LENGTH, possible=DEFAULT_CSET,
reject_ambiguous=False, force=DEFAULT_FORCE):
'''
pwgen(int, str, bool, [ str, str, ...]) -> str
 
Generate a password.
length - Password length
possible - List of characters from where to pick
reject_ambiguous - Reject characters that can be hard to tell from each other (e.g. 1 vs l vs I)
force - List of forcible sets. Force at least one character of each set.
'''
pw = ''
rejects = []
LENGTH = length
if reject_ambiguous:
rejects = REJECTS_SET
if force == DEFAULT_FORCE:
force = [ string.lowercase, string.uppercase, string.digits ]
if type(force) != list:
raise ValueError('force must be a list of strings')
def pick_one(cset):
'''
Return a random character from cset
'''
c = random.choice(cset)
while c in rejects:
c = random.choice(cset)
return c
# Forcible includes
for cset in force:
pw += pick_one(cset)
length -= 1
for i in range(length):
pick = random.choice(possible)
while pick in rejects:
pick = random.choice(possible)
pw += pick
# Re-mix order (randomize forced-characters' position)
if len(pw) > LENGTH:
pw = pw[0:LENGTH]
l = list(pw)
random.shuffle(l)
pw = ''.join(l)
return pw
 
def main(argv):
rounds = DEFAULT_RESULTS
length = DEFAULT_LENGTH
cset = DEFAULT_CSET
reject_ambiguous = False
secure = False # When True, reject mediocre passwords and below
 
# No need to use getopt or anything like it
positional = []
for arg in argv:
if arg in ( '-B', '--ambiguous' ):
reject_ambiguous = True
elif arg in ( '-s', '--secure' ):
if not DO_CHECK:
raise EnvironmentError('Can\'t generate secure-only password without checkpw.py')
secure = True
else:
positional.append(arg)
try:
if len(positional) > 0:
length = int(positional[0])
if len(positional) > 1:
rounds = int(positional[1])
except ValueError:
sys.stderr.write('Usage: pwgen [-B] [length] [num pw]\n');
sys.exit(2);
 
def newpw():
return pwgen(length=length, reject_ambiguous=reject_ambiguous)
 
for i in range(rounds):
pw = newpw()
if DO_CHECK:
( score, verdict, _ ) = checkpw.check(pw)
if secure:
while score < checkpw.STRONG_THRESHOLD:
pw = newpw()
( score, verdict, _ ) = checkpw.check(pw)
print '%s\t%d\t%s' % ( pw, score, verdict)
#print _
else:
print pw
 
if __name__ == '__main__':
locale.setlocale(locale.LC_ALL, 'C')
main(sys.argv[1:])
 
# vim:set ts=4 et ai: #
Property changes:
Added: svn:executable
+*
\ No newline at end of property