Files
Py-Backup/pyimage_ui/header_frame.py
Désiré Werner Menrath f11f30ba74 refactor(core): Implement new backup directory structure
Refactor the core backup and encryption logic to use a new, consistent directory structure. This new structure separates encrypted and unencrypted backups and centralizes metadata, making the system more robust and easier to manage.

Key changes:
- Implemented a new directory scheme:
  /pybackup/
  ├── unencrypted/{system,user}/<source>/
  ├── encrypted/{system,user}/<source>/  (mount point)
  ├── metadata/
  └── pybackup_encrypted.luks
- Reworked path generation logic in BackupManager and EncryptionManager to support the new structure.
- All backup, restore, and listing operations now correctly resolve paths based on the new scheme.

This also includes several bug fixes identified during the refactoring:
- fix(backup): Correctly quote rsync paths for user backups to prevent "No such file or directory" errors.
- fix(encryption): Change key lookup order to Keyring -> Keyfile -> Password Prompt, as requested.
- fix(ui): Remove eager auto-mount on startup to prevent unexpected password prompts. The app now only mounts when required by a user action.
2025-09-09 01:27:29 +02:00

120 lines
4.6 KiB
Python

import tkinter as tk
import os
from core.pbp_app_config import Msg
from shared_libs.common_tools import IconManager
from shared_libs.logger import app_logger
class HeaderFrame(tk.Frame):
def __init__(self, container, image_manager, encryption_manager, app, **kwargs):
super().__init__(container, bg="#455A64", **kwargs)
self.image_manager = image_manager
self.encryption_manager = encryption_manager
self.app = app
# Configure grid weights for internal layout
self.columnconfigure(1, weight=1) # Make the middle column expand
self.rowconfigure(0, weight=1) # Make the top row expand
# Left side: Icon and Main Title/Subtitle
left_frame = tk.Frame(self, bg="#455A64")
left_frame.grid(row=0, column=0, rowspan=2, sticky="nsew")
left_frame.columnconfigure(0, weight=1)
left_frame.rowconfigure(0, weight=1)
icon_label = tk.Label(
left_frame,
image=self.image_manager.get_icon(
"backup_extralarge"), # Using a generic backup icon
bg="#455A64",
)
icon_label.grid(row=0, column=0, sticky="e", padx=10, pady=5)
title_label = tk.Label(
self,
text=Msg.STR["header_title"],
font=("Helvetica", 16, "bold"),
fg="#ffffff",
bg="#455A64",
)
title_label.grid(row=0, column=1, sticky="w",
padx=(5, 20), pady=(15, 5))
subtitle_label = tk.Label(
self,
text=Msg.STR["header_subtitle"],
font=("Helvetica", 10),
fg="#bdc3c7",
bg="#455A64",
)
subtitle_label.grid(row=1, column=1, sticky="w",
padx=(5, 20), pady=(0, 10))
# Right side: Keyring status
right_frame = tk.Frame(self, bg="#455A64")
right_frame.grid(row=0, column=2, rowspan=2, sticky="nsew")
right_frame.columnconfigure(0, weight=1)
right_frame.rowconfigure(0, weight=1)
self.keyring_status_label = tk.Label(
right_frame,
text="",
font=("Helvetica", 10, "bold"),
bg="#455A64",
)
self.keyring_status_label.grid(row=0, column=0, sticky="ne", padx=(10, 10), pady=(10, 0))
self.refresh_status()
def refresh_status(self):
"""Checks the keyring status based on the current destination and updates the label."""
app_logger.log("HeaderFrame: Refreshing status...")
dest_path = self.app.destination_path
app_logger.log(f"HeaderFrame: Destination path is '{dest_path}'")
if not dest_path or not self.encryption_manager.is_encrypted(dest_path):
app_logger.log("HeaderFrame: No destination path or not encrypted. Clearing status.")
self.keyring_status_label.config(text="") # Clear status if not encrypted
return
app_logger.log("HeaderFrame: Destination is encrypted.")
username = os.path.basename(dest_path.rstrip('/'))
app_logger.log(f"HeaderFrame: Username is '{username}'")
is_mounted = self.encryption_manager.is_mounted(dest_path)
app_logger.log(f"HeaderFrame: Is mounted? {is_mounted}")
if is_mounted:
status_text = "Key: In Use"
auth_method = getattr(self.encryption_manager, 'auth_method', None)
if auth_method == 'keyring':
status_text += " (Keyring)"
elif auth_method == 'keyfile':
status_text += " (Keyfile)"
self.keyring_status_label.config(
text=status_text,
fg="#2E8B57" # SeaGreen
)
else:
key_in_keyring = self.encryption_manager.is_key_in_keyring(username)
app_logger.log(f"HeaderFrame: Key in keyring? {key_in_keyring}")
key_file_exists = os.path.exists(self.encryption_manager.get_key_file_path(dest_path))
app_logger.log(f"HeaderFrame: Key file exists? {key_file_exists}")
if key_in_keyring:
self.keyring_status_label.config(
text="Key: Available (Keyring)",
fg="#FFD700" # Gold
)
elif key_file_exists:
self.keyring_status_label.config(
text="Key: Available (Keyfile)",
fg="#FFD700" # Gold
)
else:
self.keyring_status_label.config(
text="Key: Not Available",
fg="#A9A9A9" # DarkGray
)
app_logger.log("HeaderFrame: Status refresh complete.")