来自 b 脚本的 PPA GPG 密钥

来自 b 脚本的 PPA GPG 密钥

假设我全新安装了 Ubuntu 21.10,并且想从 Launchpad 添加我喜欢的 PPA。

我知道我可以使用add-apt-repository,但它目前没有将 PPA 密钥添加到/etc/apt/trusted.gpg.d/(或者,一般来说,添加到用户设置的适当目录中,可能/usr/local/share/keyrings/是)。将密钥放入/etc/apt/trusted.gpg.d/将是未来的标准,Ubuntu 21.10 已经支持它。

因此,我想编写一个 bash 脚本,解析用户已从备份复制到的 *.list 文件/etc/apt/sources.list.d,获取密钥并将它们复制到/usr/local/share/keyrings/

如果我知道表单中的 PPA 名称,那么哪种方法是获取密钥文件的巧妙方法ppa:${PPA_NAME}/${PKG_NAME}

我的第一个想法是:

  • 了解${PPA_NAME}${PKG_NAME}转到正确的 launchpad.net 网页
  • 解析网页获取指纹
  • 使用指纹从下载密钥文件https://keyserver.ubuntu.com/
  • 生成正确格式的密钥并将其放在正确的路径下(由signed-by*.list文件中的选项引用)

另一种方法可能是运行静默apt update,捕获可能的 NO_PUBKEY 错误并使用它来检索密钥文件。

有没有不那么复杂的方法来做到这一点?

答案1

我会尽力节省您的一些时间。

为了满足我的个人需要,我创建了特殊的Python 脚本命名srslsud(Ubuntu 和 Debian 的保存/恢复软件列表脚本)。它将保存所有 APT 存储库、它们的 GPG 密钥;Snap、Flatpaks 和 Ubuntu Make 应用程序列表到第一台机器的 JSON 文件中。然后,您可以在第二台机器上使用相同的 JSON 文件恢复此列表。

对于您来说,您可以在旧机器上部分使用其功能:

sudo apt-get install python3 python3-gi python3-apt software-properties-common python3-jsonpickle

cd ~/Downloads
wget https://raw.githubusercontent.com/N0rbert/srslsud/master/srslsud.py
chmod +x srslsud.py
./srslsud.py apt_save
./srslsud.py apt_load

cat apt.sh | grep apt-key

然后解析上述输出以获取实际的密钥。

但为了获得最佳生产力,我建议sudo bash ./apt.sh在新机器上运行相同的 Ubuntu 版本,让它有机会完成所有工作。
即使对于 Ubuntu 22.04 LTS,此方法仍然适用,因此apt-key弃用不是问题。

答案2

这个问题是我自己在 2021 年发布的,但最近我编写了一个 bash 脚本,该脚本以格式的 launchap ppa 的名称作为输入ppa:[ppa_user]/[ppa_name],创建.list文件/etc/apt/sources.list.d并将相关的密钥环放在可配置的文件夹中。

该脚本分为两个文件,一个add-launchpad-ppa.conf和一个add-launchpad-ppa.sh文件。

add-launchpad-ppa.conf文件内容:

# Set English language
LANG=en_US.UTF-8
# Color settings
COLOR_ERROR="\e[1;31m"
COLOR_OFF="\e[0m"
COLOR_OK="\e[1;32m"
COLOR_WARNING="\e[1;33m"
# Definitions
KEY_DIR="/etc/apt/keyrings"
PPA_DIR="/etc/apt/sources.list.d"
KEY_HOST="keyserver.ubuntu.com"
PPA_HOST="launchpadcontent.net"

add-launchpad-ppa.sh文件内容:

#!/bin/bash
#-------------------------------------------------------------------------------
# Script:  add-launchpad-ppa.sh
# Author: Lorenz Keel (AskUbuntu)
# Purpose: Add PGP key in apt keyring
# Usage:   sudo bash <script_dir>/add-launchpad-ppa.sh ppa:[ppa_user]/[ppa_name]
#-------------------------------------------------------------------------------

# Error status variables
STATUS_OK=0
STATUS_ERROR=1

