Skip to content

Commit 06852e9

Browse files
Merge pull request #2941 from prashantgohel321/add-password-manager
Added Password Manager (Tkinter) GUI Project
2 parents b161cba + feebb9b commit 06852e9

File tree

7 files changed

+308
-0
lines changed

7 files changed

+308
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import json
2+
3+
new_data = {
4+
website_input.get():{
5+
"email": email_input.get(),
6+
"password": passw_input.get()
7+
}
8+
}
9+
10+
try:
11+
with open("data.json", "r") as data_file:
12+
data = json.load(data_file)
13+
except FileNotFoundError:
14+
with open("data.json", "w") as data_file:
15+
pass
16+
else:
17+
with open("data.json", "w") as data_file:
18+
json.dump(new_data, data_file, indent = 4)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# My Personal Password Manager
2+
3+
Hello there! Welcome to my Password Manager project. I created this application to provide a simple and secure way **to manage all my website login credentials in one place**. It's a desktop application **built with Python**, and I've focused on making it both functional and easy on the eyes.
4+
5+
---
6+
7+
## What It Can Do
8+
9+
- **Generate Strong Passwords**: One click = secure, random passwords (auto-copied to clipboard!).
10+
11+
- **Save Credentials**: Store site name, email/username, and password safely.
12+
13+
- **Quick Search**: Instantly find saved logins by website name.
14+
15+
- **View All Passwords**: Unlock all saved entries with your master password — neatly organized in a table.
16+
17+
- **One-Click Copy**: Copy email or password directly from the list for quick logins.
18+
19+
---
20+
21+
## How I Built It
22+
23+
- **Python**: Powers the core logic behind the app.
24+
25+
- **Tkinter**: Handles the clean and simple user interface.
26+
27+
- **ttkbootstrap**: Adds a modern, professional theme to the UI.
28+
29+
- **JSON**: Stores all password data securely in a local data.json file.
30+
31+
---
32+
33+
## How to Get Started
34+
35+
1. Install Python 3 on your system.
36+
37+
2. Download all project files (main.py, logo.png, requirements.txt).
38+
39+
3. Open Terminal/CMD, navigate to the project folder, and run:
40+
```python
41+
pip install -r requirements.txt
42+
```
43+
44+
4. Start the app with:
45+
```python
46+
python main.py
47+
```
48+
49+
5. Enjoy!
50+
51+
---
52+
53+
## Screenshots
54+
55+
<table border = 2 width = 800>
56+
<tr>
57+
<td width = 500>Main Window where from where you can add credentials</td>
58+
<td width = 500><img src="screenshots/main_window.png" alt="Main Window" width="400"></td>
59+
</tr>
60+
<tr>
61+
<td>Second window — where you can see all your saved passwords (but hey, you’ll need a password to see your passwords 😏).
62+
</td>
63+
<td><img src="screenshots/view_window.png" alt="Main Window" width="400"></td>
64+
</tr>
65+
</table>
66+
67+
68+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"Amazon": {
3+
"email": "prashant123Amazon@gmail.com",
4+
"password": "1mD%#Z555rF$&2aRpI"
5+
},
6+
"Facebook": {
7+
"email": "prashant123Facebook@gmail.com",
8+
"password": "qQ6#H7o&)i8S!3sO)c4"
9+
},
10+
"Flipkart": {
11+
"email": "prashant123Flipkart@gmail.com",
12+
"password": "1!+7NqmUZbN18K(3A+"
13+
}
14+
}

Password Manager Using Tkinter/data.txt

