139 lines
4.2 KiB
Python
Executable file
139 lines
4.2 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
#
|
|
# Script to handle migration of obsolete /etc/apt/trusted.gpg to split GPG
|
|
# keyrings in /etc/apt/trusted.gpg.d.
|
|
#
|
|
# Author : Benjamin Renard <brenard@zionetrix.net>
|
|
# Date : Fri, 07 Jul 2023 12:26:54 +0200
|
|
# Source : http://gitea.zionetrix.net/bn8/migrate-apt-trusted-keys
|
|
# Licence : GPL v3
|
|
#
|
|
|
|
"""
|
|
Script to handle migration of obsolete /etc/apt/trusted.gpg to split GPG
|
|
keyrings in /etc/apt/trusted.gpg.d.
|
|
"""
|
|
|
|
import argparse
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import traceback
|
|
|
|
# Variables
|
|
raw_output = ""
|
|
|
|
# Args Parsing
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
|
|
parser.add_argument(
|
|
"-p", "--keyring-path", help="APT keyring file path.", type=str, default="/etc/apt/trusted.gpg"
|
|
)
|
|
parser.add_argument(
|
|
"-o", "--output-path", help="Output directory path.", type=str, default="/etc/apt/trusted.gpg.d"
|
|
)
|
|
parser.add_argument(
|
|
"-a", "--auto", help="Migrate all GPG keys, without user interaction.", action="store_true"
|
|
)
|
|
parser.add_argument(
|
|
"-f",
|
|
"--force",
|
|
help="Force mode: overwrite output file if already exists.",
|
|
action="store_true",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
if not os.path.exists(args.keyring_path):
|
|
parser.error(f"APT keyring file {args.keyring_path} not found.")
|
|
|
|
if not os.path.isdir(args.output_path):
|
|
parser.error(f"Output directory {args.output_path} not found (or is not a directory).")
|
|
|
|
# Execute Command
|
|
process = subprocess.run(
|
|
args=["gpg", "--keyring", args.keyring_path, "--list-keys"], capture_output=True, check=True
|
|
)
|
|
if process.returncode > 0:
|
|
print("No fingerprints found!")
|
|
sys.exit()
|
|
raw_output = str(process.stdout.decode("utf-8"))
|
|
|
|
all_keys = []
|
|
current_key = None
|
|
key_id_line = re.compile("^ +([0-9A-F]+)$")
|
|
uid_line = re.compile("^uid +.*<[^@]+@([^>]+)>$")
|
|
for line in raw_output.split("\n")[2:]:
|
|
if not line:
|
|
continue
|
|
|
|
if line.startswith("pub") and current_key:
|
|
all_keys.append(current_key)
|
|
current_key = None
|
|
|
|
if current_key is None:
|
|
current_key = {"lines": [], "id": None, "domain": None}
|
|
|
|
current_key["lines"].append(line)
|
|
m = key_id_line.match(line)
|
|
if m:
|
|
current_key["id"] = m.group(1)
|
|
m = uid_line.match(line)
|
|
if m:
|
|
current_key["domain"] = m.group(1)
|
|
|
|
|
|
if current_key:
|
|
all_keys.append(current_key)
|
|
|
|
for key in all_keys:
|
|
if not args.auto:
|
|
print("\n\n")
|
|
print("\n".join(key["lines"]))
|
|
answer = input("Do you want to migrate this key [Y/n or q to exit]? ")
|
|
answer = answer.strip().lower()
|
|
if answer == 'q':
|
|
sys.exit()
|
|
if answer and answer != "y":
|
|
continue
|
|
|
|
print(f"Migrate key {key['id']}...")
|
|
name = "-".join(key["domain"].lower().split(".")[:-1]) if key["domain"] else key["id"]
|
|
name += ".gpg"
|
|
if not args.auto:
|
|
answer = input(f"Key name [{name}]? ")
|
|
name = answer.strip() if answer else name
|
|
|
|
output_path = os.path.join(args.output_path, name)
|
|
print(f"Export key {key['id']} to {output_path}...")
|
|
try:
|
|
if os.path.exists(output_path):
|
|
if not args.force:
|
|
if args.auto:
|
|
print(f"Outfile '{output_path}' already exists, pass")
|
|
continue
|
|
answer = input(f"Outfile '{output_path}' already exists, overwrite [y/N or q to exit]? ")
|
|
answer = answer.strip().lower()
|
|
if answer == 'q':
|
|
sys.exit()
|
|
if answer != "y":
|
|
continue
|
|
print(f"Remove existing output file '{output_path}'")
|
|
os.remove(output_path)
|
|
|
|
# pylint: disable=consider-using-with
|
|
export_cmd = subprocess.Popen(
|
|
("gpg", "--keyring", args.keyring_path, "--export", key["id"]), stdout=subprocess.PIPE
|
|
)
|
|
output_cmd = subprocess.check_output(
|
|
("gpg", "--dearmour", "-o", output_path), stdin=export_cmd.stdout
|
|
)
|
|
export_cmd.wait()
|
|
print(f"Key {key['id']} exported to {output_path}")
|
|
print()
|
|
except Exception: # pylint: disable=broad-exception-caught
|
|
print(f"Fail to export key {key['id']} to {output_path}")
|
|
traceback.print_exc()
|
|
|
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab
|