# Execute it as root user
if [ "${USER}" != root ]; then
  echo -e "${COLOR_ERROR}ERROR: must be root! Exiting...${COLOR_OFF}"
  exit "${STATUS_ERROR}"
fi

# Check dependencies
if [ -z "$(command -v curl)" ]; then
  echo -e "${COLOR_ERROR}ERROR: unmet dependencies. Run the command:${COLOR_OFF}"
  echo -e "${COLOR_ERROR}sudo apt install curl${COLOR_OFF}"
  exit "${STATUS_ERROR}"
fi

# Load configuration file
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
SCRIPT_FILE="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
CONF_FILE="${SCRIPT_DIR}/${SCRIPT_FILE/.sh/.conf}"
if [ -f "${CONF_FILE}" ]; then
  # shellcheck source=/dev/null
  source "${CONF_FILE}"
else
  echo "ERROR: missing ${CONF_FILE} file! Exiting..."
  exit "${STATUS_ERROR}"
fi

# Comment code blocks
if [ -n "${BASH}" ]; then
  shopt -s expand_aliases
  alias BEGINCOMMENT="if [ ]; then"
  alias ENDCOMMENT="fi"
fi

# Check input parameters
PPA_PREFIX="$(echo "$1" | cut -d ":" -f 1)"
PPA_USER="$(echo "$1" | cut -d "/" -f 1 | cut -d ":" -f 2)"
PPA_NAME="$(echo "$1" | cut -d "/" -f 2)"
if [ "${PPA_PREFIX}" != "ppa" ] || [ -z "${PPA_USER}" ] || [ -z "${PPA_NAME}" ]; then
  echo "Usage: sudo bash ${SCRIPT_FILE} ppa:[ppa_user]/[ppa_name]"
  exit "${STATUS_ERROR}"
fi

# Create list file
echo -n "→ Creating ${PPA_USER}.list in ${PPA_DIR}... "
echo "deb [arch=amd64 signed-by=${KEY_DIR}/${PPA_USER}-keyring.gpg] https://ppa.${PPA_HOST}/${PPA_USER}/${PPA_NAME}/ubuntu $(lsb_release -sc) main" \
  | tee "${PPA_DIR}/${PPA_USER}".list &> /dev/null
if [ -s "${PPA_DIR}/${PPA_USER}".list ]; then
  echo -e "${COLOR_OK}Done${COLOR_OFF}"
else
  echo -e "${COLOR_ERROR}ERROR: file creation fail${COLOR_OFF}"
  exit "${STATUS_ERROR}"
fi

# Get fingerprint and download the key
echo -n "→ Retrieving fingerprint from https://${PPA_HOST}/~${PPA_USER}/+archive/ubuntu/${PPA_NAME}... "
PPA_FINGER="$(curl -sL "https://launchpad.net/~${PPA_USER}/+archive/ubuntu/${PPA_NAME}" | sed -n -e 's/^.*key_fingerprint//p' | cut -d \" -f 3)"
SCRIPT_NAME="${SCRIPT_FILE%.*}"
USER_NAME="${SUDO_USER:-${USER}}"
TMP_DIR="$(sudo -u "${USER_NAME}" mktemp -d "${TMPDIR:-/tmp/}${SCRIPT_NAME}.XXXX")"
TMP_FILE="tmp-${PPA_USER}"
if curl -sfL "https://${KEY_HOST}/pks/lookup?op=get&search=0x${PPA_FINGER}" -o "${TMP_DIR}/${TMP_FILE}"; then
  echo -e "${COLOR_OK}Done${COLOR_OFF}"
else
  echo -e "${COLOR_ERROR}ERROR: download fail${COLOR_OFF}"
  rm -rf "${TMP_DIR}"
  exit "${STATUS_ERROR}"
fi

