summaryrefslogtreecommitdiff
path: root/sys/passgen.py
blob: e4b70918e135e2f7322d12ccbde2c73ca5959424 (plain)
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
#!/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()