#!/bin/bash

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

source /usr/libexec/helper-scripts/live-mode.sh

canary_folder_permission_issues() {
   local MSG="\
<p>$warrant_canary_check_link: Folder <code>/var/lib/canary</code> permissions issue.</p>"
   if [ "$verbose" -ge "1" ]; then
      $output_x ${output_opts[@]} --messagex --typex "info" --message "$MSG"
      $output_cli ${output_opts[@]} --messagecli --typecli "info" --message "$MSG"
   fi
   return 0
}

check_warrant_canary() {
    local warrant_canary_check_link="\
<a href=https://www.whonix.org/wiki/Systemcheck#Warrant_Canary_Check>Warrant Canary Check</a>"

   ## same conditions as in /usr/libexec/systemcheck/canary

   source /usr/libexec/systemcheck/canary-run-or-not
   if [ "$canary_run" = "false" ]; then
      local MSG="\
<p>$warrant_canary_check_link: Disabled in settings. Doing nothing. Skipping.</p>"
      if [ "$verbose" -ge "1" ]; then
         $output_x ${output_opts[@]} --messagex --typex "info" --message "$MSG"
         $output_cli ${output_opts[@]} --messagecli --typecli "info" --message "$MSG"
      fi
         return 0
   fi

   if [ "$vm_lower_case_short" = "workstation" ]; then
      local MSG="\
<p>$warrant_canary_check_link: Skipping on $VM, ok.</p>"
      if [ "$verbose" -ge "1" ]; then
         $output_x ${output_opts[@]} --messagex --typex "info" --message "$MSG"
         $output_cli ${output_opts[@]} --messagecli --typecli "info" --message "$MSG"
      fi
      return 0
   fi

   if [ "$live_status_detected" = 'true' ]; then
      local MSG="\
<p>$warrant_canary_check_link: Skipping in live mode, ok.</p>"
      if [ "$verbose" -ge "1" ]; then
         $output_x ${output_opts[@]} --messagex --typex "info" --message "$MSG"
         $output_cli ${output_opts[@]} --messagecli --typecli "info" --message "$MSG"
      fi
      return 0
   fi

   if test -f /run/qubes/this-is-templatevm ; then
      local MSG="\
<p>$warrant_canary_check_link: Skipping in Template, ok.</p>"
      if [ "$verbose" -ge "1" ]; then
         $output_x ${output_opts[@]} --messagex --typex "info" --message "$MSG"
         $output_cli ${output_opts[@]} --messagecli --typecli "info" --message "$MSG"
      fi
      return 0
   fi

   if [ "$qubes_vm_persistence" = "none" ]; then
      local MSG="\
<p>$warrant_canary_check_link: Skipping in DispVM, ok.</p>"
      if [ "$verbose" -ge "1" ]; then
         $output_x ${output_opts[@]} --messagex --typex "info" --message "$MSG"
         $output_cli ${output_opts[@]} --messagecli --typecli "info" --message "$MSG"
      fi
      return 0
   fi

    local canary_recommendation="\
See folder <code>/var/lib/canary/</code>.
<br />
* <code>/var/lib/canary/canary-download-output.txt</code><br />
* <code>/var/lib/canary/canary.txt.embed.sig</code><br />
<br />
Check system clock. Recommended to check warrant canary manually."

    if ! leaprun -- check-warrant-canary &>/dev/null ; then
        local MSG="\
<p>$warrant_canary_check_link: systemd unit <code>canary</code> not running.</p>"
        if [ "$verbose" -ge "1" ]; then
            $output_x ${output_opts[@]} --messagex --typex "info" --message "$MSG"
            $output_cli ${output_opts[@]} --messagecli --typecli "info" --message "$MSG"
        fi
        return 0
    fi

    export LC_TIME="C"
    export TZ="UTC"

    if ! test -d "/var/lib/canary" ; then
      canary_folder_permission_issues
      return 0
    fi

    if ! test -f "/var/lib/canary/canary-unixtime.txt" ; then
        local MSG="\
<p>$warrant_canary_check_link: file <code>/var/lib/canary/canary-unixtime.txt</code> does not exist yet.
<br />
$canary_recommendation<br />
<br />
If this warning happens only after boot or is transient it can be safely ignored.</p>"
        if [ "$verbose" -ge "1" ]; then
            $output_x ${output_opts[@]} --messagex --typex "warning" --message "$MSG"
            $output_cli ${output_opts[@]} --messagecli --typecli "warning" --message "$MSG"
            #EXIT_CODE="1"
        fi
        return 0
    fi

    local canary_unixtime_file_owner
    canary_unixtime_file_owner=$(stat -c "%U" -- "/var/lib/canary/canary-unixtime.txt")
    if [ ! "$canary_unixtime_file_owner" = "canary" ]; then
      canary_folder_permission_issues
      return 0
    fi

   local canary_signed_unixtime_raw
   if ! canary_signed_unixtime_raw="$(timeout --kill-after="5" "5" cat -- "/var/lib/canary/canary-unixtime.txt")" ; then
      local MSG="\
<p>$warrant_canary_check_link: timeout reading file <code>/var/lib/canary/canary-unixtime.txt</code>.
<br />
$canary_recommendation</p>"
      if [ "$verbose" -ge "1" ]; then
         $output_x ${output_opts[@]} --messagex --typex "error" --message "$MSG"
         $output_cli ${output_opts[@]} --messagecli --typecli "error" --message "$MSG"
         EXIT_CODE="1"
      fi
   fi

   local actual_string_length
   local max_string_length=10
   actual_string_length="${#canary_signed_unixtime_raw}"

   if [ ! "$actual_string_length" = "$max_string_length" ]; then
      local MSG="<p><b>$warrant_canary_check_link: Unexpected string length of <code>canary_signed_unixtime_raw</code> variable</b> (expected: <code>$actual_string_length</code> max: <code>$max_string_length</code>).
<br />
$canary_recommendation</p>"
      if [ "$verbose" -ge "1" ]; then
         $output_x ${output_opts[@]} --messagex --typex "warning" --message "$MSG"
         $output_cli ${output_opts[@]} --messagecli --typecli "warning" --message "$MSG"
         EXIT_CODE="1"
      fi
      return 0
   fi

   local canary_signature_unixtime_sanetized
   canary_signature_unixtime_sanetized="$(/usr/bin/sanitize-string -- "$max_string_length" "$canary_signed_unixtime_raw")"

   if [[ "$canary_signature_unixtime_sanetized" != *[!0-9]* ]]; then
      true "$FUNCNAME: canary_signature_unixtime_sanetized is strictly numeric."
   else
      local MSG="\
<p>$warrant_canary_check_link: contents of file <code>/var/lib/canary/canary-unixtime.txt</code> are not numeric.
<br />
$canary_recommendation</p>"
      if [ "$verbose" -ge "1" ]; then
         $output_x ${output_opts[@]} --messagex --typex "warning" --message "$MSG"
         $output_cli ${output_opts[@]} --messagecli --typecli "warning" --message "$MSG"
         EXIT_CODE="1"
      fi
      return 0
   fi

   local canary_download_unixtime canary_download_human_readable
   if [ -f /var/lib/canary/canary_last_done ]; then
      canary_download_unixtime="$(cat -- /var/lib/canary/canary_last_done)" || true
      canary_download_human_readable="$(date --utc --date "@${canary_download_unixtime}")" || true
   fi

   local canary_signature_unixtime_human_readable current_unixtime current_human_readable
   local maximum_age canary_expiration_unixtime canary_expiration_human_readable

   canary_signature_unixtime_human_readable="$(date --utc --date "@${canary_signature_unixtime_sanetized}")"

   current_unixtime="$(date --utc "+%s")"
   current_human_readable="$(date --utc --date "@${current_unixtime}")"

   ## 4 weeks = 2419200
   maximum_age=2419200
   canary_expiration_unixtime=$(( $canary_signature_unixtime_sanetized + $maximum_age ))

   canary_expiration_human_readable="$(date --utc --date "@${canary_expiration_unixtime}")"

   local MSG="\
<p>$warrant_canary_check_link: Debugging information:
<br />Canary Download Time  : <code>$canary_download_human_readable</code>
<br />Current Time          : <code>$current_human_readable</code>
<br />Canary Signature Time : <code>$canary_signature_unixtime_human_readable</code>
<br />Canary Expiration Time: <code>$canary_expiration_human_readable</code></p>"
   if [ "$verbose" -ge "1" ]; then
      $output_x ${output_opts[@]} --messagex --typex "info" --message "$MSG"
      $output_cli ${output_opts[@]} --messagecli --typecli "info" --message "$MSG"
   fi

   if [ "$current_unixtime" -gt "$canary_expiration_unixtime" ]; then
      local MSG="<p>$warrant_canary_check_link: Stale.
<br />
$canary_recommendation</p>"
      if [ "$verbose" -ge "1" ]; then
         $output_x ${output_opts[@]} --messagex --typex "warning" --message "$MSG"
         $output_cli ${output_opts[@]} --messagecli --typecli "warning" --message "$MSG"
         EXIT_CODE="1"
      fi
      return 0
   fi

   local MSG="<p>$warrant_canary_check_link: Ok.</p>"
   if [ "$verbose" -ge "1" ]; then
      $output_x ${output_opts[@]} --messagex --typex "info" --message "$MSG"
      $output_cli ${output_opts[@]} --messagecli --typecli "info" --message "$MSG"
   fi

   return 0
}
