#!/bin/bash

## Copyright (C) 2026 - 2026 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## AI-Assisted

## Download a published image plus its reproducibility metadata into a local
## directory. The image is untrusted, 'dm-reproducible-verify' handles
## verification.

## No minimum-version check: images predating reproducible-build support are
## non-reproducible, but someone can still investigate a historical image if
## they want to.

set -o errexit
set -o nounset
set -o pipefail
set -o errtrace
shopt -s inherit_errexit
shopt -s shift_verbose
export LC_ALL=C

true "INFO: Currently running script: ${BASH_SOURCE[0]} $*"

MYDIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" && pwd )"

## style-ok: no-has
## Self-contained downloader (runs outside a build tree); probes for scurl/curl
## with 'command -v'.

me="${0##*/}"

print_usage() {
   printf '%s\n' "Usage:
  ${me} URL [--output-dir DIR]
  ${me} --url IMAGE_URL [--output-dir DIR]
  ${me} --version VER --arch ARCH --target TARGET --flavor FLAVOR [--project DOMAIN] [--output-dir DIR]"
}

print_help() {
   print_usage
   printf '%s\n' "
Pass EITHER a published version OR a full download URL. A URL contains all
needed data on its own, while a version requires additional arch/target/flavor
information.

  --version VER      published version, e.g. 18.2.1.7
  --url IMAGE_URL    full download URL
  --arch ARCH        amd64 | arm64
  --target TARGET    iso | virtualbox | raw | qcow2
  --flavor FLAVOR    kicksecure-{lxqt,cli,debug} | whonix-{cli,lxqt}
  --project DOMAIN   download domain (default: kicksecure.com for kicksecure-*,
                     whonix.org for whonix-*)
  --output-dir DIR   where to place the downloads (default: current dir)

Verify downloaded images with: dm-reproducible-verify DIR/<image>
Exit codes: 0 all files fetched; 2 usage / download error."
}

error() {
   printf '%s\n' "ERROR: $*" >&2
   exit 2
}

url=""
out_dir="."
version=""
target=""
flavor=""
arch=""
project=""

while [ "$#" -gt 0 ]; do
   case "${1:-}" in
      --output-dir)
         [ "$#" -ge 2 ] || error "--output-dir requires a value."
         out_dir="$2"
         shift 2
         ;;
      --url)
         [ "$#" -ge 2 ] || error "--url requires a value."
         url="$2"
         shift 2
         ;;
      --version)
         [ "$#" -ge 2 ] || error "--version requires a value."
         version="$2"
         shift 2
         ;;
      --target)
         [ "$#" -ge 2 ] || error "--target requires a value."
         target="$2"
         shift 2
         ;;
      --flavor)
         [ "$#" -ge 2 ] || error "--flavor requires a value."
         flavor="$2"
         shift 2
         ;;
      --arch)
         [ "$#" -ge 2 ] || error "--arch requires a value."
         arch="$2"
         shift 2
         ;;
      --project)
         [ "$#" -ge 2 ] || error "--project requires a value."
         project="$2"
         shift 2
         ;;
      -h|--help)
         print_help
         exit 0
         ;;
      -*)
         error "unknown option: '$1' (run with --help)."
         ;;
      *)
         case "$1" in
            *://*)
               [ -z "${url}" ] || error "URL given more than once."
               url="$1"
               ;;
            *)
               error "unexpected argument '$1'. Note that only a URL is accepted as a positional argument (see --help)."
               ;;
         esac
         shift
         ;;
   esac
done

if [ -n "${url}" ] && [ -n "${version}" ]; then
   print_usage >&2
   error "pass EITHER --version OR --url, not both."
fi
if [ -z "${url}" ] && [ -z "${version}" ]; then
   print_usage >&2
   error "pass a published version (--version) or a URL."
fi

# shellcheck source=../libexec/developer-meta-files/reproducible-target-map.bsh
source "${MYDIR}/../libexec/developer-meta-files/reproducible-target-map.bsh"

## VERSION mode: build the download URL. Mirrors the image naming in
## help-steps/variables:
##   https://download.<domain>/<url_part>/<version>/<flavor>-<version>.<arch_pretty>.<ext>
## A naming drift here just yields a 404, never a wrong download.
if [ -n "${version}" ]; then
   [ -n "${arch}" ]   || error "--version requires --arch (see --help)."
   [ -n "${target}" ] || error "--version requires --target (see --help)."
   [ -n "${flavor}" ] || error "--version requires --flavor (see --help)."

   case "${flavor}" in
      kicksecure-lxqt)
         image_name_base="Kicksecure-LXQt"
         ;;
      kicksecure-cli)
         image_name_base="Kicksecure-CLI"
         ;;
      kicksecure-ci-tiny-do-not-use)
         image_name_base="Kicksecure-CI-Tiny-Do-Not-Use"
         ;;
      whonix-cli)
         image_name_base="Whonix-CLI"
         ;;
      whonix-lxqt)
         image_name_base="Whonix-LXQt"
         ;;
      *)
         error "unsupported --flavor '${flavor}' (see --help)."
         ;;
   esac

   ## Default the download domain from the flavor's project when not given.
   if [ -z "${project}" ]; then
      case "${flavor}" in
         whonix-*)
            project="whonix.org"
            ;;
         kicksecure-*)
            project="kicksecure.com"
            ;;
         *)
            ## Probably unreachable code.
            error "Could not determine download domain from flavor, pass --project explicitly (see --help)."
            ;;
      esac
   fi

   case "${arch}" in
      amd64)
         arch_pretty="Intel_AMD64"
         ;;
      arm64)
         arch_pretty="arm64"
         ;;
      *)
         error "unsupported --arch '${arch}' (amd64|arm64)."
         ;;
   esac

   url_part=""
   ext=""
   dm_reproducible_target_url_part url_part "${target}" \
      || error "unsupported --target '${target}' (iso|virtualbox|raw|qcow2)."
   dm_reproducible_target_ext ext "${target}"

   url="https://download.${project}/${url_part}/${version}/${image_name_base}-${version}.${arch_pretty}.${ext}"
   printf '%s\n' "INFO: built download URL from --version: ${url}" >&2
