optools/sys/passgen.py

97 lines
4.3 KiB
Python
Executable File

#!/usr/bin/env python3
# Thanks to https://gist.github.com/stantonk/7268449
# See also:
# http://stackoverflow.com/questions/5480131/will-python-systemrandom-os-urandom-always-have-enough-entropy-for-good-crypto
import argparse
import random
import re
import string
class genPass(object):
def __init__(self, case = None, charset = 'complex', passlen = 32, quotes = True, backslashes = True,
human = False):
# complex is symbols and mixed-case alphanumeric
# simple is mixed-case alphanumeric
_alphanum = string.ascii_letters + string.digits
chars = {'complex': _alphanum + string.punctuation,
'simple': _alphanum}
self.chars = chars[charset]
if not quotes:
self.chars = re.sub('["\']', '', self.chars)
if not backslashes:
self.chars = re.sub('\\\\', '', self.chars)
if human:
_dupechars = ['`', "'", '|', 'l', 'I', 'i', 'l', '1', 'o', '0', 'O']
self.chars = ''.join(sorted(list(set(self.chars) - set(_dupechars))))
if case == 'upper':
self.chars = self.chars.upper()
elif case == 'lower':
self.chars = self.chars.lower()
self.chars = ''.join(sorted(list(set(self.chars))))
self.passlen = passlen
def generate(self):
self.pw = ''
for _ in range(self.passlen):
self.pw += random.SystemRandom().choice(self.chars)
def parseArgs():
args = argparse.ArgumentParser(description = 'A password generator.')
args.add_argument('-t', '--type',
dest = 'passtype',
choices = ['simple', 'complex'], # chars in genPass
default = 'complex',
help = ('Whether to generate "simple" (no symbols, '
'safer for e.g. databases) password(s) or more complex ones. The default is "complex"'))
args.add_argument('-l', '--length',
dest = 'passlen',
metavar = 'LENGTH',
type = int,
default = 32,
help = ('The length of the password(s) to generate. The default is 32'))
args.add_argument('-c', '--count',
dest = 'passcount',
metavar = 'COUNT',
type = int,
default = 1,
help = ('The number of passwords to generate. The default is 1'))
args.add_argument('-q', '--no-quotes',
dest = 'quotes',
action = 'store_false',
help = ('If specified, strip out quotation marks (both " and \') from the passwords. '
'Only relevant if -t/--type is complex, as simple types don\'t contain these'))
args.add_argument('-b', '--no-backslashes',
dest = 'backslashes',
action = 'store_false',
help = ('If specified, strip out backslashes. Only relevant if -t/--type is complex, as '
'simple types don\'t contain these'))
args.add_argument('-H', '--human',
dest = 'human',
action = 'store_true',
help = ('If specified, make the passwords easier to read by human eyes (i.e. no 1 and l, '
'o or O or 0, etc.)'))
caseargs = args.add_mutually_exclusive_group()
caseargs.add_argument('-L', '--lower',
dest = 'case',
action = 'store_const',
const = 'lower',
help = 'If specified, make password all lowercase')
caseargs.add_argument('-U', '--upper',
dest = 'case',
action = 'store_const',
const = 'upper',
help = 'If specified, make password all UPPERCASE')
return(args)
def main():
args = vars(parseArgs().parse_args())
for _ in range(0, args['passcount']):
p = genPass(charset = args['passtype'], passlen = args['passlen'],
quotes = args['quotes'], backslashes = args['backslashes'],
human = args['human'], case = args['case'])
p.generate()
print(p.pw)
if __name__ == '__main__':
main()