#!/usr/bin/bash

set -euo pipefail

PATH=/usr/sbin:/usr/bin
readonly data_dir=/usr/share/plasma-fingerprint-workaround
readonly payload_config="$data_dir/payload.conf"
readonly program=${0##*/}
temporary_dir=

usage() {
    cat <<EOF
Usage:
  $program status
  $program enable [--rpm PATH] [--force] [--yes]
  $program disable [--yes]

Without --rpm, enable downloads the tested prebuilt package. A local package
must have been built from this tool's KScreenLocker spec. --force permits a
base-version mismatch, including an intentional downgrade.
EOF
}

die() {
    printf 'Error: %s\n' "$*" >&2
    exit 1
}

require_root() {
    (( EUID == 0 )) || die "run this command as root"
}

require_fedora() {
    # shellcheck source=/dev/null
    source /etc/os-release
    [[ ${ID:-} == fedora ]] || die "this workaround only supports Fedora Linux"
}

run_dnf() (
    # The private download's umask must not make DNF's system state root-only.
    umask 022
    dnf5 "$@"
)

cleanup() {
    [[ -n $temporary_dir ]] || return
    rm -f -- "$temporary_dir/kscreenlocker.rpm"
    rmdir -- "$temporary_dir"
}

package_value() {
    local mode=$1
    local format=$2
    local package=$3

    rpm "$mode" --qf "$format" -- "$package"
}

package_base() {
    local mode=$1
    local package=$2
    local provides

    provides=$(rpm "$mode" --provides -- "$package")
    sed -n 's/^plasma-fingerprint-workaround-base = //p' <<<"$provides"
}

is_workaround_package() {
    local mode=$1
    local package=$2
    local provides

    provides=$(rpm "$mode" --provides -- "$package")
    grep -qx 'plasma-fingerprint-workaround-payload = 1' <<<"$provides"
}

is_legacy_workaround() {
    [[ $(installed_value '%{RELEASE}') =~ \.ajp[[:digit:]]+$ ]]
}

is_any_workaround() {
    is_workaround_package -q kscreenlocker || is_legacy_workaround
}

installed_value() {
    package_value -q "$1" kscreenlocker
}

installed_base() {
    local base

    base=$(package_base -q kscreenlocker)
    if [[ -n $base ]]; then
        printf '%s\n' "$base"
    elif is_legacy_workaround; then
        printf '%s-%s\n' \
            "$(installed_value '%{VERSION}')" \
            "$(installed_value '%{RELEASE}' | sed 's/\.ajp[[:digit:]]*$//')"
    else
        installed_value '%{EVR}'
    fi
}

show_status() {
    local enabled=1
    if ! rpm -q kscreenlocker >/dev/null 2>&1; then
        printf 'KScreenLocker is not installed.\n'
        return 1
    fi

    if is_workaround_package -q kscreenlocker; then
        printf 'Fingerprint workaround: enabled\n'
    elif is_legacy_workaround; then
        printf 'Fingerprint workaround: enabled (legacy unmanaged build)\n'
    else
        enabled=0
        printf 'Fingerprint workaround: disabled\n'
    fi
    printf 'Installed package: kscreenlocker-%s\n' \
        "$(installed_value '%{EVR}.%{ARCH}')"
    if (( enabled )); then
        printf 'Based on Fedora package: kscreenlocker-%s\n' "$(installed_base)"
    fi
}

confirm() {
    local answer

    if (( assume_yes )); then
        return
    fi

    printf 'Continue? [y/N] '
    read -r answer || exit 0
    [[ $answer == y || $answer == Y ]] || exit 0
}

load_payload_config() {
    [[ -r $payload_config ]] || die "payload configuration is missing"

    unset payload_url payload_sha256
    # This root-owned file is installed by the controller RPM.
    # shellcheck source=/dev/null
    source "$payload_config"

    [[ ${payload_url:-} == https://* ]] || die "invalid payload URL"
    [[ ${payload_sha256:-} =~ ^[[:xdigit:]]{64}$ ]] ||
        die "invalid payload checksum"
}

validate_candidate() {
    local candidate=$1
    local name arch candidate_evr candidate_base current_base current_evr

    rpm -K --nosignature "$candidate" >/dev/null || die "the RPM is corrupt"

    name=$(package_value -qp '%{NAME}' "$candidate")
    [[ $name == kscreenlocker ]] ||
        die "expected a kscreenlocker RPM, got $name"

    is_workaround_package -qp "$candidate" ||
        die "the RPM was not built from this workaround's KScreenLocker spec"

    arch=$(package_value -qp '%{ARCH}' "$candidate")
    [[ $arch == "$(installed_value '%{ARCH}')" ]] ||
        die "RPM architecture $arch does not match installed architecture $(installed_value '%{ARCH}')"

    candidate_base=$(package_base -qp "$candidate")
    [[ -n $candidate_base ]] || die "the RPM has no base-version marker"

    candidate_evr=$(package_value -qp '%{EVR}' "$candidate")
    current_base=$(installed_base)
    current_evr=$(installed_value '%{EVR}')

    printf 'Installed: kscreenlocker-%s\n' "$current_evr"
    printf 'Candidate: kscreenlocker-%s (based on %s)\n' \
        "$candidate_evr" "$candidate_base"

    if [[ $candidate_base != "$current_base" ]]; then
        if (( ! force )); then
            die "candidate base $candidate_base does not match installed base $current_base; use --force to allow the version change"
        fi
        printf 'Warning: forcing a KScreenLocker base-version change.\n' >&2
    fi
}

enable_workaround() {
    local rpm_path='' candidate
    local -a dnf_args

    force=0
    assume_yes=0
    while (( $# )); do
        case $1 in
            --rpm)
                (( $# >= 2 )) || die "--rpm requires a path"
                rpm_path=$2
                shift 2
                ;;
            --force)
                force=1
                shift
                ;;
            --yes)
                assume_yes=1
                shift
                ;;
            *)
                die "unknown enable option: $1"
                ;;
        esac
    done

    require_root
    require_fedora
    rpm -q kscreenlocker >/dev/null 2>&1 || die "KScreenLocker is not installed"

    umask 077
    temporary_dir=$(mktemp -d /var/tmp/plasma-fingerprint-workaround.XXXXXX)
    trap cleanup EXIT
    candidate="$temporary_dir/kscreenlocker.rpm"

    if [[ -n $rpm_path ]]; then
        [[ -f $rpm_path ]] || die "RPM not found: $rpm_path"
        install -m 0600 -- "$rpm_path" "$candidate"
    else
        load_payload_config
        printf 'Downloading the tested KScreenLocker build...\n'
        curl --fail --location --show-error --silent \
            --proto '=https' --proto-redir '=https' \
            --output "$candidate" "$payload_url"
        printf '%s  %s\n' "$payload_sha256" "$candidate" |
            sha256sum --check --status - || die "downloaded RPM checksum does not match"
    fi

    validate_candidate "$candidate"
    printf '\nThis replaces Fedora\x27s security-sensitive KScreenLocker package.\n'
    confirm

    dnf_args=(install --assumeyes)
    (( force )) && dnf_args+=(--allow-downgrade)
    run_dnf "${dnf_args[@]}" "$candidate"

    is_workaround_package -q kscreenlocker ||
        die "DNF completed without enabling the workaround"
    printf 'Fingerprint workaround enabled. Reboot before testing it.\n'
}

disable_workaround() {
    assume_yes=0
    while (( $# )); do
        case $1 in
            --yes)
                assume_yes=1
                shift
                ;;
            *)
                die "unknown disable option: $1"
                ;;
        esac
    done

    require_root
    require_fedora
    if ! is_any_workaround; then
        printf 'Fingerprint workaround is already disabled.\n'
        return
    fi

    printf 'This will replace the workaround with Fedora\x27s current KScreenLocker package.\n'
    confirm

    run_dnf \
        --repo=fedora,updates \
        --refresh \
        distro-sync \
        --assumeyes \
        kscreenlocker

    if is_any_workaround; then
        die "no suitable Fedora KScreenLocker package was installed"
    fi
    printf 'Fingerprint workaround disabled. Reboot before testing the lock screen.\n'
}

command=${1:-}
[[ -n $command ]] || {
    usage
    exit 2
}
shift

case $command in
    status)
        (( $# == 0 )) || die "status takes no options"
        show_status
        ;;
    enable)
        enable_workaround "$@"
        ;;
    disable)
        disable_workaround "$@"
        ;;
    -h|--help|help)
        usage
        ;;
    *)
        usage >&2
        exit 2
        ;;
esac
