Skip to content

Commit ad97bda

Browse files
committed
Initial implementation
1 parent 34a8730 commit ad97bda

3 files changed

Lines changed: 112 additions & 0 deletions

File tree

‎20_password/password.py‎

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Author : Lee A. Congdon <lee@lcongdon.com>
4+
Date : 2021-09-09
5+
Purpose: Tiny Python Projects password exercise
6+
"""
7+
8+
import argparse
9+
import random
10+
import re
11+
import string
12+
13+
14+
def get_args():
15+
"""Parse arguments"""
16+
17+
parser = argparse.ArgumentParser(
18+
description='Password maker',
19+
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
20+
21+
parser.add_argument('file',
22+
nargs='+',
23+
default=None,
24+
type=argparse.FileType('rt'),
25+
help='Input file(s)',
26+
metavar='FILE')
27+
28+
parser.add_argument('-n',
29+
'--num',
30+
default=3,
31+
type=int,
32+
help='Number of passwords to generate',
33+
metavar='num_passwords')
34+
35+
parser.add_argument('-w',
36+
'--num_words',
37+
default=4,
38+
type=int,
39+
help='Number of words to use for password',
40+
metavar='num_words')
41+
42+
parser.add_argument('-m',
43+
'--min_word_len',
44+
default=3,
45+
type=int,
46+
help='Minimum word length',
47+
metavar='minimum')
48+
49+
parser.add_argument('-x',
50+
'--max_word_len',
51+
default=6,
52+
type=int,
53+
help='Maximum word length',
54+
metavar='maximum')
55+
56+
parser.add_argument('-s',
57+
'--seed',
58+
default=None,
59+
type=int,
60+
help='Random seed',
61+
metavar='seed')
62+
63+
parser.add_argument('-l',
64+
'--l33t',
65+
action='store_true',
66+
help='Obfuscate letters')
67+
68+
return parser.parse_args()
69+
70+
71+
def clean(word):
72+
"""Remove all non-letters"""
73+
pattern = re.compile(r'[^A-Za-z]')
74+
return re.sub(pattern, '', word)
75+
76+
77+
def ransom(word):
78+
"""Randomly capitalize characters"""
79+
return ''.join([char.lower() if random.choice([True, False])
80+
else char.upper() for char in word])
81+
82+
83+
def l33t(password):
84+
mapping = {'a': '@', 'A': '4', 'O': '0',
85+
't': '+', 'E': '3', 'I': '1', 'S': '5'}
86+
return ''.join([mapping.get(char, char) for char in ransom(password)]) + random.choice(string.punctuation)
87+
88+
89+
def main():
90+
"""Main program"""
91+
92+
args = get_args()
93+
random.seed(args.seed)
94+
words = set()
95+
96+
def word_len(word):
97+
return args.min_word_len <= len(word) <= args.max_word_len
98+
99+
for fh in args.file:
100+
for line in fh:
101+
for word in filter(word_len, map(clean, line.lower().split())):
102+
words.add(word.title())
103+
words = sorted(words)
104+
passwords = [''.join(random.sample(words, args.num_words))
105+
for _ in range(args.num)]
106+
if args.l33t:
107+
passwords = map(l33t, passwords)
108+
print('\n'.join(passwords))
109+
110+
111+
if __name__ == '__main__':
112+
main()

0 commit comments

Comments
 (0)