#!/bin/bash

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

set -e
if /usr/libexec/helper-scripts/debug-kicksecure-enabled; then
  set -x
fi

true "$0: START"

user_list=()
user_list_already_loaded='false'

load_user_list() {
   local user_list_str

   if [ "${user_list_already_loaded}" = 'true' ]; then
      return 0
   fi

   if ! user_list_str="$(/usr/libexec/helper-scripts/get-user-list)"; then
      printf "%s\n" "$0: ERROR: Failed to get user list!" >&2
      return 1
   fi
   readarray -t user_list <<< "$user_list_str" || return 1

   user_list_already_loaded='true'
}

command_not_found_sources_list_fix() {
   if [ -f "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_1" ]; then
      return 0
   fi

   if [ ! -e /etc/apt/sources.list ]; then
      ## https://forums.whonix.org/t/command-not-found-warningcould-not-open-file-etc-apt-sources-list/7903
      touch /etc/apt/sources.list || true
   fi

   mkdir --parents "/var/lib/whonix/do_once"
   touch "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_1"
}

command_not_found_permission_fix() {
   if [ -f "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_1" ]; then
      return 0
   fi

   if [ -f /var/lib/command-not-found/commands.db ]; then
      ## https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=917455
      chmod o+r /var/lib/command-not-found/commands.db || true
   fi

   mkdir --parents "/var/lib/whonix/do_once"
   touch "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_1"
}

bisq_desktop_directories_workaround() {
   if [ ! -f /usr/share/whonix/marker ]; then
      return 0
   fi

   if [ -f "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_1" ]; then
      return 0
   fi

   local user_name qubes_vm_name
   user_name="user"
   if test -f "/home/$user_name/.local/share/Bisq/btc_mainnet/tor/tor" ; then
      return 0
   fi
   if [ ! -d "/home/$user_name" ]; then
      return 0
   fi
   if ! id "$user_name" >&/dev/null ; then
      return 0
   fi

   if command -v qubesdb-read >&/dev/null; then
      qubes_vm_name="$(qubesdb-read /name)" || return 0
   fi
   if test -f /run/qubes/this-is-templatevm ; then
      return 0
   fi
   ## Avoid running in Qubes DVM Template.
   ## https://phabricator.whonix.org/T726
   if printf '%s\n' "$qubes_vm_name" | grep -- "-dvm" >/dev/null 2>/dev/null; then
      return 0
   fi

   sudo --non-interactive -u "$user_name" mkdir -p "/home/$user_name/.local/share/Bisq/btc_mainnet/tor" || true
   sudo --non-interactive -u "$user_name" touch "/home/$user_name/.local/share/Bisq/btc_mainnet/tor/tor" || true

   mkdir --parents "/var/lib/whonix/do_once"
   touch "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_1"
}

locales_fix() {
   if [ -f "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_1" ]; then
      return 0
   fi

   ## https://github.com/QubesOS/qubes-issues/issues/4889

   local search replace file_name etc_locale_gen_lines

   command -v str_replace >/dev/null

   search="# en_US.UTF-8 UTF-8"
   replace="en_US.UTF-8 UTF-8"
   file_name="/etc/locale.gen"

   if ! command -v locale-gen &>/dev/null ; then
      ## If the locale-gen program is not available, do not attempt to fix this.
      return 0
   fi

   if ! test -f "$file_name" ; then
      ## If user deleted that file, do not attempt to fix this.
      ## Could be on purpose.
      return 0
   fi

   etc_locale_gen_lines="$(cat -- "$file_name" | grep --invert-match -- '\#' | grep --invert-match -- '^$')" || true

   if ! [ "$etc_locale_gen_lines" = "" ]; then
      ## If file /etc/locale.gen is already non-empty, i.e. has an entry other
      ## blank lines or comments (lines starting with "#") then this should not be needed.
      return 0
   fi

   str_replace "$search" "$replace" "$file_name" || true

   ## Using LANG=C because locale-gen is a perl script and as long as this is
   ## not fixed it would show a warning confusing for users:
   ## "perl: warning: Setting locale failed."
   ## LANG=C only applies to the locale-gen script. Not to the end result of locale-gen.
   ## LANG=C might not be used if already using LC_ALL=C.
   LC_ALL=C LANG=C locale-gen || true

   mkdir --parents "/var/lib/whonix/do_once"
   touch "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_1"
}

