first commit
This commit is contained in:
commit
9bc37aeae8
12
Pipfile
Normal file
12
Pipfile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[[source]]
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
name = "pypi"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
pyperclip = "*"
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.12"
|
28
Pipfile.lock
generated
Normal file
28
Pipfile.lock
generated
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "8ceead135ee6991bd49b68802a159c7b7d7cfe2f2218d7a71d7a5d55b1d4cd6e"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.12"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"pyperclip": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==1.8.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {}
|
||||||
|
}
|
146
main.py
Normal file
146
main.py
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
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()
|
Loading…
x
Reference in New Issue
Block a user