import tkinter as tk from tkinter import ttk import random import json import pyperclip from tkinter import messagebox from tkinter import filedialog # Constants for password characters UPPERCASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' LOWERCASE_CHARS = 'abcdefghijklmnopqrstuvwxyz' DIGITS = '0123456789' SPECIAL_CHARS = '!@#$%^&*()-_=+[]{}|;:",.<>?/~' AMBIGUOUS_CHARS = 'lI1oO0' class PasswordGeneratorApp: def __init__(self, root): self.root = root self.root.title("Password Generator") # Variables for password generation self.include_uppercase = tk.BooleanVar(value=True) self.include_lowercase = tk.BooleanVar(value=True) self.include_digits = tk.BooleanVar(value=True) self.include_special = tk.BooleanVar(value=True) self.exclude_ambiguous = tk.BooleanVar(value=False) self.include_every_category = tk.BooleanVar(value=False) self.password_length = tk.IntVar(value=12) # Configure the main grid self.root.columnconfigure(0, weight=1) # Create and place widgets self.create_widgets() def create_widgets(self): # Password entry self.password_entry = ttk.Entry(self.root, font=('Arial', 14), width=40) self.password_entry.grid(row=0, column=0, padx=10, pady=10, sticky="ew") # Password settings frame settings_frame = ttk.LabelFrame(self.root, text="Settings", padding=10) settings_frame.grid(row=1, column=0, padx=10, pady=10, sticky="ew") # Character type checkboxes ttk.Checkbutton(settings_frame, text="A-Z", variable=self.include_uppercase, command=self.update_password).grid(row=0, column=0, sticky="w") ttk.Checkbutton(settings_frame, text="a-z", variable=self.include_lowercase, command=self.update_password).grid(row=0, column=1, sticky="w") ttk.Checkbutton(settings_frame, text="0-9", variable=self.include_digits, command=self.update_password).grid(row=0, column=2, sticky="w") ttk.Checkbutton(settings_frame, text="Special", variable=self.include_special, command=self.update_password).grid(row=0, column=3, sticky="w") ttk.Checkbutton(settings_frame, text="Exclude look-alike (lI1oO0)", variable=self.exclude_ambiguous, command=self.update_password).grid(row=1, column=0, columnspan=2, sticky="w") ttk.Checkbutton(settings_frame, text="Include every category", variable=self.include_every_category, command=self.update_password).grid(row=1, column=2, columnspan=2, sticky="w") # Password length slider ttk.Label(settings_frame, text="Password Length:").grid(row=2, column=0, columnspan=2, sticky="w") self.length_slider = ttk.Scale(settings_frame, from_=4, to_=32, orient='horizontal', variable=self.password_length, command=lambda event: self.update_password()) self.length_slider.grid(row=2, column=2, columnspan=2, sticky="ew") # Buttons button_frame = ttk.Frame(self.root) button_frame.grid(row=2, column=0, padx=10, pady=10, sticky="ew") button_frame.columnconfigure((0, 1, 2), weight=1) ttk.Button(button_frame, text="Copy", command=self.copy_to_clipboard).grid(row=0, column=0, padx=5, pady=5, sticky="ew") ttk.Button(button_frame, text="Save Settings", command=self.save_settings).grid(row=0, column=1, padx=5, pady=5, sticky="ew") ttk.Button(button_frame, text="Load Settings", command=self.load_settings).grid(row=0, column=2, padx=5, pady=5, sticky="ew") # Initial password generation self.update_password() def generate_password(self): # Collect selected character types chars = '' if self.include_uppercase.get(): chars += UPPERCASE_CHARS if self.include_lowercase.get(): chars += LOWERCASE_CHARS if self.include_digits.get(): chars += DIGITS if self.include_special.get(): chars += SPECIAL_CHARS if self.exclude_ambiguous.get(): chars = ''.join(filter(lambda x: x not in AMBIGUOUS_CHARS, chars)) # Ensure the password includes at least one character from each selected category if required password = '' if self.include_every_category.get(): if self.include_uppercase.get(): password += random.choice(UPPERCASE_CHARS) if self.include_lowercase.get(): password += random.choice(LOWERCASE_CHARS) if self.include_digits.get(): password += random.choice(DIGITS) if self.include_special.get(): password += random.choice(SPECIAL_CHARS) random_chars = [random.choice(chars) for _ in range(self.password_length.get() - len(password))] password += ''.join(random_chars) else: password = ''.join(random.choice(chars) for _ in range(self.password_length.get())) return ''.join(random.sample(password, len(password))) def update_password(self): new_password = self.generate_password() self.password_entry.delete(0, tk.END) self.password_entry.insert(0, new_password) def copy_to_clipboard(self): password = self.password_entry.get() pyperclip.copy(password) messagebox.showinfo("Password Generator", "Password copied to clipboard!") def save_settings(self): settings = { 'include_uppercase': self.include_uppercase.get(), 'include_lowercase': self.include_lowercase.get(), 'include_digits': self.include_digits.get(), 'include_special': self.include_special.get(), 'exclude_ambiguous': self.exclude_ambiguous.get(), 'include_every_category': self.include_every_category.get(), 'password_length': self.password_length.get() } filename = filedialog.asksaveasfilename(defaultextension='.json', filetypes=[("JSON files", "*.json")]) if filename: with open(filename, 'w') as f: json.dump(settings, f) messagebox.showinfo("Password Generator", "Settings saved successfully!") def load_settings(self): filename = filedialog.askopenfilename(filetypes=[("JSON files", "*.json")]) if filename: with open(filename, 'r') as f: settings = json.load(f) self.include_uppercase.set(settings['include_uppercase']) self.include_lowercase.set(settings['include_lowercase']) self.include_digits.set(settings['include_digits']) self.include_special.set(settings['include_special']) self.exclude_ambiguous.set(settings['exclude_ambiguous']) self.include_every_category.set(settings['include_every_category']) self.password_length.set(settings['password_length']) self.update_password() messagebox.showinfo("Password Generator", "Settings loaded successfully!") if __name__ == "__main__": root = tk.Tk() app = PasswordGeneratorApp(root) root.mainloop()