#!/bin/bash

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

#set -x
set -o nounset
set -o errexit
set -o pipefail
set -o errtrace

SCRIPTNAME="$(basename "$BASH_SOURCE")"

source /usr/libexec/helper-scripts/log_run_die.sh

error_handler() {
   local exit_code="$?"

   local MSG="
${bold}${red}###############################################################################${nocolor}
## ${bold}$SCRIPTNAME script bug.${nocolor}
## ${red}Please report this bug!${nocolor}
##
## ${yellow}BASH_COMMAND:${nocolor} '$BASH_COMMAND'
## ${yellow}exit_code:${nocolor} '$exit_code'
##
## ${cyan}For debugging run:${nocolor}
##
## ${bold}$SCRIPTNAME --verbose${nocolor}
##
## ${green}Clean the output and submit to developers.${nocolor}
${bold}${red}###############################################################################${nocolor}
"
   log bug "$MSG"
   exit 1
}

trap "error_handler" ERR

preparation() {
   ## Fallback.
   ## TODO
#    [ -n "$DERIVATIVE_APT_REPOSITORY_BASEURI" ] || DERIVATIVE_APT_REPOSITORY_BASEURI="\
# tor+http://deb.dds6qkxpwdeubwucdiaord2xgbbeyds25rbsgr73tbfpqpt4a6vjwsyd.onion
# tor+https://deb.whonix.org"

   ## Not naming sources_list_target_build_remote_derivative to avoid conflict with Whonix / Kicksecure build script.
   [ -n "${sources_file_derivative:-}" ] || sources_file_derivative="/etc/apt/sources.list.d/derivative.sources"
}

root_check() {
   if [ "$(id -u)" != "0" ]; then
      log error "This must be run as root (sudo)!"
      exit 1
   fi
   true "INFO: Script running as root."
}

sanity_tests() {
   command -v id >/dev/null
}

usage() {
   get_codename_default
   log notice "${bold}${cyan}Usage:${nocolor} ${0##*/} [OPTIONS]
Options:
  ${yellow}-h, --help${nocolor}           print this help message
  ${yellow}-v, --verbose${nocolor}        increase verbosity

  ${green}-e, --enable${nocolor}         enables derivative distribution repository
  ${red}-d, --disable${nocolor}        remove '$sources_file_derivative'

  ${blue}-r, --repository${nocolor}     set the suite, values: stable, stable-proposed-updates, testers, developers
  ${blue}-t, --transport${nocolor}      set the transport, values: plain-tls, plain-tls-tor (default), onion, onion-tls (discouraged)

${bold}Advanced options:${nocolor}
  ${magenta}-c, --codename${nocolor}       set the codename

${bold}Transport assignment:${nocolor}
  ${cyan}plain-tls:${nocolor}           https://DOMAIN.org
  ${cyan}plain-tls-tor:${nocolor}       tor+https://DOMAIN.org
  ${cyan}onion:${nocolor}               tor+http://DOMAIN.onion
  ${cyan}onion-tls:${nocolor}           tor+https://DOMAIN.onion

${bold}Examples:${nocolor}
  ${green}sudo $SCRIPTNAME --enable --repository stable${nocolor}
  ${green}sudo $SCRIPTNAME --enable --repository stable-proposed-updates${nocolor}
  ${green}sudo $SCRIPTNAME --enable --repository testers${nocolor}
  ${green}sudo $SCRIPTNAME --enable --repository developers${nocolor}
  ${green}sudo $SCRIPTNAME --enable --verbose --repository stable${nocolor}
  ${green}sudo $SCRIPTNAME --enable --codename $codename_default_stable${nocolor}
  ${green}sudo $SCRIPTNAME --enable --transport onion${nocolor}
  ${green}sudo $SCRIPTNAME --enable --transport onion --repository testers${nocolor}
  ${red}sudo $SCRIPTNAME --disable${nocolor}
  ${red}sudo $SCRIPTNAME --disable --verbose${nocolor}

${bold}See also:${nocolor}
  ${underline}man $SCRIPTNAME${nounderline}"
   exit "${1:-1}"
}

parse_cmd_options() {
   ## Thanks to:
   ## http://mywiki.wooledge.org/BashFAQ/035
   if [ -z "${1-}" ]; then
      usage 1
   fi
   while :
   do
       case "${1-}" in
           -h | --help | -\? )
               usage 0
               ;;
           -v | --verbose)
               log notice "'$BASH_SOURCE': verbose output..."
               set -x
               VERBOSE="1"
               shift
               ;;
           -e | --enable)
               enable="1"
               shift
               ;;
           -d | --disable)
               disable="1"
               shift
               ;;
           -c | --codename)
               codename="${2:-}"
               if [ -z "${codename:-}" ]; then
                  log error "codename may not be empty!"
                  exit 1
               fi
               shift 2
               ;;
           -r | --repository)
               repository="${2:-}"
               case "$repository" in
                  stable|stable-proposed-updates|testers|developers)
                     ;;
                  *)
                     log error "Invalid repository option."
                     exit 1
                     ;;
               esac
               shift 2
               ;;
           -t | --transport)
                transport="${2:-}"
                case "${transport}" in
                   plain-tls|plain-tls-tor|onion|onion-tls)
                      ;;
                  "")
                     log error "transport must not be empty."
                     exit 1
                     ;;
                  *)
                     log error "transport is invalid."
                     exit 1
                     ;;
                esac
                shift 2
                ;;

             ## TODO
#            -b | --baseuri)
#                DERIVATIVE_APT_REPOSITORY_BASEURI="${2:-}"
#                if [ -z "$DERIVATIVE_APT_REPOSITORY_BASEURI" ]; then
#                   log error "DERIVATIVE_APT_REPOSITORY_BASEURI may not be empty!"
#                   exit 1
#                fi
#                shift 2
#                ;;
           --)
               shift
               break
               ;;
           -*)
               log error "$BASH_SOURCE': unknown option: '$1'"
               exit 1
               ;;
           "")
               break
               ;;
           *)
               break
               ;;
       esac
   done

   ## If there are input files (for example) that follow the options, they
   ## will remain in the "$@" positional parameters.
}

get_codename_default() {
    [ "${disable:-}" = "1" ] && return 0

   if [ -z "${codename:-}" ]; then
      [ -n "${codename_default_stable:-}" ] || codename_default_stable="$(lsb_release --short --codename)"

      ## If codename_default_stable could not be set using lsb_release above, try to acquire it
      ## from /etc/debian_version.
      if [ "${codename_default_stable:-}" = "n/a" ]; then
         if grep --quiet -- "/sid" /etc/debian_version ; then
            codename_default_stable="$(cat /etc/debian_version)"
            ## example codename_default_stable:
            ## trixie/sid
            codename_default_stable="${codename_default_stable/%"/sid"}"
            ## example codename_default_stable:
            ## trixie
         fi
      fi

      ## Remove eventual white spaces. Just in case.
      codename_default_stable="${codename_default_stable//[[:space:]]}"

      if [ -z "${codename_default_stable:-}" ]; then
         log error "codename auto detection failed! Please manually set ${underline}--codename${nounderline}."
         exit 1
      fi
   fi
}

parse_variables() {
   [ "${disable:-}" = "1" ] && return 0

   if [ -z "${codename:-}" ]; then
      get_codename_default
      case "${repository:-}" in
         stable) codename="${codename_default_stable:-}";;
         stable-proposed-updates) codename="${codename_default_stable}-proposed-updates";;
         testers) codename="${codename_default_stable}-testers";;
         developers) codename="${codename_default_stable}-developers";;
         "") codename="${codename_default_stable:-}";;
      esac
   fi

   local codename_old
   codename_old="${codename:-}"

   codename="${codename//[[:space:]]}"

   if [ ! "$codename_old" = "${codename:-}" ]; then
      log notice "Removed white spaces from codename ${underline}$codename_old${nounderline} and set to codename ${underline}$codename${nounderline}."
   fi
}

disable_or_create() {
   if [ "${disable:-}" = "1" ]; then
      if [ -f "$sources_file_derivative" ]; then
         log notice "'$BASH_SOURCE': Deleting derivative APT repository '${underline}$sources_file_derivative${nounderline}'..."
         rm --force --verbose -- "$sources_file_derivative"
         ## Deletion of /usr/share/keyrings/derivative.asc is unnecessary, see:
         ## https://www.kicksecure.com/wiki/Dev/APT
         ## Sanity test.
         ! test -f "$sources_file_derivative"
         log notice "'$BASH_SOURCE': Done."
      else
         log notice "'$BASH_SOURCE': '${underline}$sources_file_derivative${nounderline}' does not exist, ok."
      fi
      mkdir -p /var/cache/setup-dist/status-files || true
      touch /var/cache/setup-dist/status-files/repository-dist.done || true
   else
      sources_generator
      mkdir -p /var/cache/setup-dist/status-files || true
      touch /var/cache/setup-dist/status-files/repository-dist.done || true
   fi

   ## Check if /etc/apt/sources.list.d/derivative.list exists before deletion
   ## to avoid repetitive verbose deletion message.
   if test -f /etc/apt/sources.list.d/derivative.list; then
      ## Remove legacy .list file, this is no longer used as of Kicksecure 18.
      rm --force --verbose -- /etc/apt/sources.list.d/derivative.list
   fi
}

