Skip to content

Commit 2b8c9c3

Browse files
committed
ll
1 parent c1c384c commit 2b8c9c3

3 files changed

Lines changed: 482 additions & 241 deletions

File tree

Lines changed: 161 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,167 @@
1-
# PasswordGenerator GGearing 314 01/10/19
2-
# modified Prince Gangurde 4/4/2020
3-
4-
import random
5-
6-
import pycountry
7-
8-
9-
def generate_password():
10-
# Define characters and word sets
11-
special_characters = list("!@#$%/?<>|&*-=+_")
12-
13-
animals = (
14-
"ant",
15-
"alligator",
16-
"baboon",
17-
"badger",
18-
"barb",
19-
"bat",
20-
"beagle",
21-
"bear",
22-
"beaver",
23-
"bird",
24-
"bison",
25-
"bombay",
26-
"bongo",
27-
"booby",
28-
"butterfly",
29-
"bee",
30-
"camel",
31-
"cat",
32-
"caterpillar",
33-
"catfish",
34-
"cheetah",
35-
"chicken",
36-
"chipmunk",
37-
"cow",
38-
"crab",
39-
"deer",
40-
"dingo",
41-
"dodo",
42-
"dog",
43-
"dolphin",
44-
"donkey",
45-
"duck",
46-
"eagle",
47-
"earwig",
48-
"elephant",
49-
"emu",
50-
"falcon",
51-
"ferret",
52-
"fish",
53-
"flamingo",
54-
"fly",
55-
"fox",
56-
"frog",
57-
"gecko",
58-
"gibbon",
59-
"giraffe",
60-
"goat",
61-
"goose",
62-
"gorilla",
63-
)
64-
65-
colours = (
66-
"red",
67-
"orange",
68-
"yellow",
69-
"green",
70-
"blue",
71-
"indigo",
72-
"violet",
73-
"purple",
74-
"magenta",
75-
"cyan",
76-
"pink",
77-
"brown",
78-
"white",
79-
"grey",
80-
"black",
81-
)
82-
83-
# Get random values
84-
animal = random.choice(animals)
85-
colour = random.choice(colours)
86-
number = random.randint(1, 999)
87-
special = random.choice(special_characters)
88-
case_choice = random.choice(["upper_colour", "upper_animal"])
89-
90-
# Pick a random country and language
91-
country = random.choice(list(pycountry.countries)).name
92-
languages = [lang.name for lang in pycountry.languages if hasattr(lang, "name")]
93-
language = random.choice(languages)
94-
95-
# Apply casing
96-
if case_choice == "upper_colour":
1+
#!/usr/bin/env python3
2+
"""
3+
Secure Password Generator – copies password to clipboard, never prints it.
4+
5+
This module generates a strong, memorable password by combining:
6+
- Two random words (animal + colour)
7+
- A random 3‑digit number
8+
- A random special character
9+
10+
It also picks a random country and language (via pycountry) to provide a
11+
memoization hint – these are NOT part of the password.
12+
13+
Security:
14+
- Uses `secrets` module for cryptographically strong randomness.
15+
- Does NOT print the password to the terminal (only a confirmation message).
16+
- Copies the password to the system clipboard using `pyperclip`.
17+
18+
Author: Modified from GGearing / Prince Gangurde
19+
Date: 2026-07-11
20+
"""
21+
22+
import secrets
23+
import string
24+
from typing import Optional
25+
26+
# Optional imports with fallback
27+
try:
28+
import pyperclip # type: ignore
29+
except ImportError:
30+
pyperclip = None
31+
32+
try:
33+
import pycountry
34+
except ImportError:
35+
pycountry = None
36+
37+
38+
# ----------------------------------------------------------------------
39+
# Word lists – extend as needed, but keep them diverse
40+
# ----------------------------------------------------------------------
41+
ANIMALS = (
42+
"ant", "bear", "cat", "dog", "eagle", "fox", "goat", "hawk", "ibis",
43+
"jaguar", "kangaroo", "lion", "monkey", "newt", "owl", "panda", "quail",
44+
"rabbit", "shark", "tiger", "unicorn", "vulture", "wolf", "xerus",
45+
"yak", "zebra"
46+
)
47+
48+
COLOURS = (
49+
"red", "orange", "yellow", "green", "blue", "indigo", "violet",
50+
"purple", "magenta", "cyan", "pink", "brown", "white", "grey", "black"
51+
)
52+
53+
SPECIAL_CHARS = "!@#$%/?<>|&*-=+_"
54+
DIGITS = string.digits
55+
56+
57+
# ----------------------------------------------------------------------
58+
# Core function
59+
# ----------------------------------------------------------------------
60+
def generate_secure_password(
61+
animal_list: tuple = ANIMALS,
62+
colour_list: tuple = COLOURS,
63+
special_chars: str = SPECIAL_CHARS,
64+
num_digits: int = 3
65+
) -> str:
66+
"""
67+
Generate a secure, memorable password using cryptographically strong randomness.
68+
69+
The password is built as: <colour><digits><animal><special>
70+
One of the words (colour or animal) is randomly capitalised.
71+
72+
Args:
73+
animal_list: Tuple of animal names.
74+
colour_list: Tuple of colour names.
75+
special_chars: String of allowed special characters.
76+
num_digits: Number of digits to include (default 3).
77+
78+
Returns:
79+
The generated password string (not printed to console).
80+
81+
Raises:
82+
ValueError: If any word list is empty.
83+
"""
84+
if not animal_list or not colour_list or not special_chars:
85+
raise ValueError("Word lists and special chars must not be empty.")
86+
87+
# Select random elements using secrets (cryptographically secure)
88+
animal = secrets.choice(animal_list)
89+
colour = secrets.choice(colour_list)
90+
91+
# Build a random digit string of given length
92+
digit_str = ''.join(secrets.choice(DIGITS) for _ in range(num_digits))
93+
94+
special = secrets.choice(special_chars)
95+
96+
# Randomly choose which word to uppercase
97+
if secrets.choice([True, False]):
9798
colour = colour.upper()
9899
else:
99100
animal = animal.upper()
100101