zsh_migration() {
   local do_once_folder do_once_file
   if test -f /run/qubes/this-is-appvm ; then
      do_once_folder="/usr/local/var/lib/kicksecure/do_once"
   else
      do_once_folder="/var/lib/kicksecure/do_once"
   fi
   do_once_file="${do_once_folder}/${FUNCNAME[0]}_version_1"

   if [ -f "$do_once_file" ]; then
      return 0
   fi

   local user_name
   user_name="user"
   ## https://github.com/Kicksecure/desktop-config-dist/blob/master/etc/skel/.zshrc
   if test -f "/home/$user_name/.zshrc" ; then
      return 0
   fi
   if [ ! -d "/home/$user_name" ]; then
      return 0
   fi
   if ! id "$user_name" >&/dev/null ; then
      return 0
   fi

   sudo --non-interactive -u "$user_name" touch "/home/$user_name/.zshrc" || true

   mkdir --parents "$do_once_folder"
   touch "$do_once_file"
}

## Enables multiline-paste configuration for all active users.
qterminal_confirm_multiline_paste() {
   if [ -f "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_2" ]; then
      return 0
   fi

   local user_entry config_file config_file_contents

   load_user_list || return 1
   for user_entry in "${user_list[@]}"; do
      config_file="/home/${user_entry}/.config/qterminal.org/qterminal.ini"
      if ! [ -f "${config_file}" ]; then
         continue
      fi
      config_file_contents="$(cat -- "${config_file}")"
      if grep '^ConfirmMultilinePaste=false$' <<< "${config_file_contents}" >/dev/null; then
         # shellcheck disable=SC2001
         config_file_contents="$(sed 's/^ConfirmMultilinePaste=false$/ConfirmMultilinePaste=true/' <<< "${config_file_contents}")"
         printf '%s\n' "${config_file_contents}" | sponge -- "${config_file}"
      fi
   done

   mkdir --parents "/var/lib/whonix/do_once"
   touch "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_2"
}

## Fixes an issue where QTerminal attempts to save its bookmarks file in the
## home folder of a user account other than the account QTerminal is
## running as.
qterminal_bookmarks_file() {
   if [ -f "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_2" ]; then
      return 0
   fi

   local user_entry config_file

   load_user_list || return 1
   for user_entry in "${user_list[@]}"; do
      config_file="/home/${user_entry}/.config/qterminal.org/qterminal.ini"
      if ! [ -f "${config_file}" ]; then
         continue
      fi
      sed -i '/BookmarksFile=\/home\/user\/.config\/qterminal.org\/qterminal_bookmarks.xml/d' "${config_file}"
   done

   mkdir --parents "/var/lib/whonix/do_once"
   touch "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_2"
}

## Fixes removable media automount being enabled by default in pcmanfm-qt
## (this is a security risk)
pcmanfm_qt_removable_media_automount() {
   if [ -f "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_2" ]; then
      return 0
   fi
   local user_entry config_file config_file_variant_list config_file_variant

   load_user_list || return 1
   for user_entry in "${user_list[@]}"; do
      config_file_variant_list=(
         'lxqt'
         'default'
      )
      for config_file_variant in "${config_file_variant_list[@]}"; do
         config_file="/home/${user_entry}/.config/pcmanfm-qt/${config_file_variant}/settings.conf";
         if ! [ -f "${config_file}" ]; then
            continue
         fi
         sed -i 's/^MountOnStartup=true$/MountOnStartup=false/' "${config_file}"
         sed -i 's/^MountRemovable=true$/MountRemovable=false/' "${config_file}"
      done
   done

   mkdir --parents "/var/lib/whonix/do_once"
   touch "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_2"
}

## Fixes the default archiver being xarchiver (which isn't installed by
## default)
pcmanfm_qt_archiver() {
   if [ -f "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_2" ]; then
      return 0
   fi

   load_user_list || return 1
   for user_entry in "${user_list[@]}"; do
      config_file_variant_list=(
         'lxqt'
         'default'
      )
      for config_file_variant in "${config_file_variant_list[@]}"; do
         config_file="/home/${user_entry}/.config/pcmanfm-qt/${config_file_variant}/settings.conf";
         if ! [ -f "${config_file}" ]; then
            continue
         fi
         sed -i 's/^Archiver=xarchiver$/Archiver=lxqt-archiver/' "${config_file}"
      done
   done

   mkdir --parents "/var/lib/whonix/do_once"
   touch "/var/lib/whonix/do_once/${FUNCNAME[0]}_version_2"
}