Whitespace-only changes.
13.8 KB
Loading
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
import tkinter as tk
2+
from tkinter import messagebox, simpledialog
3+
import ttkbootstrap as ttk
4+
from ttkbootstrap.constants import *
5+
import pyperclip
6+
import json
7+
from random import choice, randint, shuffle
8+
9+
# ---------------------------- CONSTANTS ------------------------------- #
10+
FONT_NAME = "Helvetica"
11+
# IMP: this is not a secure way to store a master password.
12+
# in a real application, this should be changed and stored securely (e.g., hashed and salted).
13+
MASTER_PASSWORD = "password123"
14+
15+
# ---------------------------- PASSWORD GENERATOR ------------------------------- #
16+
def generate_password():
17+
"""generates a random strong password and copies it to clipboard."""
18+
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
19+
numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
20+
symbols = ['!', '#', '$', '%', '&', '(', ')', '*', '+']
21+
22+
password_letters = [choice(letters) for _ in range(randint(8, 10))]
23+
password_symbols = [choice(symbols) for _ in range(randint(2, 4))]
24+
password_numbers = [choice(numbers) for _ in range(randint(2, 4))]
25+
26+
password_list = password_letters + password_symbols + password_numbers
27+
shuffle(password_list)
28+
29+
password = "".join(password_list)
30+
password_entry.delete(0, tk.END)
31+
password_entry.insert(0, password)
32+
pyperclip.copy(password)
33+
messagebox.showinfo(title="Password Generated", message="Password copied to clipboard!")
34+
35+
# ---------------------------- SAVE PASSWORD ------------------------------- #
36+
def save():
37+
"""saves the website, email, and password to a JSON file."""
38+
website = website_entry.get()
39+
email = email_entry.get()
40+
password = password_entry.get()
41+
new_data = {
42+
website: {
43+
"email": email,
44+
"password": password,
45+
}
46+
}
47+
48+
if not website or not password:
49+
messagebox.showerror(title="Oops", message="Please don't leave any fields empty!")
50+
return
51+
52+
is_ok = messagebox.askokcancel(title=website, message=f"These are the details entered: \nEmail: {email} "
53+
f"\nPassword: {password} \nIs it ok to save?")
54+
if is_ok:
55+
try:
56+
with open("data.json", "r") as data_file:
57+
data = json.load(data_file)
58+
except (FileNotFoundError, json.JSONDecodeError):
59+
data = {}
60+
61+
data.update(new_data)
62+
63+
with open("data.json", "w") as data_file:
64+
json.dump(data, data_file, indent=4)
65+
66+
website_entry.delete(0, tk.END)
67+
password_entry.delete(0, tk.END)
68+
69+
# ---------------------------- FIND PASSWORD ------------------------------- #
70+
def find_password():
71+
"""finds and displays password for a given website."""
72+
website = website_entry.get()
73+
try:
74+
with open("data.json", "r") as data_file:
75+
data = json.load(data_file)
76+
except (FileNotFoundError, json.JSONDecodeError):
77+
messagebox.showerror(title="Error", message="No Data File Found.")
78+
return
79+
80+
if website in data:
81+
email = data[website]["email"]
82+
password = data[website]["password"]
83+
messagebox.showinfo(title=website, message=f"Email: {email}\nPassword: {password}")
84+
pyperclip.copy(password)
85+
messagebox.showinfo(title="Copied", message="Password for {} copied to clipboard.".format(website))
86+
else:
87+
messagebox.showerror(title="Error", message=f"No details for {website} exists.")
88+
89+
# ---------------------------- VIEW ALL PASSWORDS ------------------------------- #
90+
def view_all_passwords():
91+
"""prompts for master password and displays all saved passwords if correct."""
92+
password = simpledialog.askstring("Master Password", "Please enter the master password:", show='*')
93+
94+
if password == MASTER_PASSWORD:
95+
show_passwords_window()
96+
elif password is not None: # avoids error message if user clicks cancel
97+
messagebox.showerror("Incorrect Password", "The master password you entered is incorrect.")
98+
99+
def show_passwords_window():
100+
"""creates a new window to display all passwords in a table."""
101+
all_passwords_window = tk.Toplevel(window)
102+
all_passwords_window.title("All Saved Passwords")
103+
all_passwords_window.config(padx=20, pady=20)
104+
105+
# a frame for the treeview and scrollbar
106+
tree_frame = ttk.Frame(all_passwords_window)
107+
tree_frame.grid(row=0, column=0, columnspan=2, sticky='nsew')
108+
109+
# a Treeview (table)
110+
cols = ('Website', 'Email', 'Password')
111+
tree = ttk.Treeview(tree_frame, columns=cols, show='headings')
112+
113+
# column headings and widths
114+
tree.heading('Website', text='Website')
115+
tree.column('Website', width=150)
116+
tree.heading('Email', text='Email/Username')
117+
tree.column('Email', width=200)
118+
tree.heading('Password', text='Password')
119+
tree.column('Password', width=200)
120+
121+
tree.grid(row=0, column=0, sticky='nsew')
122+
123+
# a scrollbar
124+
scrollbar = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL, command=tree.yview)
125+
tree.configure(yscroll=scrollbar.set)
126+
scrollbar.grid(row=0, column=1, sticky='ns')
127+
128+
# load data from JSON file
129+
try:
130+
with open("data.json", "r") as data_file:
131+
data = json.load(data_file)
132+
133+
# insert data into the treeview
134+
for website, details in data.items():
135+
tree.insert("", "end", values=(website, details['email'], details['password']))
136+
137+
except (FileNotFoundError, json.JSONDecodeError):
138+
# if file not found or empty, it will just show an empty table
139+
pass
140+
141+
def copy_selected_info(column_index, info_type):
142+
"""copies the email or password of the selected row."""
143+
selected_item = tree.focus()
144+
if not selected_item:
145+
messagebox.showwarning("No Selection", "Please select a row from the table first.", parent=all_passwords_window)
146+
return
147+
148+
item_values = tree.item(selected_item, 'values')
149+
info_to_copy = item_values[column_index]
150+
pyperclip.copy(info_to_copy)
151+
messagebox.showinfo("Copied!", f"The {info_type.lower()} for '{item_values[0]}' has been copied to your clipboard.", parent=all_passwords_window)
152+
153+
# a frame for the buttons
154+
button_frame = ttk.Frame(all_passwords_window)
155+
button_frame.grid(row=1, column=0, columnspan=2, pady=(10,0))
156+
157+
copy_email_button = ttk.Button(button_frame, text="Copy Email", style="success.TButton", command=lambda: copy_selected_info(1, "Email"))
158+
copy_email_button.pack(side=tk.LEFT, padx=5)
159+
160+
copy_password_button = ttk.Button(button_frame, text="Copy Password", style="success.TButton", command=lambda: copy_selected_info(2, "Password"))
161+
copy_password_button.pack(side=tk.LEFT, padx=5)
162+
163+
all_passwords_window.grab_set() # makes window modal
164+
165+
# ---------------------------- UI SETUP ------------------------------- #
166+
window = ttk.Window(themename="superhero")
167+
window.title("Password Manager")
168+
window.config(padx=50, pady=50)
169+
170+
# logo
171+
canvas = tk.Canvas(width=200, height=200, highlightthickness=0)
172+
logo_img = tk.PhotoImage(file="logo.png")
173+
canvas.create_image(100, 100, image=logo_img)
174+
canvas.grid(row=0, column=1, pady=(0, 20))
175+
176+
# labels
177+
website_label = ttk.Label(text="Website:", font=(FONT_NAME, 12))
178+
website_label.grid(row=1, column=0, sticky="W")
179+
email_label = ttk.Label(text="Email/Username:", font=(FONT_NAME, 12))
180+
email_label.grid(row=2, column=0, sticky="W")
181+
password_label = ttk.Label(text="Password:", font=(FONT_NAME, 12))
182+
password_label.grid(row=3, column=0, sticky="W")
183+
184+
# entries
185+
website_entry = ttk.Entry(width=32)
186+
website_entry.grid(row=1, column=1, pady=5, sticky="EW")
187+
website_entry.focus()
188+
email_entry = ttk.Entry(width=50)
189+
email_entry.grid(row=2, column=1, columnspan=2, pady=5, sticky="EW")
190+
email_entry.insert(0, "example@email.com")
191+
password_entry = ttk.Entry(width=32)
192+
password_entry.grid(row=3, column=1, pady=5, sticky="EW")
193+
194+
# buttons
195+
search_button = ttk.Button(text="Search", width=14, command=find_password, style="info.TButton")
196+
search_button.grid(row=1, column=2, sticky="EW", padx=(5,0))
197+
generate_password_button = ttk.Button(text="Generate Password", command=generate_password, style="success.TButton")
198+
generate_password_button.grid(row=3, column=2, sticky="EW", padx=(5,0))
199+
add_button = ttk.Button(text="Add", width=43, command=save, style="primary.TButton")
200+
add_button.grid(row=4, column=1, columnspan=2, pady=(10,0), sticky="EW")
201+
202+
view_all_button = ttk.Button(text="View All Passwords", command=view_all_passwords, style="secondary.TButton")
203+
view_all_button.grid(row=5, column=1, columnspan=2, pady=(10,0), sticky="EW")
204+
205+
206+
window.mainloop()
207+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ttkbootstrap

0 commit comments

Comments
 (0)