diff --git a/sys/passgen.py b/sys/passgen.py new file mode 100755 index 0000000..e4b7091 --- /dev/null +++ b/sys/passgen.py @@ -0,0 +1,97 @@ +#!/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() \ No newline at end of file