#!/bin/bash

## Copyright (C) 2018 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## Copyright (C) 2018 Iry Koon <iry@riseup.net>
## See the file COPYING for copying conditions.

#### meta start
#### project Whonix
#### category tor and usability
#### gateway_only yes
#### description
## Tor configuration check command line utility.
#### meta end

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

shopt -s nullglob

## parse_cmd_options is based on code in repository-dist by Patrick
parse_cmd_options() {
   ## Thanks to:
   ## http://mywiki.wooledge.org/BashFAQ/035

   ## Initialize all the option variables.
   ## This ensures we are not contaminated by variables from the environment.
   VERBOSE=
   VERY_VERBOSE=

   local HELP_MSG="See:
   man $SCRIPTNAME"

   while :
   do
      case $1 in
         -h | --help | -\?)
            echo "$HELP_MSG"
            exit 0
         ;;
            -v | --verbose )
            echo "$SCRIPTNAME verbose output..."
            VERBOSE="1"
            shift
         ;;
            -vv | --very-verbose)
            echo "$SCRIPTNAME very verbose output..."
            VERBOSE="1"
            VERY_VERBOSE="1"
            shift
         ;;
            --)
            shift
            break
         ;;
            -*)
            echo "$SCRIPTNAME 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.
}

## get_tor_start_command() will set the $tor_start_command to the command
## used in Whonix to start Tor. If it did not successfully extract the
## command, it will exit with exit code 1. If Whonix get rid of
## systemd for Tor control in the future, we simply change the content
## in the tor_start_command.
##
## This is incompatible with privleap, thus out-commented to allow
## Whonix-Gateway to operate sudoless.
#function get_tor_start_command() {
#   ## Tor use systemd to start
#   tor_start_command=$(grep -i "ExecStart=" /lib/systemd/system/tor@default.service | sed s/ExecStart=//g)
#
#   if [ -z "$tor_start_command" ]; then
#      echo "[error] Failed to extra commands used to start Tor." >&2
#      return 1
#   fi
#
#   ## Tor is run as root, we need to simulate this, too.
#   tor_start_command="sudo $tor_start_command"
#}

## generate_report will generate a user-friendly report based on
## $tor_verify_config_output and $tor_verify_config_exit_code
function generate_report() {
   ## generate concise report
   echo "/===================================================================\\"
   echo "|                      Report Summary                               |"
   echo "\\===================================================================/"

   if [ "$tor_verify_config_exit_code" = "0" ]; then
      echo "No error detected in your Tor configuration."
      echo "Tor verify exit code: $tor_verify_config_exit_code"
      tor_verify_config_output_concise="Tor configuration was valid."
   else
      echo "Your Tor config files contain at least one error."
      echo "Tor verify exit code: $tor_verify_config_exit_code"

      ## concise report which only contains complains with [warn] or [err] tags
      echo "/===================================================================\\"
      echo "|                    Tor Concise Report                             |"
      echo "\\===================================================================/"
      echo "Below warns and errors must be fixed before you can use Tor:"
      grep -E -w -h -i --color '\[warn\]|\[err\]' <<< "$tor_verify_config_output"
      tor_verify_config_output_concise="$(grep -E -w -h -i --color '\[warn\]|\[err\]' <<< "$tor_verify_config_output" 2>&1)" || true
   fi

   echo "/===================================================================\\"
   echo "|                      Tor Full Report                              |"
   echo "\\===================================================================/"
   echo "$tor_verify_config_output"

   ## TODO: $anon_verify_report_html is used by systemcheck
   ## we need to find a way to merge it with $anon_verify_report
   tor_verify_config_output_html="$(/usr/libexec/msgcollector/br_add "$tor_verify_config_output")"
   anon_verify_report_html="<p>Tor Config Check Result:
<br></br><b>Your Tor config files contain at least one error.</b></p>

<p>(Tor exit code: $tor_verify_config_exit_code)</p>

<p><u><b>Tor concise reports (below warns and errors must be fixed before you can use Tor)</b></u>:
<br></br><code>$tor_verify_config_output_concise</code></p>

<p><u>Tor full reports</u>:
<br></br><code>$tor_verify_config_output_html</code></p>

Try to look at this report again by running:

$start_menu_instructions_system_first_part Terminal

<blockquote>anon-verify</blockquote>

<p>To try to fix this, please open your Tor config file.

<blockquote>    $start_menu_instructions_system_first_part Torrc</blockquote>
    <br></br>or in Terminal: <code>sudo nano /usr/local/etc/torrc.d/50_user.conf</code></p>

<p>Please restart Tor after fixing this error.

<blockquote>    $start_menu_instructions_system_first_part Restart Tor</blockquote>
    <br></br>or in Terminal: <code>sudo systemctl restart tor@default</code></p>"

   ## torrc-parser will grep the invalid option for user and specify
   ## which file is corrupted for better fixing suggestion
   bash -n /usr/libexec/anon-gw-anonymizer-config/torrc-parser
   source /usr/libexec/anon-gw-anonymizer-config/torrc-parser

   ## extract default_torrc file and -f torrc file
   if [[ "$tor_start_command" =~ (--defaults-torrc )([^ ]*) ]]; then
      default_torrc="${BASH_REMATCH[2]}"
   fi

   if [[ "$tor_start_command" =~ (-f )([^ ]*) ]]; then
      f_torrc="${BASH_REMATCH[2]}"
   fi

   ## call parser() to parse torrc files, arguments order matters
   parser "$default_torrc" "$f_torrc"

   echo "/===================================================================\\"
   echo "|                 Used Tor Configuration Files                      |"
   echo "\\===================================================================/"
   used_torrc_files

   extraneous_torrc_files

   ## TODO: More suggestions to different errors can be added in the
   ## future

   ## extract the unknown option complained by Tor
   if [[ "$tor_verify_config_output" =~ (Unknown option \')([^\']*) ]]; then
      echo "/===================================================================\\"
      echo "|                 Detailed Suggested Solution                       |"
      echo "\\===================================================================/"
      unknown_option_specifier "${BASH_REMATCH[2]}"
   fi

   ## parsing_order_verbose creates a very long output which is not
   ## user-friendly. Therefore, we do not enable it by default and
   ## only use it with anon-verify -v and anon-verify -vv
   if [ "$VERBOSE" = "1" ]; then
      echo "/===================================================================\\"
      echo "|                Verbose Tor Configuration Parsing                  |"
      echo "\\===================================================================/"
      parsing_order_verbose
   fi

   echo "====================================================================="
}

parse_cmd_options "$@"

#get_tor_start_command

## since we should use exactly the same arguments to examine if Tor
## can start, we simply append the --verify-config arguments behind it
## (and run as root)
#tor_verify="$tor_start_command --verify-config"

## execute the verification
tor_verify_config_exit_code="0"
tor_verify_config_output="$(leaprun anonymizer-tor-verify-config)" || { tor_verify_config_exit_code="$?" ; true; };

## generate the report
generate_report