# Convert the keyfile
echo -n "→ Converting keyfile... "
# Remove first character (is a blank)
KEY_TYPE="$(file "${TMP_DIR}/${TMP_FILE}" | awk -F ':' '{print substr($2, 2, length($2)-1)}')"
if [ "${KEY_TYPE}" = 'PGP public key block Public-Key (old)' ]; then
  gpg --batch --yes --dearmor --keyring=gnupg-ring "${TMP_DIR}/${TMP_FILE}"
  mv "${TMP_DIR}/${TMP_FILE}.gpg" "${TMP_DIR}/${PPA_USER}-keyring.gpg"
  echo -e "${COLOR_OK}Done${COLOR_OFF}"
elif [ "${KEY_TYPE}" = 'PGP public key block Secret-Key' ]; then
  gpg --batch --yes --no-default-keyring --keyring=gnupg-ring:"${TMP_DIR}/temp-keyring.gpg" --quiet --import "${TMP_DIR}/${TMP_FILE}"
  gpg --batch --yes --no-default-keyring --keyring=gnupg-ring:"${TMP_DIR}/temp-keyring.gpg" --export --output "${TMP_DIR}/${PPA_USER}-keyring.gpg"
  echo -e "${COLOR_OK}Done${COLOR_OFF}"
elif [ "${KEY_TYPE}" = 'PGP/GPG key public ring (v4)' ]; then
  mv "${TMP_DIR}/${TMP_FILE}" "${TMP_DIR}/${PPA_USER}-keyring.gpg"
  echo -e "${COLOR_OK}Done${COLOR_OFF}"
else
  echo -e "${COLOR_ERROR}ERROR: invalid input keyfile format${COLOR_OFF}"
  rm -rf "${TMP_DIR}"
  exit "${STATUS_ERROR}"
fi

# Move keyfile
echo -n "→ Moving keyfile to ${KEY_DIR}... "
# Check if keyfile exist
if [ -f "${TMP_DIR}/${PPA_USER}-keyring.gpg" ]; then
  mkdir -p  "${KEY_DIR}"
  mv "${TMP_DIR}/${PPA_USER}-keyring.gpg" "${KEY_DIR}/${PPA_USER}-keyring.gpg"
  echo -e "${COLOR_OK}Done${COLOR_OFF}"
else
  echo -e "${COLOR_ERROR}ERROR: keyfile does not exist${COLOR_OFF}"
  rm -rf "${TMP_DIR}"
  exit "${STATUS_ERROR}"
fi

# Cleanup
echo -n "→ Cleaning temporary files... "
rm -rf "${TMP_DIR}"
echo -e "${COLOR_OK}Done${COLOR_OFF}"

# Exit
exit "${STATUS_OK}"

该脚本执行以下操作:

  1. 检查脚本是否被调用sudo
  2. 检查是否curl已安装
  3. 必须将源文件add-launchpad-ppa.conf放在同一文件夹add-launchpad-ppa.sh
  4. 获取输入以构建一些内部变量。仅举一个例子,添加 musicbrainz picard 应用程序的输入(https://launchpad.net/~musicbrainz-developers/+archive/ubuntu/stable) 是ppa:musicbrainz-developers/stable(如“将此 PPA 添加到您的系统”段落中所述),因此添加此 ppa 的命令是sudo bash ~/.local/bin/add-launchpad-ppa.sh ppa:musicbrainz-developers/stable(考虑到脚本位于~/.local/bin/)。
  5. 根据以上数据,.list在 中创建文件/etc/apt/sources.list.d。在本例中,文件将是/etc/apt/sources.list.d/musicbrainz-developers.list
  6. 解析 ppa 的 html 页面并下载(在临时文件夹中)ppa 密钥环。
  7. 使用命令将密钥转换为正确的格式gpg。这些转换命令(在if-elif-else语句中)是从 AskUbuntu 中关于apt-key弃用相关主题的几个答案中复制/修改的。
  8. 将密钥移动到.conf文件中配置的文件夹中。在示例中,密钥将是/etc/apt/keyrings/musicbrainz-developers-keyring.gpg
  9. 最后清理临时文件。

换句话说,它是本机命令的简单替换add-apt-repository此脚本还有很大的改进空间,我知道这一点,但就我个人而言,我发现它非常有用。

相关内容