File fix-home-kimi-source-and-key of Package kimi-utils-ubuntu
#!/usr/bin/bash
# -*- mode: Shell-script; sh_shell: "bash"; -*-
set -euo pipefail
IFS=$'\n\t'
LANG=C
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
source /etc/os-release
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi
KEYRING_DIR="/usr/share/keyrings"
KEYFILE_NAME="home_kimi.gpg"
KEYFILE="${KEYRING_DIR}/${KEYFILE_NAME}"
REPO_URL="http://download.opensuse.org/repositories/home:/kimi:/utils/xUbuntu_${VERSION_ID}"
KEY_URL="${REPO_URL}/Release.key"
SRC_GLOB="/etc/apt/sources.list.d/home:kimi:*.list"
ENABLE_BACKUP=0
# track deleted/rotated files for reporting
DELETED=()
ROTATED=()
die() { printf 'Error: %s\n' "$*" >&2; exit 1; }
log_info() { printf 'Info: %s\n' "$*"; }
log_warn() { printf 'Warning: %s\n' "$*"; }
safe_mv() {
local src=$1 dst=$2
if [[ -e "$src" ]]; then
if mv -v -- "$src" "$dst"; then
ROTATED+=("$src -> $dst")
else
log_warn "mv failed: $src -> $dst"
fi
else
log_info "source not found, skipping mv: $src"
fi
}
safe_rm() {
for f in "$@"; do
[[ -e "$f" ]] || continue
if rm -f -- "$f"; then
DELETED+=("$f")
else
log_warn "rm failed: $f"
fi
done
}
set_key_permissions() {
if [[ -f "$KEYFILE" ]]; then
chmod 0644 "$KEYFILE" || log_warn "chmod failed on $KEYFILE"
chown root:root "$KEYFILE" || log_warn "chown failed on $KEYFILE"
echo "Permissions set on $KEYFILE"
else
log_info "No key file to set permissions on: $KEYFILE"
fi
}
rename_expired_key() {
local file=$1 base ts new
base="${file%~}"
ts=$(date '+.%Y-%m-%d_%H-%M-%S')
new="${base}${ts}~"
echo "Renaming expired $file → $new"
safe_mv "$file" "$new"
}
mkdir -p "$KEYRING_DIR"
shopt -s nullglob
found=()
for d in /etc/apt/trusted.gpg.d /etc/apt/keyrings /usr/share/keyrings; do
found+=("$d"/home_kimi*)
done
shopt -u nullglob
for f in "${found[@]}"; do
[[ -f "$f" && ! -s "$f" ]] && echo "Removing empty $f" && rm -f "$f" && DELETED+=("$f")
done
found=()
shopt -s nullglob
for d in /etc/apt/trusted.gpg.d /etc/apt/keyrings /usr/share/keyrings; do
found+=("$d"/home_kimi*)
done
shopt -u nullglob
if ((${#found[@]})); then
echo "Found ${#found[@]} home_kimi key(s):"
printf ' %s\n' "${found[@]}"
for f in "${found[@]}"; do
if gpg --show-key --with-colons "$f" 2>/dev/null |
awk -F: '$1=="pub"{print $7}' |
while read -r exp; do
[[ -z "$exp" ]] && echo "no-expiry" && exit 0
((exp < $(date +%s))) && echo "expired" && exit 0
done | grep -qE 'expired|no-expiry'; then
rename_expired_key "$f"
fi
done
found=()
shopt -s nullglob
for d in /etc/apt/trusted.gpg.d /etc/apt/keyrings /usr/share/keyrings; do
found+=("$d"/home_kimi*)
done
shopt -u nullglob
for f in "${found[@]}"; do
[[ -e "$f" ]] || continue
src=$(readlink -f "$f")
dest=$(readlink -f "$KEYRING_DIR/${f##*/}")
if [[ "$src" == "$dest" ]]; then
echo "Already in $KEYRING_DIR: $f"
continue
fi
echo "Moving $f → $KEYRING_DIR/"
safe_mv "$f" "$KEYRING_DIR/"
done
else
echo "No existing home_kimi keys found."
fi
shopt -s nullglob
keys=("$KEYRING_DIR"/home_kimi*.gpg)
shopt -u nullglob
if ((${#keys[@]} > 1)); then
newest=""
newest_exp=0
get_expiry() {
gpg --show-key --with-colons "$1" 2>/dev/null |
awk -F: '$1=="pub"{print $7}' | head -n1
}
for k in "${keys[@]}"; do
exp=$(get_expiry "$k")
exp=${exp:-0}
((exp == 0)) && exp=$(stat -c %Y "$k" 2>/dev/null || stat -f %m "$k")
((exp > newest_exp)) && newest_exp=$exp && newest=$k
done
echo "Keeping newest key: ${newest:-<none>}"
if [[ -n "$newest" ]]; then
newest_real=$(readlink -f "$newest" 2>/dev/null || echo "$newest")
keyfile_real=$(readlink -f "$KEYFILE" 2>/dev/null || echo "$KEYFILE")
if [[ "$newest_real" == "$keyfile_real" ]]; then
log_info "Newest key is already the canonical key; no move needed."
else
if [[ -f "$KEYFILE" ]]; then
dest="${KEYFILE}.$(date '+%Y-%m-%d_%H-%M-%S')~"
if mv -v -- "$KEYFILE" "$dest"; then
ROTATED+=("$KEYFILE -> $dest")
else
log_warn "Failed to rotate canonical key $KEYFILE"
fi
else
log_info "Canonical key not present; skipping rotation"
fi
if [[ -f "$newest" ]]; then
if mv -v -- "$newest" "$KEYFILE"; then
ROTATED+=("$newest -> $KEYFILE")
else
log_warn "Failed to move newest $newest to $KEYFILE"
fi
else
log_warn "Expected newest key file missing: $newest"
fi
fi
else
log_warn "No newest key determined"
fi
shopt -s nullglob
keys_after=("$KEYRING_DIR"/home_kimi*.gpg)
shopt -u nullglob
for k in "${keys_after[@]}"; do
if [[ "$k" != "$KEYFILE" ]]; then
safe_rm "$k"
fi
done
fi
need_download=1
if [[ -f "$KEYFILE" ]] && /usr/local/bin/check-apt-key-if-less-than-x-days-to-expiry "$KEYFILE"; then
need_download=0
echo "Existing key still valid."
fi
if ((need_download)); then
echo "Downloading key from $KEY_URL"
if wget -qO- "$KEY_URL" | gpg --dearmor >"$KEYFILE".new; then
if mv -f -- "$KEYFILE".new "$KEYFILE"; then
ROTATED+=("$KEYFILE.new -> $KEYFILE")
else
log_warn "mv failed moving downloaded key into place"
safe_mv "$KEYFILE".new "$KEYFILE"
fi
set_key_permissions
else
rm -f -- "$KEYFILE".new 2>/dev/null || true
die "Failed to download/dearmor key"
fi
else
set_key_permissions
fi
shopt -s nullglob
src_files=($SRC_GLOB)
shopt -u nullglob
if ((${#src_files[@]} == 0)); then
echo "No home:kimi source‑list files found."
exit 0
fi
for f in "${src_files[@]}"; do
((ENABLE_BACKUP)) && cp -a -- "$f" "${f}.orig" && echo "Backup: ${f}.orig"
if grep -q "signed-by=${KEYFILE}" "$f"; then
echo "signed‑by already present in $f"
continue
fi
{
while IFS= read -r line; do
if [[ $line =~ ^[[:space:]]*deb[[:space:]]+ ]]; then
if [[ $line =~ ^([[:space:]]*deb[[:space:]]+)(\[[^]]*\])?[[:space:]]*([^[:space:]]+)([[:space:]].*)$ ]]; then
prefix="${BASH_REMATCH[1]}"
opts="${BASH_REMATCH[2]}"
url="${BASH_REMATCH[3]}"
rest="${BASH_REMATCH[4]}"
if [[ "$url" =~ ^https?://download\.opensuse\.org/repositories/home:/kimi: ]]; then
if [[ -n $opts ]]; then
new_opts="${opts%]}"
new_opts="${new_opts} signed-by=${KEYFILE}]"
else
new_opts="[signed-by=${KEYFILE}]"
fi
echo "${prefix}${new_opts} ${url}${rest}"
continue
fi
fi
fi
echo "$line"
done <"$f"
} >"${f}.tmp" && mv -f "${f}.tmp" "$f"
echo "Updated signed‑by in $f"
done
echo "Cleaning APT cache ..."
apt clean || log_warn "apt clean failed"
rm -rf /var/lib/apt/lists/* || log_warn "rm lists failed"
echo
echo "Key file:"
ls -al "$KEYFILE" 2>/dev/null || echo "(no keyfile found: $KEYFILE)"
echo
echo "Updated source‑list files:"
for f in "${src_files[@]}"; do
echo "---- $f ----"
grep -E '^deb' "$f" || echo "(no deb line found)"
done
# Only print a summary if there were changes
if ((${#ROTATED[@]} + ${#DELETED[@]})); then
echo
echo "Summary of changes:"
if ((${#ROTATED[@]})); then
echo "Rotated/moved files:"
for r in "${ROTATED[@]}"; do echo " $r"; done
fi
if ((${#DELETED[@]})); then
echo "Deleted files:"
for d in "${DELETED[@]}"; do echo " $d"; done
fi
fi
echo "Done."