diff --git a/usr/lib/linuxmint/mintSources/apt-key.sh b/usr/lib/linuxmint/mintSources/apt-key.sh new file mode 100644 index 0000000..bd5c169 --- /dev/null +++ b/usr/lib/linuxmint/mintSources/apt-key.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# apt-key-clone: A drop-in replacement for apt-key on Debian 13 +# Maps legacy commands to all modern and legacy keyring directories. + +# Strip up to two dashes to normalize (e.g., --list becomes list) +COMMAND="${1#-}" +COMMAND="${COMMAND#-}" + +# Define all possible key locations to scan +SCAN_PATHS=( + "/etc/apt/trusted.gpg" + "/etc/apt/trusted.gpg.d"/* + "/etc/apt/keyrings"/* +# "/usr/share/keyrings"/* +) + +case "$COMMAND" in + list) + for keyfile in "${SCAN_PATHS[@]}"; do + # The [ -f ] check safely skips missing directories like /etc/apt/trusted.gpg + [ -f "$keyfile" ] || continue + if file "$keyfile" | grep -qi -E 'PGP|GPG'; then + echo "--------------------------------------------------------" + echo "Keyring: $keyfile" + echo "--------------------------------------------------------" + gpg --show-keys --with-fingerprint "$keyfile" 2>/dev/null + echo "" + fi + done + ;; + + add) + if [ "$EUID" -ne 0 ]; then echo "ERROR: Root privileges required."; exit 1; fi + FILE="$2" + if [ -z "$FILE" ]; then echo "Usage: apt-key add "; exit 1; fi + + # Capture file or STDIN + TMP_INPUT=$(mktemp) + if [ "$FILE" = "-" ]; then + cat > "$TMP_INPUT" + else + cat "$FILE" > "$TMP_INPUT" + fi + + # Extract the fingerprint to name the file safely + FPR=$(gpg --show-keys --with-colons "$TMP_INPUT" 2>/dev/null | grep "^fpr:" | head -n 1 | cut -d: -f10) + if [ -z "$FPR" ]; then + echo "ERROR: Could not extract a valid GPG key." + rm -f "$TMP_INPUT" + exit 1 + fi + + # We save to trusted.gpg.d so the key is globally trusted, mimicking legacy apt-key behavior + DEST="/etc/apt/trusted.gpg.d/imported-${FPR}.gpg" + + # Import to a temporary keyring, then export cleanly as a dearmored binary + # This handles both ASCII (.asc) and binary (.gpg) files perfectly. + TMP_RING=$(mktemp) + gpg --no-default-keyring --keyring "$TMP_RING" --import "$TMP_INPUT" >/dev/null 2>&1 + gpg --no-default-keyring --keyring "$TMP_RING" --export > "$DEST" + + chmod 644 "$DEST" + rm -f "$TMP_INPUT" "$TMP_RING" "${TMP_RING}~" + echo "OK" + ;; + + del) + if [ "$EUID" -ne 0 ]; then echo "ERROR: Root privileges required."; exit 1; fi + KEYID="$2" + if [ -z "$KEYID" ]; then echo "Usage: apt-key del "; exit 1; fi + + # Remove spaces in case the user passed a full fingerprint + KEYID=$(echo "$KEYID" | tr -d ' ') + FOUND=0 + + for keyfile in "${SCAN_PATHS[@]}"; do + [ -f "$keyfile" ] || continue + + # Check if the keyid exists in this specific keyring file + if gpg --show-keys --with-colons "$keyfile" 2>/dev/null | grep -qF "${KEYID}"; then + KEY_COUNT=$(gpg --show-keys --with-colons "$keyfile" 2>/dev/null | grep -c "^pub:") + + if [ "$KEY_COUNT" -le 1 ]; then + # If it's the only key in the file, delete the file entirely + rm -f "$keyfile" + else + # If it's a multi-key file, delete just the specific key + gpg --no-default-keyring --keyring "$keyfile" --batch --yes --delete-keys "$KEYID" >/dev/null 2>&1 + rm -f "${keyfile}~" # Clean up GPG backup file + fi + FOUND=1 + fi + done + + if [ $FOUND -eq 1 ]; then + echo "OK" + else + echo "Warning: Key not found." + fi + ;; + + *) + echo "Usage: apt-key {add | del | list}" + exit 1 + ;; +esac diff --git a/usr/lib/linuxmint/mintSources/mintSources.py b/usr/lib/linuxmint/mintSources/mintSources.py index 02a3d31..19248a1 100755 --- a/usr/lib/linuxmint/mintSources/mintSources.py +++ b/usr/lib/linuxmint/mintSources/mintSources.py @@ -29,6 +29,7 @@ from io import BytesIO from CountryInformation import CountryInformation +from pathlib import Path import apt_pkg @@ -41,6 +42,7 @@ disable_refresh = False sources_changed = False +script_dir = Path(__file__).parent FLAG_PATH = "/usr/share/iso-flag-png/%s.png" FLAG_SIZE = 16 @@ -340,7 +342,7 @@ def __init__(self, pub): self.uid = "" def delete(self): - subprocess.call(["apt-key", "del", self.pub]) + subprocess.run(["./apt-key.sh", "del", self.pub], cwd=script_dir, capture_output=True, text=True) def get_name(self): return "%s\n %s" % (GLib.markup_escape_text(self.uid), GLib.markup_escape_text(self.pub)) @@ -1293,9 +1295,9 @@ def __init__(self, path, uri): def load_keys(self): self.keys = [] key = None - output = subprocess.getoutput("apt-key list") + output = subprocess.run(["./apt-key.sh", "list"], cwd=script_dir, capture_output=True, text=True) lines = [] - for line in output.split("\n"): + for line in output.stdout.split("\n"): line = line.strip() if line.startswith("/etc/apt"): continue @@ -1332,7 +1334,7 @@ def add_key(self, widget): dialog.set_default_response(Gtk.ResponseType.OK) response = dialog.run() if response == Gtk.ResponseType.OK: - subprocess.call(["apt-key", "add", dialog.get_filename()]) + subprocess.run(["./apt-key.sh", "add", dialog.get_filename()], cwd=script_dir, capture_output=True, text=True) self.load_keys() self.enable_reload_button() dialog.destroy()