Skip to content

Instantly share code, notes, and snippets.

@creisor
Last active March 28, 2023 16:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save creisor/8fb5ba300e65f2e02e32475ef831b567 to your computer and use it in GitHub Desktop.
Save creisor/8fb5ba300e65f2e02e32475ef831b567 to your computer and use it in GitHub Desktop.
A python (python3) password generator, possibly overkill
import string
import secrets
# https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_account-policy.html#default-policy-details
SYMBOLS='!@#$%^&*()_+-=[]{}|'
def gen_password(length=20, symbols=True, uppercase=True, lowercase=True, digits=True):
choices = ''
if symbols:
choices += SYMBOLS
if uppercase:
choices += string.ascii_uppercase
if lowercase:
choices += string.ascii_lowercase
if digits:
choices += string.digits
while True:
symbols_satisfied = False if symbols else True
uppercase_satisfied = False if uppercase else True
lowercase_satisfied = False if lowercase else True
digits_satisfied = False if digits else True
password = ''.join(secrets.choice(choices) for i in range(length))
# ensure we have at least all the required things
if not symbols_satisfied:
if set(SYMBOLS) & set(password):
symbols_satisfied = True
if not uppercase_satisfied:
if (any(c.isupper() for c in password)):
uppercase_satisfied = True
if not lowercase_satisfied:
if (any(c.islower() for c in password)):
lowercase_satisfied = True
if not digits_satisfied:
if sum(c.isdigit() for c in password) >= 3:
digits_satisfied = True
if (symbols_satisfied
and uppercase_satisfied
and lowercase_satisfied
and digits_satisfied):
break
return password
import unittest
import string
from . import util
class TestUtil(unittest.TestCase):
def test_gen_password_len(self):
tests = (20, 30, 100)
for length in tests:
with self.subTest(length=length):
self.assertEqual(
len(util.gen_password(length=length)),
length)
def test_gen_password_symbols(self):
reps = 20
for i in range(1, reps):
pw = util.gen_password(symbols=True)
with self.subTest(pw=pw):
self.assertTrue(set(util.SYMBOLS) & set(pw))
for i in range(1, reps):
pw = util.gen_password(symbols=False)
with self.subTest(pw=pw):
self.assertFalse(set(util.SYMBOLS) & set(pw))
def test_gen_password_cases(self):
reps = 20
for i in range(1, reps):
pw = util.gen_password(uppercase=True)
with self.subTest(pw=pw):
self.assertTrue(set(string.ascii_uppercase) & set(pw))
for i in range(1, reps):
pw = util.gen_password(uppercase=False)
with self.subTest(pw=pw):
self.assertFalse(set(string.ascii_uppercase) & set(pw))
for i in range(1, reps):
pw = util.gen_password(lowercase=True)
with self.subTest(pw=pw):
self.assertTrue(set(string.ascii_lowercase) & set(pw))
for i in range(1, reps):
pw = util.gen_password(lowercase=False)
with self.subTest(pw=pw):
self.assertFalse(set(string.ascii_lowercase) & set(pw))
def test_gen_password_digits(self):
reps = 20
for i in range(1, reps):
pw = util.gen_password(digits=True)
with self.subTest(pw=pw):
self.assertTrue(set(string.digits) & set(pw))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment