#!/bin/bash

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

#set -x
set -o pipefail
set -o errtrace

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

error_handler() {
   local exit_code="$?"

   local MSG="\
###############################################################################
## $SCRIPTNAME script bug.
## Please report this bug!
##
## BASH_COMMAND: $BASH_COMMAND
## exit_code: $exit_code
##
## For debugging run:
##
## $SCRIPTNAME --verbose
##
## Clean the output and submit to developers.
###############################################################################\
"
   echo "$MSG"
   exit 1
}

trap "error_handler" ERR

colors() {
   if [ "$TERM" = "" ]; then
      return 0
   fi

   ## Thanks to:
   ## http://mywiki.wooledge.org/BashFAQ/037
   ## Variables for terminal requests.
   [[ -t 2 ]] && {
       alt=$(      tput smcup  || tput ti      ) # Start alt display
       ealt=$(     tput rmcup  || tput te      ) # End   alt display
       hide=$(     tput civis  || tput vi      ) # Hide cursor
       show=$(     tput cnorm  || tput ve      ) # Show cursor
       save=$(     tput sc                     ) # Save cursor
       load=$(     tput rc                     ) # Load cursor
       bold=$(     tput bold   || tput md      ) # Start bold
       stout=$(    tput smso   || tput so      ) # Start stand-out
       estout=$(   tput rmso   || tput se      ) # End stand-out
       under=$(    tput smul   || tput us      ) # Start underline
       eunder=$(   tput rmul   || tput ue      ) # End   underline
       reset=$(    tput sgr0   || tput me      ) # Reset cursor
       blink=$(    tput blink  || tput mb      ) # Start blinking
       italic=$(   tput sitm   || tput ZH      ) # Start italic
       eitalic=$(  tput ritm   || tput ZR      ) # End   italic
   [[ $TERM != *-m ]] && {
       red=$(      tput setaf 1|| tput AF 1    )
       green=$(    tput setaf 2|| tput AF 2    )
       yellow=$(   tput setaf 3|| tput AF 3    )
       blue=$(     tput setaf 4|| tput AF 4    )
       magenta=$(  tput setaf 5|| tput AF 5    )
       cyan=$(     tput setaf 6|| tput AF 6    )
   }
       white=$(    tput setaf 7|| tput AF 7    )
       default=$(  tput op                     )
       eed=$(      tput ed     || tput cd      )   # Erase to end of display
       eel=$(      tput el     || tput ce      )   # Erase to end of line
       ebl=$(      tput el1    || tput cb      )   # Erase to beginning of line
       ewl=$eel$ebl                                # Erase whole line
       draw=$(     tput -S <<< '   enacs
                                   smacs
                                   acsc
                                   rmacs' || { \
                   tput eA; tput as;
                   tput ac; tput ae;         } )   # Drawing characters
       back=$'\b'
   } 2>/dev/null ||:
}

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_list_file_derivative" ] || sources_list_file_derivative="/etc/apt/sources.list.d/derivative.list"
}

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

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

no_option_msg() {
   echo "ERROR: No option given. Usage examples:

   sudo $SCRIPTNAME --enable --repository stable

   sudo $SCRIPTNAME --verbose --enable --repository stable

   sudo $SCRIPTNAME --enable --codename $codename_default_stable

   sudo $SCRIPTNAME --disable

   sudo $SCRIPTNAME --disable --verbose

   See also:

   man $SCRIPTNAME"
   exit 1
}

parse_cmd_options() {
   ## Thanks to:
   ## http://mywiki.wooledge.org/BashFAQ/035

   local HELP_MSG="See:
man $SCRIPTNAME"

   args="$@"
   args_without_spaces="${args//[[:space:]]/}"
   if [ "$args_without_spaces" = "" ]; then
      no_option_msg
      exit 1
   fi

   while :
   do
       case $1 in
           -h | --help | -\?)
               echo "$HELP_MSG"
               exit 0
               ;;
           -v | --verbose)
               echo "INFO '$BASH_SOURCE': verbose output..."
               set -x
               VERBOSE="1"
               shift
               ;;
           -e | --enable)
               enable="1"
               shift
               ;;
           -d | --disable)
               disable="1"
               shift
               ;;
           -c | --codename)
               codename="$2"
               if [ "$codename" = "" ]; then
                  echo "ERROR: codename may not be empty!"
                  exit 1
               fi
               shift 2
               ;;
           -r | --repository)
               repository="$2"
               if [ "$repository" = "" ]; then
                  echo "ERROR: repository may not be empty! You most likely want to use ${under}stable${reset}, ${under}stable-proposed-update${reset}, ${under}testers${reset} or ${under}developers${reset} as repository."
                  exit 1
               fi
               shift 2
               ;;
           -t | --transport)
                transport="$2"
                if [ -z "${transport}" ]; then
                    echo "ERROR: transport must not be empty. Choose between:
 plain-tls
 plain-tls-tor
 onion
 onion-tls"
                    exit 1
                fi
                shift 2
                ;;

             ## TODO
