Skip to content

Commit 417fb29

Browse files
committed
feat: add clipboard copy feature for most recent password
1 parent 18d231c commit 417fb29

File tree

1 file changed

+62
-6
lines changed

1 file changed

+62
-6
lines changed

src/main.py

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from rich.text import Text
1414
from rich.align import Align
1515
import platform
16+
import pyperclip
1617

1718
# To-do
1819
# Add ability to go back at anytime
@@ -21,12 +22,13 @@
2122

2223
class PasswordManager:
2324
def __init__(self):
24-
self.version = "0.2.0"
25+
self.version = "0.3.0"
2526
self.console = Console()
2627
self.master_hash = None
2728
self.is_authenticated = False
2829
self.fernet = None
2930
self.DB_PATH = self._get_database_path()
31+
self.most_recent_id = ""
3032

3133
self._initialize_database()
3234

@@ -195,7 +197,6 @@ def _get_user_password(self):
195197
while True:
196198
password = self.console.input(f"[yellow]> [/yellow]{prompt}").strip()
197199
if self._check_complexity(password):
198-
print("Password created successfully.")
199200
return password
200201

201202
def _hash_master_password(self, password):
@@ -366,6 +367,7 @@ def _handle_view(self):
366367
decrypted = self._decrypt_password(result[0])
367368
if decrypted:
368369
print(f"Password for entry ID {selected_id}: {decrypted}\n")
370+
self.most_recent_id = selected_id
369371
else:
370372
print("Failed to decrypt password.\n")
371373
else:
@@ -424,6 +426,8 @@ def _handle_add(self):
424426
VALUES (?, ?, ?)''',
425427
(website, username, encrypted_password))
426428

429+
self.most_recent_id = cursor.lastrowid
430+
427431
connection.commit()
428432
print("Password added successfully.\n")
429433

@@ -518,6 +522,7 @@ def _handle_update(self):
518522
continue
519523

520524
print(f"Update for ID {selected_id} complete.\n")
525+
self.most_recent_id = selected_id
521526

522527
else:
523528
print("No password found for that ID.\n")
@@ -566,10 +571,38 @@ def _handle_master(self):
566571
print(f"Failed to re-encrypt password for ID {pw_id}. Data might be inconsistent.")
567572

568573
connection.commit()
574+
569575
except sqlite3.Error as e:
570576
print(f"Database error: {e}\n")
571577

578+
def _handle_copy(self):
579+
"""Copy most recent password to clipboard"""
580+
with sqlite3.connect(self.DB_PATH) as connection:
581+
cursor = connection.cursor()
582+
selected_id = self.most_recent_id
572583

584+
try:
585+
cursor.execute("SELECT id, website, username, created_at FROM passwords ORDER BY created_at DESC")
586+
entries = cursor.fetchall()
587+
588+
if entries:
589+
cursor.execute("SELECT password FROM passwords WHERE id = ?", (selected_id,))
590+
result = cursor.fetchone()
591+
592+
if result:
593+
decrypted = self._decrypt_password(result[0])
594+
if decrypted:
595+
pyperclip.copy(decrypted)
596+
print("Most recent password copied to clipboard.\n")
597+
else:
598+
print("Failed to decrypt password.\n")
599+
else:
600+
print("Failed to copy most recent password.\n")
601+
else:
602+
print("No passwords stored yet.\n")
603+
604+
except sqlite3.Error as e:
605+
print(f"Database error: {e}\n")
573606

574607
def _handle_delete(self):
575608
"""Delete a password from the database"""
@@ -637,23 +670,43 @@ def startup_text(self):
637670
console.print(Align.center(header))
638671
console.print()
639672

640-
self.show_help()
673+
table = Table(show_header=False, show_lines=False, box=None, padding=(0, 2))
674+
table.add_column("Command", style="dim white", width=17)
675+
table.add_column("Description", style="white", width=20)
676+
table.add_column("Shortcut", style="dim white", width=10)
677+
678+
commands = [
679+
("/help", "all commands", "/h"),
680+
("/view", "view passwords", "/v"),
681+
("/add", "add password", "/a"),
682+
("/update", "update password", "/u"),
683+
("/delete", "delete password", "/d"),
684+
("/quit", "quit program", "/q"),
685+
]
686+
687+
for cmd, desc, shortcut in commands:
688+
table.add_row(cmd, desc, shortcut)
689+
690+
print("")
691+
console.print(Align.center(table))
692+
console.print()
641693

642694
def show_help(self):
643695
console = Console()
644696

645697
table = Table(show_header=False, show_lines=False, box=None, padding=(0, 2))
646-
table.add_column("Command", style="dim white", width=17)
698+
table.add_column("Command", style="dim white", width=10)
647699
table.add_column("Description", style="white", width=20)
648700
table.add_column("Shortcut", style="dim white", width=10)
649701

650702
commands = [
651-
("/help", "show help", "/h"),
703+
("/help", "all commands", "/h"),
652704
("/info", "version details", "/i"),
653705
("/view", "view passwords", "/v"),
654706
("/add", "add password", "/a"),
655707
("/update", "update password", "/u"),
656708
("/delete", "delete password", "/d"),
709+
("/copy", "copy to clipboard", "/c"),
657710
("/master", "change master", "/m"),
658711
("/quit", "quit program", "/q"),
659712
]
@@ -662,7 +715,7 @@ def show_help(self):
662715
table.add_row(cmd, desc, shortcut)
663716

664717
print("")
665-
console.print(Align.center(table))
718+
console.print(Align.left(table))
666719
console.print()
667720

668721
def show_info(self):
@@ -718,6 +771,9 @@ def run(self):
718771
elif manager_process == "/delete" or manager_process == "/d":
719772
self._handle_delete()
720773

774+
elif manager_process == "/copy" or manager_process == "/c":
775+
self._handle_copy()
776+
721777
elif manager_process == "/master" or manager_process == "/m":
722778
self._handle_master()
723779

0 commit comments

Comments
 (0)