#!/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
#### gateway_only yes
#### description
## helper script for <code>anon-verify</code>
#### meta end

#set -ex

temp_verbose_torrc=$(mktemp)

## style-ok: no-strict -- this file is sourced, not executed.

declare -a torrc_files=()
declare -a extraneous_torrc=()

function parser() {
   local abs_path
   for abs_path in "$@"; do
      true "abs_path: '${abs_path}'"
      if [[ -f "${abs_path}" ]]; then
         local base_name first_character file_extension
         base_name="${abs_path##*/}"
         first_character=${base_name:0:1}
         file_extension="${base_name##*.}"

         if [ "${first_character}" = "." ]; then
            printf '%s\n' "===> Ignoring file name starting with '.': ${abs_path} (Quote Tor manual: 'Files starting with a dot are ignored.')" | tee -a -- "${temp_verbose_torrc}" >/dev/null
            continue
         fi

         if [ "${abs_path}" = "/usr/share/tor/tor-service-defaults-torrc" ]; then
            true "good: ${abs_path}"
         elif [ "${abs_path}" = "/usr/share/tor/tor-service-defaults-torrc.anondist" ]; then
            true "good: ${abs_path}"
         elif [ "${abs_path}" = "/etc/tor/torrc" ]; then
            true "good: ${abs_path}"
         else
            if [ "${file_extension}" = "conf" ]; then
               true "good: ${abs_path}"
            else
               true "extraneous: ${abs_path}"
               extraneous_torrc+=("${abs_path}")
            fi
         fi

         printf '%s\n' "===> Start parsing file ${abs_path}" | tee -a -- "${temp_verbose_torrc}" >/dev/null
         torrc_files+=("${abs_path}")

         while read -r line ; do
            true "line: '${line}'"
            if [ "${line}" = "" ]; then
               ## show empty lines only when $VERY_VERBOSE is "1"
               ## Set by anon-verify, which sources this file, so shellcheck
               ## cannot see the assignment from here.
               # shellcheck disable=SC2154
               if [ ! "${VERY_VERBOSE}" = "1" ]; then
                  true "Skipping empty line."
                  continue
               fi
            fi
            ## only show comments in torrc files when $VERY_VERBOSE is "1"
            if [[ "${line}" =~ ^[[:space:]]*# ]]; then
               true "line is a comment: yes"
               if [ "${VERY_VERBOSE}" = "1" ]; then
                  printf '%s\n' "${line}" | tee -a -- "${temp_verbose_torrc}" >/dev/null
               fi
            else
               true "line is a comment: no"
               printf '%s\n' "${line}" | tee -a -- "${temp_verbose_torrc}" >/dev/null
            fi

            true "Checking if the line includes '%include'..."
            if printf '%s\n' "${line}" | grep -- "%include" &>/dev/null ; then
               true "Yes, the line includes '%include'."
               local second_word
               second_word="$(printf '%s\n' "${line}" | awk '{print $2;}')"
               ## Do not quote because /etc/torrc.d/*.conf needs to be expanded.
               ## '${second_word}' is DELIBERATELY UNQUOTED. A torrc
               ## '%include /etc/torrc.d/*.conf' puts a glob here.
               # shellcheck disable=SC2086
               parser ${second_word}
            else
               true "No, the line does not include '%include'."
            fi
         done < "${abs_path}"
         printf '%s\n' "===> Done parsing file ${abs_path}" | tee -a -- "${temp_verbose_torrc}" >/dev/null
      elif [[ -d "${abs_path}" ]]; then
         printf '%s\n' "===> Start parsing folder: ${abs_path}" | tee -a -- "${temp_verbose_torrc}" >/dev/null
         local fso
         while IFS= read -r -d '' fso ; do
            if [ -d "${fso}" ]; then
               printf '%s\n' "===> Ignoring subfolder: ${abs_path} (Quote Tor manual: 'Files on subfolders are ignored.')" | tee -a -- "${temp_verbose_torrc}" >/dev/null
               continue
            fi
            parser "${fso}"
         done < <(find "${abs_path}" -mindepth 1 -maxdepth 1 -print0 | sort -z -g)
         printf '%s\n' "===> Done parsing folder : ${abs_path}" | tee -a -- "${temp_verbose_torrc}" >/dev/null
      else
         printf '%s\n' "ERROR: invalid file system object (fso) (abs_path): '${abs_path}'"
      fi
   done
}

function parsing_order_verbose(){
   printf '%s\n' "The Tor configuration files are parsed in such order: "
   cat -- "${temp_verbose_torrc}"
}

function used_torrc_files(){
   printf '%s\n' "${#torrc_files[@]} files are used as Tor configuration files: "
   printf '%s\n' "${torrc_files[@]}"
}

function unknown_option_specifier(){
   for unknown_option in "$@"; do
      printf '%s\n' "The following files contain unknown option '${unknown_option}': "

      if [ "${#torrc_files[@]}" -eq 0 ]; then
         printf '%s\n' "(none -- no Tor configuration files were found to search)"
         continue
      fi

      if ! grep -iHnE --color -- "^([[:space:]])*${unknown_option}" "${torrc_files[@]}" ; then
         printf '%s\n' "(none -- no files containing '${unknown_option}' were matched)"
      fi
      printf '%s\n' "Please modify these files to fix the problem."
   done
}

function extraneous_torrc_files(){
   if [ "${#extraneous_torrc[@]}" -eq 0 ]; then
      return 0
   fi
   printf '%s\n' "/===================================================================\\"
   printf '%s\n' "|                 Extraneous Tor Configuration Files                |"
   printf '%s\n' "\\===================================================================/"
   printf '%s\n' "${#extraneous_torrc[@]} files are do not end with file extension '.conf': "
   printf '%s\n' "${extraneous_torrc[@]}"
   printf '%s\n' "These should be probably removed."
}

#parser $@
#parsing_order_verbose
#used_torrc_files
#unknown_option_specifier "bridge" "control"