#            -b | --baseuri)
#                DERIVATIVE_APT_REPOSITORY_BASEURI="$2"
#                if [ "$DERIVATIVE_APT_REPOSITORY_BASEURI" = "" ]; then
#                   echo "ERROR: DERIVATIVE_APT_REPOSITORY_BASEURI may not be empty!"
#                   exit 1
#                fi
#                shift 2
#                ;;
           --)
               shift
               break
               ;;
           -*)
               echo "INFO '$BASH_SOURCE': unknown option: '$1'" >&2
               exit 1
               ;;
           *)
               break
               ;;
       esac
   done

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

parse_variables() {
    [ "$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 -q "/sid" /etc/debian_version ; then
            codename_default_stable="$(cat /etc/debian_version)"
            ## example codename_default_stable:
            ## bookworm/sid
            codename_default_stable="${codename_default_stable/%"/sid"}"
            ## example codename_default_stable:
            ## bookworm
         fi
      fi

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

      if [ -z "$codename_default_stable" ]; then
         echo "ERROR: codename auto detection failed! Please manually set ${under}--codename${reset}."
         exit 1
      fi

    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";;
        *)
            echo "ERROR: Invalid repository option, available options are:
 stable
 stable-proposed-updates
 testers
 developers"
            exit 1
        esac
   fi

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

   if [ ! "$codename_old" = "$codename" ]; then
      echo "INFO: Removed white spaces from codename ${under}$codename_old${reset} and set to codename ${under}$codename${reset}."
   fi
}

disable_or_create() {
   if [ "$disable" = "1" ]; then
      if [ -f "$sources_list_file_derivative" ]; then
         echo "INFO '$BASH_SOURCE': Deleting derivative APT repository '${under}$sources_list_file_derivative${reset}'..."
         rm --force "$sources_list_file_derivative"
         ## Deletion of /usr/share/keyrings/derivative.asc is unnecessary, see:
         ## https://www.kicksecure.com/wiki/Dev/APT
         echo "INFO '$BASH_SOURCE': Done."
      else
         echo "INFO '$BASH_SOURCE': '${under}$sources_list_file_derivative${reset}' 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_list_generator
      mkdir -p /var/cache/setup-dist/status-files || true
      touch /var/cache/setup-dist/status-files/repository-dist.done || true
   fi
}

sources_list_generator() {
    if echo "$codename" | grep -q -i "n/a" ; then
        echo "ERROR: Autodetected codename '${under}$codename${reset}' is invalid!"
        echo 'Please set codename explicitly using:'
        echo '${under}--codename${reset}'
        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="/etc/apt/sources.list.d/derivative.list"

    ## 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}"
            ;;
        *) echo "ERROR: Invalid transport type, it can only be:
 plain-tls
 plain-tls-tor
 onion
 onion-tls"
        exit 1
        ;;
    esac

    echo "INFO '$BASH_SOURCE': Using distribution '${under}$codename${reset}' (version of derivative) as apt repository."
    echo "INFO '$BASH_SOURCE': Creating '${under}$sources_file${reset}'..."

    echo "\
## Copyright (C) 2012 - 2023 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## $sources_list_file_derivative

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

deb [signed-by=/usr/share/keyrings/derivative.asc] $kicksecure_repo $codename main contrib non-free
#deb-src [signed-by=/usr/share/keyrings/derivative.asc] $kicksecure_repo $codename main contrib non-free
" | tee "$sources_file" >/dev/null

    if test -f /usr/share/whonix/marker; then
        echo "\
deb [signed-by=/usr/share/keyrings/derivative.asc] $whonix_repo $codename main contrib non-free
#deb-src [signed-by=/usr/share/keyrings/derivative.asc] $whonix_repo $codename main contrib non-free
" | tee -a "$sources_file" >/dev/null
    fi

    cat "$sources_file"
    echo "INFO '$BASH_SOURCE': Done."
}

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

main_function "$@"
