#!/bin/bash

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

set -e
set -o errtrace
set -o pipefail

NAME=bootclockrandomization
DIR=/run/$NAME
FAIL_FILE=$DIR/fail
SUCCESS_FILE=$DIR/success

log() {
   echo "$@"
}

error_handler() {
   local exit_code="$?"
   touch "$FAIL_FILE"
   log "ERROR: exit_code: $exit_code | BASH_COMMAND: $BASH_COMMAND"
   exit 1
}

trap "error_handler" ERR

if [ "$(id -u)" != "0" ]; then
   log "ERROR: $0 be run as root (sudo)! Use: sudo $0"
   exit 3
fi

get_random_time() {
   ## Get a random 0 or 1.
   ## Will use this to decide to use plus or minus.
   ##
   ## Thanks to
   ## http://linux.byexamples.com/archives/128/generating-random-numbers/
   ZERO_OR_ONE="$(( 0+($(od -An -N2 -i /dev/random) )%(0+2) ))"

   ## Create a random number between 0 and $delay_plus_or_minus.
   ## delay_plus_or_minus is  30 for clock-random-manual.
   ## delay_plus_or_minus is 180 for bootclockrandomization.
   DELAY="$(( $(od -An -N2 -i /dev/random)%($delay_plus_or_minus-0+1) ))"

   ## Create a random number between 0 and 999999999.
   ##
   ## Thanks to
   ## https://stackoverflow.com/questions/22887891/how-can-i-get-a-random-dev-random-number-between-0-and-999999999-in-bash
   NANOSECONDS="$(shuf -i0-999999999 -n1 --random-source=/dev/random)"

   ## Examples NANOSECONDS:
   ## 117752805
   ## 38653957

   ## Add leading zeros, because `date` expects 9 digits.
   NANOSECONDS="$(printf '%0*d\n' 9 "$NANOSECONDS")"

   ## Using
   ## printf '%0*d\n' 9 "38653957"
   ##  38653957
   ## becomes
   ## 038653957

   ## Examples NANOSECONDS:
   ## 117752805
   ## 038653957

   if [ "$ZERO_OR_ONE" = "0" ]; then
      PLUS_OR_MINUS="-"
   elif [ "$ZERO_OR_ONE" = "1" ]; then
      PLUS_OR_MINUS="+"
   else
      touch "$FAIL_FILE"
      log "ERROR: ZERO_OR_ONE is neither 0 nor 1, it's: $ZERO_OR_ONE"
      log "       Please report this bug!"
      return 2
   fi

   log "$PLUS_OR_MINUS $DELAY $NANOSECONDS"

   ## OLD_TIME will be set when called by clock-random-manual-cli.
   ## OLD_TIME will not be set when called by bootclockrandomization.
   if [ "$OLD_TIME" = "" ]; then
      OLD_TIME="$(date)"
      true "Setting OLD_TIME to $OLD_TIME."
      OLD_TIME_NANOSECONDS="$(date +%s.%N)"
      OLD_UNIXTIME="$(date +%s)"
   else
      true "OLD_TIME already set to $OLD_TIME."
      OLD_TIME_NANOSECONDS="$(date --date "@$OLD_TIME" +%s.%N)"
      OLD_UNIXTIME="$(date --date "@$OLD_TIME" +%s)"
   fi

   NEW_TIME="$(( $OLD_UNIXTIME $PLUS_OR_MINUS $DELAY ))"
   NEW_TIME_HUMAN="$(date --date "@$NEW_TIME")"
}