## Removes insecure MOK keys that were accidentally shipped in installation
## images previously, but only if it is safe to do so.
##
## Note that this function CANNOT be placed in either legacy-dist.preinst or
## legacy-dist.postinst. If the user has a vulnerable key enrolled in their
## firmware, starts the process of resetting the MOK keys, but then generates
## new keys before rebooting and finishing the reset process, helper-scripts'
## 'check-image-builtin-mok' script will detect what it thinks is a
## vulnerable-but-not-enrolled key. What *should* be done in this situation is
## the key should be deleted, but if the deletion logic is in a package
## maintainer script, it won't be run again to remove the new keys. This will
## result in a confusing systemcheck warning about needing to upgrade
## legacy-dist.
##
## Theoretically, we could allow users to generate their new MOK keys after
## starting a MOK reset but before finishing it. Doing so would require saving
## a hash of the old insecure key somewhere so that we could tell that the new
## key was a different key. This probably isn't a good idea though, because if
## the user generates a new key using the shim-enroll-mok helper, the new key
## creation request will override the pending MOK reset request. Then when the
## user reboots and enrolls the newly generated key, the vulnerable key will
## still be present in the MOK store. If we relied on the hash trick above,
## 'check-image-builtin-mok' would then see that the existing key is
## different, and assume the system is safe, when in reality it is still
## vulnerable.
##
## We could work around *that* too by dumping the MOK store and checking to
## see if any of the keys are the previously detected vulnerable key, but
## it's far simpler if we just require that new MOK keys are only generated
## after the reset is complete. Putting this function here implements that.
secure_boot_mok_cleanup() {
   local check_image_builtin_mok_retcode

   check_image_builtin_mok_retcode='0'
   ## Note that 'check-image-builtin-mok' handles the do_once mechanism
   ## itself.
   /usr/libexec/helper-scripts/check-image-builtin-mok || check_image_builtin_mok_retcode="$?"
   if [ "${check_image_builtin_mok_retcode}" = '1' ]; then
      ## Vulnerable key is present but may be safely wiped, delete them

      # shellcheck source=../../../../helper-scripts/usr/sbin/shim-signed-mok-setup
      source /usr/sbin/shim-signed-mok-setup
      dkms_mok_variables_set

      safe-rm --force -- "${dkms_mok_public_file}"
      safe-rm --force -- "${dkms_mok_private_file}"
   fi
}

if ! [ "$(id -u)" = "0" ]; then
   echo "$0 ERROR: must run as root!" >&2
   exit 1
fi

## Fix for:
## dpkg-maintscript-helper: error: couldn't identify the package
[ -n "$DPKG_MAINTSCRIPT_PACKAGE" ] || DPKG_MAINTSCRIPT_PACKAGE="legacy-dist"
[ -n "$DPKG_MAINTSCRIPT_NAME" ] || DPKG_MAINTSCRIPT_NAME="preinst"
export DPKG_MAINTSCRIPT_PACKAGE DPKG_MAINTSCRIPT_NAME
timeout --kill-after 60 60 /var/lib/dpkg/info/legacy-dist.preinst install || true

## automate Tor permission fix
## https://www.whonix.org/wiki/Tor#Permissions_Fix
## https://forums.whonix.org/t/tor-error-your-tor-config-file-contains-at-least-one-error-var-lib-tor-tor-cannot-be-read-permission-denied/6200
## cat -- /var/lib/dpkg/info/tor.postinst | grep -- chown
## chown debian-tor:debian-tor /var/lib/tor
## chown debian-tor:adm /var/log/tor
if [ -d "/var/lib/tor" ]; then
   chown --recursive debian-tor:debian-tor /var/lib/tor || true
fi
if [ -d "/var/log/tor" ]; then
   chown --recursive debian-tor:adm /var/log/tor || true
fi

command_not_found_sources_list_fix || true

command_not_found_permission_fix || true

bisq_desktop_directories_workaround || true

locales_fix || true

zsh_migration || true

qterminal_confirm_multiline_paste || true

qterminal_bookmarks_file || true

pcmanfm_qt_removable_media_automount || true

pcmanfm_qt_archiver || true

secure_boot_mok_cleanup || true

true "$0: END"
