#!/bin/bash

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

#set -x
set -e
set -o pipefail

error_handler() {
   echo "ERROR: BASH_COMMAND: $BASH_COMMAND | exit_code: $?"
   exit 1
}

trap "error_handler" ERR

canary_preparation() {
    source /usr/libexec/systemcheck/canary-run-or-not
    if [ "$canary_run" = "false" ]; then
       echo "INFO: Disabled in settings. Doing nothing. Exiting."
       exit 0
    fi

   if [ ! "$(whoami)" = "canary" ]; then
      echo "ERROR: Exiting. Must be run under user 'canary'."
      exit 1
   fi

   if [ "$NOTIFY_SOCKET" = "" ]; then
      ## Support manual run from command line.
      ## I.e. when run not through systemd unit.
      systemd_notify="true 'INFO: skip because NOTIFY_SOCKET unset. Probably run manually. SKIP: systemd-notify"
   else
      systemd_notify=systemd-notify
   fi

   if test -d /usr/share/qubes ; then
      virtualizer=qubes
      known_virtualizer=yes
   else
      virtualizer="$(systemd-detect-virt)" || true
      if [ "$virtualizer" = "oracle" ]; then
         known_virtualizer=yes
      elif [ "$virtualizer" = "kvm" ]; then
         known_virtualizer=yes
      elif [ "$virtualizer" = "qemu" ]; then
         known_virtualizer=yes
      fi
   fi

   if [ ! "$known_virtualizer" = "yes" ]; then
      virtualizer=unknown
   fi

   ## Dedicated onion different from homepage.
   if test -f /usr/share/whonix/marker ; then
      true "INFO: Whonix detected."
      [ -n "$canary_base_api_link" ] || canary_base_api_link="http://api.vel76jfvbl6rlq7qrgewrxpkzhulutx5tl4me4lwpzfje4sv6qgrckad.onion"
   else
      true "INFO: Kicksecure detected."
      [ -n "$canary_base_api_link" ] || canary_base_api_link="http://api.ost5p5ju2eojz4ukhb7iib7pxvwrkm7yzeezamnzmxwidhnrtgad7yad.onion"
   fi

   ## Testing.
   #virtualizer=apitest

   canary_api_link=""
   canary_api_link+="$canary_base_api_link"
   canary_api_link+="/"
   canary_api_link+="canary"
   canary_api_link+="?virtualizer=${virtualizer}"

   ## Sanity test.
   test -w /var/lib/canary
}

connectivity_wait() {
   while true; do
      $systemd_notify --pid="$PPID" WATCHDOG=1

      if test -f /run/sdwdate/success ; then
         break
      fi

      $systemd_notify --pid="$PPID" WATCHDOG=1

      sleep 120

      $systemd_notify --pid="$PPID" WATCHDOG=1
   done
}

check_canary_lastrun() {
   ## One hour has 3600 seconds.
   ## A day has 86400 seconds.
   local MAX="86400"

   if [ -f /var/lib/canary/canary_last_done ]; then
      LASTRUN="$(cat /var/lib/canary/canary_last_done)" || true
   fi

   if [[ "$LASTRUN" != *[!0-9]* ]]; then
      true "INFO: $FUNCNAME: LASTRUN is strictly numeric."
   else
      echo "ERROR: $FUNCNAME: LASTRUN not strictly numeric. LASTRUN: $LASTRUN"
      ## Not strictly numeric.
      ## the canary_completed function does almost the same
      LASTRUN="0"
   fi

   ## good until Sat 20 Nov 2286
   ## output of `date --utc --date @9999999999`:
   ## Sat 20 Nov 2286 05:46:39 PM UTC
   expected_string_length="10"
   actual_string_length="${#LASTRUN}"

   if [ ! "$actual_string_length" = "$expected_string_length" ]; then
      LASTRUN="0"
   fi

   local CURRENTTIME
   CURRENTTIME="$(date --utc +%s)"

   DIFFERENCE="$(( $CURRENTTIME - $LASTRUN ))"

   if [ "$DIFFERENCE" -le "$MAX" ]; then
      echo "LASTRUN: date --utc --date \"@${LASTRUN}\""
      echo "INFO: No need."
      exit 0
   fi

   echo "INFO: Attempting to download..."
}

canary_completed() {
   local LASTRUN
   LASTRUN="$(date --utc +%s)"
   echo "$LASTRUN" | tee /var/lib/canary/canary_last_done > /dev/null
}

canary_count_or_not() {
   if grep -qs "boot=live" /proc/cmdline; then
      echo "INFO: Skip in live mode."
      exit 0
   fi

   if test -f /run/qubes/this-is-templatevm ; then
      echo "INFO: Skip in Qubes TemplateVM."
      exit 0
   fi

   if command -v qubesdb-read &>/dev/null ; then
      qubes_vm_persistence="$(qubesdb-read /qubes-vm-persistence)"
   fi

   if [ "$qubes_vm_persistence" = "none" ]; then
      echo "INFO: Skip in Qubes DispVM."
      exit 0
   fi

   ## Count Whonix-Gateway and Kicksecure.
   if test -f /usr/share/anon-ws-base-files/workstation ; then
      echo "INFO: Skip. Not counting workstation. Only gateway only."
      exit 0
   fi
}

canary_files_delete() {
   rm -f "/var/lib/canary/canary.txt.embed.sig"
   rm -f "/var/lib/canary/canary-unembed.txt"
   rm -f "/var/lib/canary/canary-unixtime.txt"
   rm -f "/var/lib/canary/canary-download-output.txt"
}

canary_do() {
   canary_files_delete

   canary_download_exit_code="0"

   timeout --kill-after="5" "180" \
      /usr/libexec/systemcheck/canary-download \
      "$canary_api_link" 2>&1 \
      | tee "/var/lib/canary/canary-download-output.txt" > /dev/null \
      || { canary_download_exit_code="$?" ; true; };

   if [ ! "$canary_download_exit_code" = "0" ]; then
      echo "ERROR: Failure."
      echo "See: https://www.kicksecure.com/wiki/Systemcheck#Warrant_Canary_Check"
      exit 0
   fi

   echo "INFO: Success."

   canary_completed
}

canary_preparation
connectivity_wait
canary_count_or_not
check_canary_lastrun
canary_do