fi

## URL mode: auto-detect version, project, target and arch from the link, but
## only when the URL actually matches the published layout
## (.../<url_part>/<version>/Kicksecure-...). The download always uses the URL
## verbatim, so detection is purely informational.
if [ -n "${url}" ] && [ -z "${version}" ]; then
   ## The parsing below splits up a URL as follows:
   ##
   ##                                          url
   ##                                           v
   ##  ___________________________________________________________________________________
   ## /                                    det_hostpath                                   \
   ## |                                         v                                         |
   ## |        ___________________________________________________________________________|
   ## |       /                                                                           \
   ## |       |                                                                           |
   ## https://download.kicksecure.com/ova/18.2.1.9/Kicksecure-LXQt-18.2.1.9.Intel_AMD64.ova
   ##         |        |            | | | |      | |             |          |         |   |
   ##         |        \____________/ | | |      | \_____________/          \_________/   |
   ##         |              ^      | | | |      | |      ^                 |    ^        |
   ##         |         det_project | | | |      | |  det_flavor            |det_arch_pretty
   ##         \_____________________/ | | |      | |                        \_____________/
   ##                    ^            | | |      | |                                ^     |
   ##                 det_host        | | |      | |                            det_after |
   ##                                 | | \______/ \______________________________________/
   ##                                 | | |   ^                      ^                    |
   ##                                 | | | det_version           det_file                |
   ##                                 \_/ \_______________________________________________/
   ##                                 |^                           ^                      |
   ##                                 |det_url_part          det_afterpart                |
   ##                                 \___________________________________________________/
   ##                                                           ^
   ##                                                     det_pathonly
   ##
   ## det_target is derived from det_url_part.
   ##
   ## NOTE: Please maintain this diagram as this code changes. Too much time
   ## has been wasted re-analyzing this every time code review comes up, the
   ## diagram above answers "what does each variable contain" at a glance.

   det_hostpath="${url#*://}"
   det_host="${det_hostpath%%/*}"
   det_project="${det_host#download.}"
   det_pathonly="${det_hostpath#*/}"
   det_url_part="${det_pathonly%%/*}"
   det_afterpart="${det_pathonly#*/}"
   det_version="${det_afterpart%%/*}"
   det_file="$(basename -- "${url%%\?*}")"
   det_flavor="${det_file%%-"${det_version}".*}"
   det_after="${det_file#*-"${det_version}".}"
   det_arch_pretty="${det_after%%.*}"
   dm_reproducible_url_part_to_target det_target "${det_url_part}" || det_target=""
   case "${det_arch_pretty}" in
      Intel_AMD64)
         det_arch="amd64"
         ;;
      *)
         det_arch="${det_arch_pretty}"
         ;;
   esac
   if [ -n "${det_target}" ]; then
      if [ "${det_file#Kicksecure-}" != "${det_file}" ] \
         || [ "${det_file#Whonix-}" != "${det_file}" ]; then
         printf '%s\n' "INFO: detected from URL: project=${det_project} flavor=${det_flavor} target=${det_target} version=${det_version} arch=${det_arch}" >&2
      fi
   else
      printf '%s\n' "INFO: URL not in the recognized download layout; fetching verbatim (no metadata detected)." >&2
   fi
fi
command -v scurl >/dev/null 2>&1 || command -v curl >/dev/null 2>&1 || error "neither scurl nor curl found."

mkdir --parents -- "${out_dir}"

## Resumable, https-only. scurl (hardened wrapper) preferred.
fetch() {
   local src="$1" dst="$2"
   local dl=( curl --tlsv1.3 --proto '=https' --location --fail --retry 5 --retry-all-errors --retry-delay 10 --continue-at - )
   if command -v scurl >/dev/null 2>&1; then
      dl=( scurl --location --fail --retry 5 --retry-all-errors --retry-delay 10 --continue-at - )
   fi
   "${dl[@]}" --output "${dst}" -- "${src}" || error "download failed: ${src}"
}

image_name="$(basename -- "${url%%\?*}")"
dest="${out_dir}/${image_name}"

printf '%s\n' "INFO: fetching image (UNTRUSTED) + reproducibility sidecars into '${out_dir}'..." >&2
fetch "${url}"                    "${dest}"
fetch "${url}.dm-buildinfo"       "${dest}.dm-buildinfo"
fetch "${url}.dm-buildinfo.asc"   "${dest}.dm-buildinfo.asc"
fetch "${url}.dm-buildinfo.sig"   "${dest}.dm-buildinfo.sig"
fetch "${url}.sha512sums"         "${dest}.sha512sums"
fetch "${url}.sha512sums.asc"     "${dest}.sha512sums.asc"
fetch "${url}.sha512sums.sig"     "${dest}.sha512sums.sig"

printf '%s\n' "INFO: downloaded to '${dest}'." >&2
printf '%s\n' "INFO: verify with: dm-reproducible-verify '${dest}'" >&2
