#!/usr/bin/env bash

# Reviewed installer inputs are data, never shell code. Consumers source this
# library, load the data through its parser, and verify each fetched artifact
# before any privileged operation can see it.

declare -gA INSTALLER_PROVENANCE=()

_primary_key_fingerprints() (
    local home
    home="$(mktemp -d)" || exit 1
    chmod 700 "$home"
    trap 'rm -rf -- "$home"' EXIT
    trap 'exit 130' INT
    trap 'exit 143' TERM
    GNUPGHOME="$home" gpg --batch --with-colons --import-options show-only --import "$1" 2>/dev/null \
        | awk -F: '$1 == "pub" { primary = 1; next } primary && $1 == "fpr" { print $10; primary = 0 }'
)

key_fingerprint_matches() {
    local file="$1" expected="$2"
    local -a primary_fingerprints=()
    mapfile -t primary_fingerprints < <(_primary_key_fingerprints "$file")
    [[ ${#primary_fingerprints[@]} -eq 1 && "${primary_fingerprints[0]}" == "$expected" ]]
}

_key_has_one_primary() {
    local -a primary_fingerprints=()
    mapfile -t primary_fingerprints < <(_primary_key_fingerprints "$1")
    [[ ${#primary_fingerprints[@]} -eq 1 ]]
}

verify_detached_signature() {
    local key="$1" signature="$2" content="$3" home
    _key_has_one_primary "$key" || return 1
    (
        home="$(mktemp -d)" || exit 1
        chmod 700 "$home"
        trap 'rm -rf -- "$home"' EXIT
        trap 'exit 130' INT
        trap 'exit 143' TERM
        GNUPGHOME="$home" gpg --batch --quiet --import "$key" >/dev/null 2>&1 \
            && GNUPGHOME="$home" gpg --batch --verify "$signature" "$content" >/dev/null 2>&1
    )
}

download_sha256() {
    local url="$1" expected="$2" max_bytes="$3" destination="$4" actual directory filename

    [[ "$expected" =~ ^[0-9a-f]{64}$ ]] || return 1
    actual="$expected"

    directory="$(dirname -- "$destination")"
    filename="$(basename -- "$destination")"
    (
        local part=""
        trap '[[ -z "$part" ]] || rm -f -- "$part"' EXIT
        trap 'exit 130' INT
        trap 'exit 143' TERM
        [[ "$max_bytes" =~ ^[1-9][0-9]*$ ]] || exit 1
        [[ -n "$destination" && -d "$directory" ]] || exit 1
        umask 077
        part="$(mktemp "$directory/.${filename}.part.XXXXXX")" || exit 1
        curl --fail --location --connect-timeout 10 --max-time 600 \
            --max-filesize "$max_bytes" --output "$part" "$url" \
            || exit 1
        [[ -f "$part" ]] || exit 1
        [[ "$(stat -c %s "$part")" -le "$max_bytes" ]] || exit 1
        [[ "$(sha256sum "$part" | awk '{ print $1 }')" == "$actual" ]] || exit 1
        mv -f -- "$part" "$destination"
    )
}

rpm_signature_matches() {
    local package="$1" key="$2" expected="$3" home db output status

    key_fingerprint_matches "$key" "$expected" || return 1
    home="$(mktemp -d)" || return 1
    chmod 700 "$home"
    db="$home/rpmdb"
    mkdir -m 700 "$db" || {
        rm -rf -- "$home"
        return 1
    }

    rpmkeys --dbpath "$db" --import "$key" >/dev/null 2>&1 \
        && output="$(rpmkeys --dbpath "$db" --checksig --verbose "$package" 2>&1)"
    status=$?
    rm -rf -- "$home"
    (( status == 0 )) || return 1
    grep -Eqi 'OpenPGP.*signature.*: OK' <<<"$output"
}

load_installer_provenance() {
    local file="$1" line name value required
    local -A parsed=() allowed=() required_values=()

    for name in \
        BUN_VERSION BUN_X86_64_URL BUN_X86_64_SHA256 BUN_X86_64_MAX_BYTES \
        BUN_AARCH64_URL BUN_AARCH64_SHA256 BUN_AARCH64_MAX_BYTES \
        NODE_VERSION NODE_X86_64_URL NODE_X86_64_SHA256 NODE_X86_64_MAX_BYTES \
        NODE_AARCH64_URL NODE_AARCH64_SHA256 NODE_AARCH64_MAX_BYTES \
        CODEX_VERSION CODEX_X86_64_URL CODEX_X86_64_SHA256 CODEX_X86_64_MAX_BYTES \
        CODEX_AARCH64_URL CODEX_AARCH64_SHA256 CODEX_AARCH64_MAX_BYTES \
        RUSTDESK_VERSION RUSTDESK_X86_64_URL RUSTDESK_X86_64_SHA256 RUSTDESK_X86_64_MAX_BYTES \
        FEDORA_RELEASE RPMFUSION_FREE_RELEASE_URL RPMFUSION_FREE_RELEASE_MAX_BYTES \
        RPMFUSION_NONFREE_RELEASE_URL RPMFUSION_NONFREE_RELEASE_MAX_BYTES TERRA_BASEURL \
        HYPRLAND_COPR_BASEURL FLATHUB_DESCRIPTOR_URL FLATHUB_DESCRIPTOR_MAX_BYTES \
        CLAUDE_CODE_BASEURL CLAUDE_DESKTOP_BASEURL TERRA_FINGERPRINT CLAUDE_CODE_FINGERPRINT \
        BUN_FINGERPRINT RPMFUSION_FREE_FINGERPRINT RPMFUSION_NONFREE_FINGERPRINT \
        HYPRLAND_COPR_FINGERPRINT FLATHUB_FINGERPRINT CLAUDE_DESKTOP_FINGERPRINT; do
        allowed["$name"]=1
        required_values["$name"]=1
    done

    [[ -r "$file" ]] || return 1
    while IFS= read -r line || [[ -n "$line" ]]; do
        [[ "$line" == *=* && "${line#*=}" != *=* ]] || return 1
        IFS='=' read -r name value <<<"$line"
        [[ -n "${allowed[$name]:-}" && -n "$value" && -z "${parsed[$name]:-}" ]] || return 1
        [[ "$value" != *'$('* && "$value" != *'`'* ]] || return 1
        parsed["$name"]="$value"
    done < "$file"

    for required in "${!required_values[@]}"; do
        [[ -n "${parsed[$required]:-}" ]] || return 1
    done

    INSTALLER_PROVENANCE=()
    for name in "${!parsed[@]}"; do
        INSTALLER_PROVENANCE["$name"]="${parsed[$name]}"
    done
}
