diff --git a/KeePassDiff/components/entry_modal.py b/KeePassDiff/components/entry_modal.py index 9c21d2a..721760b 100644 --- a/KeePassDiff/components/entry_modal.py +++ b/KeePassDiff/components/entry_modal.py @@ -1,9 +1,12 @@ -from typing import Dict, Optional - import streamlit as st +from KeePassDiff.utils.database import EntryDetails + -def show_entry_details(entry_details: Optional[Dict] = None, key: str = None): +def show_entry_details( + entry_details: EntryDetails | None = None, + key: str | None = None, +): if entry_details: st.markdown("### Entry Details") st.markdown(f"**Title:** {entry_details['title']}") @@ -12,11 +15,12 @@ def show_entry_details(entry_details: Optional[Dict] = None, key: str = None): st.markdown(f"**URL:** {entry_details['url']}") st.markdown("**Notes:**") st.text_area( - "", + "notes", + label_visibility="collapsed", value=entry_details["notes"], height=100, disabled=True, - key=f"notes_{key}" if key else None, + key=f"notes_{key}", ) st.markdown(f"**Created:** {entry_details['created']}") st.markdown(f"**Modified:** {entry_details['modified']}") diff --git a/KeePassDiff/utils/comparison.py b/KeePassDiff/utils/comparison.py index 16abcea..3e3826b 100644 --- a/KeePassDiff/utils/comparison.py +++ b/KeePassDiff/utils/comparison.py @@ -1,9 +1,9 @@ -from typing import Dict, Set +from typing import Dict, Set, List def compare_databases( db1_data: Dict[str, Set[str]], db2_data: Dict[str, Set[str]] -) -> Dict: +) -> Dict[str, List[str]]: return { "entries_only_in_db1": sorted(db1_data["entries"] - db2_data["entries"]), "entries_only_in_db2": sorted(db2_data["entries"] - db1_data["entries"]), diff --git a/KeePassDiff/utils/database.py b/KeePassDiff/utils/database.py index 2d47afb..76c508a 100644 --- a/KeePassDiff/utils/database.py +++ b/KeePassDiff/utils/database.py @@ -1,7 +1,19 @@ +import datetime import tempfile -from typing import Dict, Optional, Set, Tuple +from typing import TypedDict, Dict, Optional, Set, Tuple -from pykeepass import PyKeePass +from pykeepass import Group, PyKeePass + + +class EntryDetails(TypedDict): + title: str | None + username: str | None + password: str | None + url: str | None + notes: str | None + created: datetime.datetime | None + modified: datetime.datetime | None + path: str def save_temp_database(db_file, keyfile=None) -> Tuple[str, Optional[str]]: @@ -42,42 +54,45 @@ def get_entries_set(kp: PyKeePass) -> Dict[str, Set[str]]: entries = set() groups = set() - for entry in kp.entries: - # Ensure all elements are strings and not None - entry_path = "/".join( - [str(g) for g in entry.path[:-1] if g is not None] - + [str(entry.title) if entry.title is not None else ""] - ) - entries.add(entry_path) - - for group in kp.groups: - if group != "Root": - group_path = "/".join([str(g) for g in group.path if g is not None]) - groups.add(group_path) + if kp.entries: + for entry in kp.entries: + # Ensure all elements are strings and not None + entry_path = "/".join( + [str(g) for g in entry.path[:-1] if g is not None] + + [str(entry.title) if entry.title is not None else ""] + ) + entries.add(entry_path) + + if kp.groups: + for group in kp.groups: + if group != "Root": + group_path = "/".join([str(g) for g in group.path if g is not None]) + groups.add(group_path) return {"entries": entries, "groups": groups} -def get_entry_details(kp: PyKeePass, entry_path: str) -> Dict: +def get_entry_details(kp: PyKeePass, entry_path: str) -> EntryDetails | None: path_parts = entry_path.split("/") title = path_parts[-1] group_path = path_parts[:-1] - for entry in kp.entries: - if ( - entry.title == title - and [str(g) for g in entry.path[:-1] if g is not None] == group_path - ): - return { - "title": entry.title, - "username": entry.username, - "password": entry.password, - "url": entry.url, - "notes": entry.notes, - "created": entry.ctime, - "modified": entry.mtime, - "path": "/".join(group_path), - } + if kp.entries: + for entry in kp.entries: + if ( + entry.title == title + and [str(g) for g in entry.path[:-1] if g is not None] == group_path + ): + return { + "title": entry.title, + "username": entry.username, + "password": entry.password, + "url": entry.url, + "notes": entry.notes, + "created": entry.ctime, + "modified": entry.mtime, + "path": "/".join(group_path), + } return None @@ -87,17 +102,24 @@ def merge_entry(source_kp: PyKeePass, target_kp: PyKeePass, entry_path: str) -> group_path = path_parts[:-1] source_entry = None - for entry in source_kp.entries: - if entry.title == title and [g for g in entry.path[:-1]] == group_path: - source_entry = entry - break + if source_kp.entries: + for entry in source_kp.entries: + if entry.title == title and [g for g in entry.path[:-1]] == group_path: + source_entry = entry + break if not source_entry: return False current_group = target_kp.root_group + + if not isinstance(current_group, Group): + return False + for group_name in group_path: - next_group = next((g for g in current_group.subgroups if g == group_name), None) + next_group = next( + (g for g in current_group.subgroups if g.name == group_name), None + ) if not next_group: next_group = target_kp.add_group(current_group, group_name) current_group = next_group