I work for a service desk and change A LOT of passwords. Most the time the end user is a complete fool that doesn't understand the requirements for the password they want to use. So I created a program that will generate random passwords based on a randomness level (1 - 3).
Here's how the levels work:
- Reads the passwords from a file that you made, these are the most readable passwords
- Runs through a
gibberish
function and returns somewhat word like passwords complete with uppercase, lowercase, integer, and special character - Completely random string, no pattern to it, has uppercase, lowercase, integers, and special characters.
What I would like to know is if there is anything I can do better inside of this program, along with a way to make more readable strings output from the gibberish
function.
import optparse
import string
import random
import itertools
import os
from random import randint
init_cons = (set(string.ascii_lowercase) - set("aeiou")
- set("qxc")
| {"bl", "br", "cl", "cr", "dr", "fl", "fr", "gl", "gr", "pl", "pr", "sk", "sl", "sm", "sn", "sp", "st",
"str", "sw", "tr"}
)
final_cons = (set(string.ascii_uppercase) - set("aeiou")
- set("qxcsj")
| {"ct", "ft", "mp", "nd", "ng", "nk", "nt",
"pt", "sk", "sp", "ss", "st"}
)
vowels = "aeiou"
SYLLABLES = map(''.join, itertools.product(init_cons,
vowels,
final_cons))
opts = optparse.OptionParser()
opts.add_option("-l", "--level", metavar="RANDOMNESS LEVEL",
dest="level", help="How random do you want the passwords [1-3]")
opts.add_option("-a", "--add", metavar="PASS TO ADD",
dest="add", help="Add a password to the password file")
opts.add_option("--test-demo", action="store_true", dest="test",
help="Run the program 5 times in each level")
(options, args) = opts.parse_args()
def define_randomness_level(level):
""" Return how random you the strings are going to be
:type level: String the level you're on with your randomness
>>> from gen import define_randomness_level
>>>
>>> print(define_randomness_level(2))
>>> 2
"""
if level == "1":
return 1
elif level == "2":
return 2
elif level == "3":
return 3
else:
return None
def random_strings(size=randint(8, 15), spec_chars=random.choice("?!@*^"), chars=string.ascii_lowercase + string.digits
+ string.ascii_uppercase):
""" Return a random string between 8 and 15 characters long.
:type size: Integers, the length of the string returned
:type spec_chars: String of special characters that is randomly grabbed from
:type chars: String of random characters
>>> from gen import random_strings
>>>
>>> print(random_strings())
>>> hfYpvO4YCzHuCW^
"""
return ''.join(random.choice(chars) for _ in xrange(size)) + spec_chars
def read_pass_from_file(filename):
""" Read from the file if you want actual readable password strings
:type filename: I shouldn't have to tell you what this is..
>>> from gen import read_pass_from_file
>>>
>>> print(read_pass_from_file("pass_list.txt"))
>>> Cocoa!55
"""
with open(filename, "r") as data:
arr = data.read().splitlines()
return random.choice(arr)
def gibberish(count):
""" Somewhat readable stuff that almost makes sense.
:type count: Integer, how many somewhat words you want smooshed together
>>> from gen import gibberish
>>>
>>> print(gibberish(2))
>>> druJdiE!9
"""
return ''.join(random.sample(SYLLABLES, count)) + random.choice("?!@*^") + random.choice(string.digits)
def add_to_file(word):
""" Add a password to the password file
:type word: String, your cool password you want added to the file
>>> from gen import add_to_file
>>>
>>> add_to_file("this1SAt3st!")
>>> NOTHING! BECAUSE IT'S IN THE FILE!
"""
with open("pass_list.txt", "r") as words:
data = words.read()
open("pass_list.txt", "w").write(data + "\n{}".format(word))
def test_levels(amount):
""" Test each level of randomness because @boardrider thought it was confusing
:type amount: Integer, run each level this many times
>>> from gen import test_levels
>>>
>>> test_levels(5)
>>> Running with level: 1
>>> Scha3fer!07
>>> ...
"""
command_list = ["python gen.py -l 1", "python gen.py -l 2", "python gen.py -l 3"]
while amount != 0:
amount -= 1
for command in command_list:
arr = command.split(" ")
print("Running with level: {}".format(arr[3]))
os.system(command)
def console_main(opt):
""" Main section of the program, decide where to send what command
:type opt: Dict, given as an option
"""
if define_randomness_level(opt) == 1:
return read_pass_from_file("pass_list.txt")
elif define_randomness_level(opt) == 2:
return gibberish(2)
elif define_randomness_level(opt) == 3:
return random_strings()
else:
raise NotImplementedError("Randomness level of {} is not implemented yet".format(options.level))
if __name__ == '__main__':
# To test run with the --test-demo flag
if options.level:
print(console_main(options.level))
elif options.add:
add_to_file(options.add)
elif options.test:
test_levels(5)
Example of usage:
C:\bin\python\gen_pass.py>python gen.py --test-demo Running with level: 1 MSHa!899 Running with level: 2 proIclamp@0 Running with level: 3 DkrYnuADyI! Running with level: 1 Scha3fer!07 Running with level: 2 hespproE@4 Running with level: 3 wm4m2rVfjh! Running with level: 1 American!Dad!07 Running with level: 2 taSreL!8 Running with level: 3 TcR5ozXofmCUlY8^ Running with level: 1 American!Dad!07 Running with level: 2 peVcloO@6 Running with level: 3 9ZktisBY? Running with level: 1 grAnd1k! Running with level: 2 floskneD!7 Running with level: 3 3jbHmth4j0P@ None
x
amount if times to output level 1, 2 and 3? \$\endgroup\$