sources_generator() {
    if printf "%s" "${codename:-}" | grep --quiet --ignore-case -- "n/a" ; then
        log error "Autodetected codename '${underline}$codename${nounderline}' is invalid!"
        log error "Please set codename explicitly using:"
        log error "${underline}--codename${nounderline}"
        exit 1
    fi

    whonix_url_onion="deb.dds6qkxpwdeubwucdiaord2xgbbeyds25rbsgr73tbfpqpt4a6vjwsyd.onion"
    whonix_url_plain="deb.whonix.org"
    kicksecure_url_onion="deb.w5j6stm77zs6652pgsij4awcjeel3eco7kvipheu6mtr623eyyehj4yd.onion"
    kicksecure_url_plain="deb.kicksecure.com"

    sources_file="$sources_file_derivative"

    ## syntax is prefixing with 'tor+http(s)' for uniformity
    ## although 'http(s)+tor' also works.
    case "${transport:-}" in
        plain-tls)
            whonix_repo="https://${whonix_url_plain}"
            kicksecure_repo="https://${kicksecure_url_plain}"
            ;;
        plain-tls-tor)
            whonix_repo="tor+https://${whonix_url_plain}"
            kicksecure_repo="tor+https://${kicksecure_url_plain}"
            ;;
        onion)
            whonix_repo="tor+http://${whonix_url_onion}"
            kicksecure_repo="tor+http://${kicksecure_url_onion}"
            ;;
        onion-tls)
            whonix_repo="tor+https://${whonix_url_onion}"
            kicksecure_repo="tor+https://${kicksecure_url_onion}"
            ;;
        "")
            ## https://forums.whonix.org/t/tool-to-onionize-all-apt-sources/13367/29
            ## default to onion
            #whonix_repo="tor+http://${whonix_url_onion}"
            #kicksecure_repo="tor+http://${kicksecure_url_onion}"
            ## default to plain-tls-tor
            whonix_repo="tor+https://${whonix_url_plain}"
            kicksecure_repo="tor+https://${kicksecure_url_plain}"
            ;;
    esac

    sq cert lint --cert-file "/usr/share/keyrings/derivative.asc" &>/dev/null

    log notice "'$BASH_SOURCE': Using distribution '${underline}$codename${nounderline}' (version of derivative) as apt repository."
    log notice "'$BASH_SOURCE': Creating '${underline}$sources_file${nounderline}'..."

    printf "%s" "\
## Copyright (C) 2012 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## $sources_file_derivative

## This file has been automatically created by $SCRIPTNAME.
## If you make manual changes to it, your changes will be lost the next time
## you run the $SCRIPTNAME tool.
## You can conveniently manage this file using the $SCRIPTNAME tool.
## For any modifications (delete this file, use the stable version, use the testers'
## version, or use the developers' version), please use the $SCRIPTNAME tool.
## Run:
##    sudo $SCRIPTNAME --help
## Leaving the source line disabled by default to save time during updates.
## These are not useful anyway, since it's better to get the source code from
## the git repository.

#### ENABLED KICKSECURE SOURCES ####

Types: deb
URIs: $kicksecure_repo
Suites: $codename
Components: main contrib non-free
Enabled: yes
Signed-By: /usr/share/keyrings/derivative.asc

#### DISABLED BY DEFAULT KICKSECURE SOURCES ####

Types: deb-src
URIs: $kicksecure_repo
Suites: $codename
Components: main contrib non-free
Enabled: no
Signed-By: /usr/share/keyrings/derivative.asc

Types: deb deb-src
URIs: tor+http://$kicksecure_url_onion
Suites: $codename
Components: main contrib non-free
Enabled: no
Signed-By: /usr/share/keyrings/derivative.asc
" | sponge -- "$sources_file" >/dev/null

    if test -f /usr/share/whonix/marker; then
        printf "%s" "\

#### ENABLED WHONIX SOURCES ####

Types: deb
URIs: $whonix_repo
Suites: $codename
Components: main contrib non-free
Enabled: yes
Signed-By: /usr/share/keyrings/derivative.asc

#### DISABLED BY DEFAULT WHONIX SOURCES ####

Types: deb-src
URIs: $whonix_repo
Suites: $codename
Components: main contrib non-free
Enabled: no
Signed-By: /usr/share/keyrings/derivative.asc

Types: deb deb-src
URIs: tor+http://$whonix_url_onion
Suites: $codename
Components: main contrib non-free
Enabled: no
Signed-By: /usr/share/keyrings/derivative.asc
" | sponge -a -- "$sources_file" >/dev/null
    fi

    cat -- "$sources_file"
    log notice "'$BASH_SOURCE': Done."
}

main_function() {
    sanity_tests
    preparation
    parse_cmd_options "$@"
    root_check
    parse_variables
    disable_or_create
    sync
}

main_function "$@"