101-
# Combine to form password
102-
password = f"{colour}{number}{animal}{special}"
103-
print("Generated Password:", password)
104-
print("Based on Country:", country)
105-
print("Language Hint:", language)
102+
# Assemble the password
103+
password = f"{colour}{digit_str}{animal}{special}"
104+
return password
105+
106+
107+
def get_random_country_and_language() -> tuple[Optional[str], Optional[str]]:
108+
"""
109+
Return a random country name and a random language name (for memorisation hints).
110+
111+
Falls back gracefully if pycountry is not installed.
112+
113+
Returns:
114+
A tuple (country_name, language_name) – either may be None.
115+
"""
116+
country = None
117+
language = None
118+
119+
if pycountry is not None:
120+
try:
121+
# Pick a random country
122+
countries = list(pycountry.countries)
123+
if countries:
124+
country = secrets.choice(countries).name
125+
126+
# Pick a random language (only those with a 'name' attribute)
127+
languages = [lang.name for lang in pycountry.languages if hasattr(lang, "name")]
128+
if languages:
129+
language = secrets.choice(languages)
130+
except Exception:
131+
# Silently ignore any pycountry errors
132+
pass
133+
134+
return country, language
135+
136+
137+
def copy_to_clipboard(text: str) -> bool:
138+
"""
139+
Copy text to the system clipboard using pyperclip.
140+
141+
Args:
142+
text: The string to copy.
143+
144+
Returns:
145+
True if successful, False if pyperclip is not available or fails.
146+
"""
147+
if pyperclip is None:
148+
return False
149+
try:
150+
pyperclip.copy(text)
151+
return True
152+
except Exception:
153+
return False
154+
155+
156+
# ----------------------------------------------------------------------
157+
# Main entry point
158+
# ----------------------------------------------------------------------
159+
def main() -> None:
160+
"""
161+
Generate a password, copy it to clipboard, and show hints.
106162
163+
The password itself is never printed – only a confirmation message.
164+
"""
165+
print("🔐 Generating a secure password...")
107166

108-
# Run it
109-
generate_password()
167+
# Generate the pass

0 commit comments

Comments
 (0)