File list-apt-key-expiry-date of Package kimi-utils-ubuntu

#!/usr/bin/env bash
# List APT key files (.gpg and .asc), show their expiry dates and how many days remain.
# Keys with no expiry are reported as "This key never expires."
set -euo pipefail
IFS=$'\n\t'

# Force C locale so gpg shows predictable English tokens
export LANG=C
export LC_ALL=C

# Options
USE_COLORS=true
for arg in "$@"; do
    case "$arg" in
        --no-colors) USE_COLORS=false ;;
        *) printf 'Unknown option: %s\n' "$arg" >&2; exit 2 ;;
    esac
done

# Colours
if $USE_COLORS && tput setaf 1 &>/dev/null; then
    RED=$(tput setaf 1)
    GREEN=$(tput setaf 2)
    NC=$(tput sgr0)
else
    RED='' GREEN='' NC=''
fi

readonly KEYRING_DIRS=(
    "/etc/apt/trusted.gpg.d"
    "/etc/apt/keyrings"
    "/usr/share/keyrings"
)
readonly COL1_W=8
readonly COL2_W=60

wrap() { fmt -w "$COL2_W" <<< "$1"; }

print_header() {
    printf "%-${COL1_W}s  %s\n" "Key Type" "Description"
    printf "%-${COL1_W}s  %s\n" "--------" "-----------"
}

print_row() {
    local key_type=$1 description=$2 wrapped
    wrapped=$(wrap "$description")
    printf "%-${COL1_W}s  %s\n" "$key_type" "$(head -n1 <<< "$wrapped")"
    tail -n +2 <<< "$wrapped" | sed "s/^/$(printf '%*s' $((COL1_W + 2)) '')/"
}

found_any=false
current_sec=$(date +%s)

echo "Listing APT keys and their expiry dates:"
echo "-----------------------------------------"
echo

print_header
print_row "SC" 'Signing & Certification (can sign other keys).'
echo
print_row "SCEAR" 'Signing, Certification, Encryption, Authentication, Revocation.'
echo

shopt -s nullglob

for KEYRING_DIR in "${KEYRING_DIRS[@]}"; do
    if [[ ! -d "$KEYRING_DIR" ]]; then
        printf 'Keyring directory %s does not exist.\n' "$KEYRING_DIR" >&2
        continue
    fi

    for key_file in "$KEYRING_DIR"/*.{gpg,asc}; do
        if [[ -e "$key_file" ]]; then
            found_any=true
            printf '%b\n' "${GREEN}${key_file}${NC}"

            line_number=0
            # Use gpg --show-key for a human-readable key dump; parse "pub" lines
            while IFS= read -r line; do
                line_number=$((line_number + 1))

                if [[ $line == pub* ]]; then
                    # Colorize expired token if present
                    if [[ $line == *expired* ]] && $USE_COLORS; then
                        line=${line//expired/${RED}expired${NC}}
                    fi
                    printf '%b\n' "$line"

                    # Extract expiry information robustly.
                    expiry_date=''

                    # Check for expiry information
                    if [[ $line =~ ([Ee]xpires|[Ee]xpired)[[:space:]]*:[[:space:]]*([0-9]{4}-[0-9]{2}-[0-9]{2}) ]]; then
                        expiry_date="${BASH_REMATCH[2]}"
                    elif [[ $line =~ [^]]*([Ee]xpires|[Ee]xpired)[^]]*:[[:space:]]*([0-9]{4}-[0-9]{2}-[0-9]{2})[^]]* ]]; then
                        expiry_date="${BASH_REMATCH[2]}"
                    fi

                    if [[ -z $expiry_date ]]; then
                        # Find all YYYY-MM-DD tokens in the line
                        mapfile -t dates < <(grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' <<< "$line" || true)
                        if (( ${#dates[@]} )); then
                            expiry_date="${dates[-1]}"
                            # Check for labels to infer if this date is the expiry date
                            if (( ${#dates[@]} == 1 )) && ! [[ $line =~ ([Ee]xpires|[Ee]xpired|expire) ]]; then
                                expiry_date=''
                            fi
                        fi
                    fi

                    # If still empty => key never expires.
                    if [[ -z $expiry_date ]]; then
                        echo "This key never expires."
                        continue
                    fi

                    # Parse expiry_date robustly; accept YYYYMMDD or YYYY-MM-DD and some time variants.
                    target_sec=''
                    target_sec=$(date -d "$expiry_date" +%s 2>/dev/null || true)
                    if [[ -z $target_sec ]]; then
                        # Try to normalize YYYYMMDD -> YYYY-MM-DD
                        normalized=$(sed 's/[^0-9]//g' <<< "$expiry_date")
                        if [[ $normalized =~ ^([0-9]{4})([0-9]{2})([0-9]{2})$ ]]; then
                            normalized="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]}"
                            target_sec=$(date -d "$normalized" +%s 2>/dev/null || true)
                        fi
                    fi

                    if [[ -z $target_sec ]]; then
                        printf 'Could not parse expiry date: %s\n' "$expiry_date"
                        continue
                    fi

                    diff_sec=$(( target_sec - current_sec ))
                    # Use floor division for negative values too
                    if (( diff_sec >= 0 )); then
                        days_left=$(( (diff_sec + 86399) / 86400 ))  # round up partial days
                    else
                        days_left=$(( diff_sec / 86400 ))  # negative or zero
                    fi

                    if (( diff_sec < 0 )); then
                        overdue_days=$(( (-diff_sec + 86399) / 86400 ))
                        printf 'The date %s is already past (%d day(s) overdue).\n' "$expiry_date" "$overdue_days"
                    elif (( days_left == 0 )); then
                        echo "This key expires today."
                    else
                        printf '%d day(s) left until %s.\n' "$days_left" "$expiry_date"
                    fi

                elif [[ $line_number -eq 2 ]]; then
                    # Print signature/user-id line (trimmed)
                    trimmed="${line#"${line%%[![:space:]]*}"}"
                    trimmed="${trimmed%"${trimmed##*[![:space:]]}"}"
                    printf 'signature: %s\n' "$trimmed"
                fi
            done < <(LANG=C gpg --show-key "$key_file" 2>/dev/null)

            echo "-----------------------------------------"
        fi
    done
done

if ! $found_any; then
    printf 'No .gpg or .asc files found in the specified keyring directories.\n' >&2
    exit 1
fi
			
openSUSE Build Service is sponsored by