from bs4 import BeautifulSoup import httpx, lxml # need lxml as bs4 parser from pprint import pp import pandas as pd from typing import Set import random from io import StringIO def fetch_names_table() -> pd.DataFrame: """Grab the list of most common names across the last century from the american social security agency SSA and parse it out as a pandas dataframe""" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36", "Accept-Language": "en-US,en;q=0.9,de;q=0.8", } page = httpx.get('https://www.ssa.gov/OACT/babynames/decades/century.html', headers=headers) soup = BeautifulSoup(page.content, 'lxml') table = soup.find('table') with StringIO(str(table)) as f: df = pd.read_html(f)[0] return df def make_names_set() -> Set[str]: """extract the male & female names from the SSA table and lowercase them into a single set (to be 100% unique, even if they should already be from the source material)""" my_names = fetch_names_table() return set([ n.lower() for n in [ n for n in my_names['Females']['Name'] ] + [ n for n in my_names['Males']['Name'] ] if ' ' not in n ]) def get_randomized_names_list() -> list[str]: """takes the unique (ordered) set of common names and returns a shuffled version as a list to be used for sequentially assigning randomized user names to containers""" names = list(make_names_set()) random.shuffle(names) return(names) def sha512_crypt(password: str, salt: bytes = None) -> str: """ Produce a SHA‑512 crypt‑style hash (like ``crypt.crypt(..., METHOD_SHA512)``) using only ``hashlib``. The output format matches the traditional ``$6$salt$hash`` string. """ # Generate a 16‑byte salt if none is provided if salt is None: salt = os.urandom(16) # Encode password and salt as bytes pwd_bytes = password.encode("utf-8") # ``crypt`` uses a base64 variant; ``base64`` with ``urlsafe_b64encode`` # and stripping padding gives the same character set. salt_str = base64.urlsafe_b64encode(salt).rstrip(b"=").decode("ascii") # Perform the SHA‑512 hash hasher = hashlib.sha512() hasher.update(pwd_bytes + salt) digest = hasher.digest() # Encode the digest in the same base64 variant hash_str = base64.urlsafe_b64encode(digest).rstrip(b"=").decode("ascii") # Return the full crypt‑style string return f"$6${salt_str}${hash_str}" def create_password(username: str) -> str: """generate a crypted pw hash for this username""" return sha512_crypt(f'{username}123!') def my_password(password) -> str: salt = os.urandom(8) pwd_hash = sha512_crypt.using(salt=salt, rounds=1000).hash(password) return pwd_hash if __name__ == "__main__": import hashlib import os import base64 import yaml from xkcd_passwords import generate_password from passlib.hash import sha512_crypt from pathlib import Path with Path('../names.yml').open('r') as yaml_file: names = yaml.safe_load(yaml_file) # names = get_randomized_names_list() # name_pw_map = { n: (sha512_crypt(pwd:= generate_password(separator="", capitalize=True).strip())) + ',' + pwd for n in names} name_pw_map = { n: (my_password(pwd:= generate_password(separator="", capitalize=True).strip())) + ',' + pwd for n in names} with Path('names.yml').open('w') as yaml_file: yaml.dump(name_pw_map, yaml_file) pp(name_pw_map, width=200, compact=True)