#!/bin/bash

set -o errexit
set -o nounset
set -o pipefail
set -o errtrace
shopt -s inherit_errexit
shopt -s shift_verbose

# shellcheck source=../../../../kicksecure/helper-scripts/usr/libexec/helper-scripts/has.sh
## Sibling repo: absent in an isolated CI checkout, so shellcheck cannot follow
## it there. The source= path above still documents where it lives.
##
## TODO: Don't run shellcheck unless in a full derivative-maker source tree.
# shellcheck disable=SC1091
source /usr/libexec/helper-scripts/has.sh

temp_dir="${temp_dir:-}"

preparation() {
   if [ ! "${temp_dir}" = "" ]; then
      true "INFO: custom temp_dir"
      return 0
   fi
   temp_dir="$(mktemp --directory)"
   mkdir -p "${temp_dir}/keys"
}

no_ssh_found_exit() {
   ${output_command} "ERROR: ssh client not installed" >&2
   ${output_command} ""
   ${output_command} "INFO: To install:"
   ${output_command} ""
   ${output_command} "sudo apt update"
   ${output_command} "sudo apt install --no-install-recommends openssh-client"
   ${output_command} ""
   ${output_command} "ERROR: Stop." >&2
   exit 101
}

hostname_malicious() {
   ${output_command} "File ${temp_dir}/qubes-remote-support/keys/hostname might be malicious." >&2
   ${output_command} "Do not look at it unless you know what you are doing." >&2
}

if test -o xtrace ; then
   output_command=true
else
   ## "%s\n" is intentionally unquoted, so that it functions correctly after
   ## word-splitting.
   output_command="printf %s\n"
fi

${output_command} "INFO: Starting Qubes Remote Support Provider."
${output_command} "INFO: This tool is supposed to be run by those who wish to provide remote support."
${output_command} "INFO: Setting up... This will take a moment..."

if test -d ~/.ssh ; then
   ${output_command} "ERROR: Folder ~/.ssh already exists" >&2
   ${output_command} ""
   ${output_command} "INFO: Highly recommended to update your ~/.ssh folder!"
   ${output_command} ""
   ${output_command} "INFO: To move the existing ~/.ssh folder out of the way:"
   ${output_command} ""
   ${output_command} "mv --backup ~/.ssh ~/.ssh_my_backup"
   ${output_command} ""
   ${output_command} "ERROR: Stop." >&2
   exit 100
fi

if test -h /usr/bin/ssh ; then
   ## Whonix
   if ! has /usr/bin/ssh.anondist-orig ; then
      no_ssh_found_exit
   fi
else
   ## Non-Whonix or no uwt installed.
   if ! has ssh ; then
      no_ssh_found_exit
   fi
fi

my_vm_name="$(qubesdb-read /name)"

preparation
cd "${temp_dir}"
mkdir -p "${temp_dir}/qubes-remote-support"
## Test if could create file.
touch "${temp_dir}/qubes-remote-support/remote-support-keys.tar.gz"
## Test if could delete files.
safe-rm -- "${temp_dir}/qubes-remote-support/remote-support-keys.tar.gz"

${output_command} "INFO: Ask the remote support receiver for the wormhole code phrase and enter it below."

## input wormhole code and press enter
## to confirm, press y and press enter
wormhole receive
## Example output including user interaction:
# Enter receive wormhole code: 8-reproduce-virus
#  (note: you can use <Tab> to complete words)
# Waiting for sender...
# Receiving file (817 Bytes) into: remote-support-keys.tar.gz
# ok? (y/N): y
# Receiving (->relay:tcp:magic-wormhole-transit.debian.net:4001)..
# 100%|| 817/817 [00:00<00:00, 2.49MB/s]
# Received file written to remote-support-keys.tar.gz

## As seen in output above, wormhole points out the file size beforehand.

if ! test -f "${temp_dir}/remote-support-keys.tar.gz" ; then
   ${output_command} "ERROR: error receiving file!"
   ${output_command} "ERROR: file ${temp_dir}/remote-support-keys.tar.gz does not exist!"
   exit 102
fi

${output_command} "INFO: Success, received remote support archive file '${temp_dir}/remote-support-keys.tar.gz'."
${output_command} "INFO: (That file allows a Qubes Remote Support Provider to connect to this machine.)"
${output_command} "INFO: (No need to do anything with that file.)"
${output_command} "INFO: Setting up... This will take a moment..."

## Debugging.
if test -o xtrace ; then
   ls -la
   ls -la remote-support-keys.tar.gz
fi

file_size="$(stat --printf="%s" remote-support-keys.tar.gz)"
## example output:
## 818

if [ "${file_size}" -ge 1000 ]; then
   ${output_command} "ERROR: file_size of ${temp_dir}/remote-support-keys.tar.gz larger than 1000. file_size: ${file_size}"
   exit 102
fi

if test -o xtrace ; then
   tar --warning=no-timestamp -xvf remote-support-keys.tar.gz -C "${temp_dir}/qubes-remote-support"
else
   tar --warning=no-timestamp -xvf remote-support-keys.tar.gz -C "${temp_dir}/qubes-remote-support" >/dev/null
fi

## Debugging.
if test -o xtrace ; then
   ls -la
   ls -la "${temp_dir}/qubes-remote-support/keys"
fi

hostname="$(cat "${temp_dir}/qubes-remote-support/keys/hostname")"
## Example hostname:
## pp3nxkdbekhaac6r57blbrgniramltvriuukw6g6vqpbudymk33mpnyd.onion

string_length_ofhostname="${#hostname}"
if [ ! "${string_length_ofhostname}" = "62" ]; then
   ${output_command} "ERROR: hostname string string is not 62. it is: ${string_length_ofhostname}" >&2
   hostname_malicious
   exit 200
fi
if ! [[ "${hostname}" =~ ^[.0-9a-zA-Z_-]+$ ]]; then
   ${output_command} "ERROR: hostname contains invalid character!" >&2
   hostname_malicious
   exit 201
fi
if ! [[ "${hostname}" == *.onion ]]; then
   ${output_command} "ERROR: hostname does not end with '.onion'!" >&2
   hostname_malicious
   exit 202
fi

## Rely on ssh for sanitation.
ssh_algorithm="$(cat "${temp_dir}/qubes-remote-support/keys/ssh_algorithm")"
## Example ssh_algorithm:
## ssh-ed25519

## Rely on ssh for sanitation.
ssh_fingerprint="$(cat "${temp_dir}/qubes-remote-support/keys/ssh_fingerprint")"
## Example ssh_fingerprint:
## AAAAC3NzaC1lZDI1NTE5AAAAICF7BLyxUHVzpwD9DVcG5+H+1TydgvcQlTQdKrXqNgFF

ssh_known_keys_line="${hostname} ${ssh_algorithm} ${ssh_fingerprint}"

mkdir -p ~/.ssh
## Rely on ssh for sanitation of id_ed25519.pub.
cp "${temp_dir}/qubes-remote-support/keys/id_ed25519.pub" ~/.ssh/
## Rely on ssh for sanitation of id_ed25519.
cp "${temp_dir}/qubes-remote-support/keys/id_ed25519" ~/.ssh/
printf '%s\n' "${ssh_known_keys_line}" > ~/.ssh/known_hosts
chmod 700 ~/.ssh
chmod 600 ~/.ssh/*

## example id_ed25519, do NOT reuse this:
## -----BEGIN OPENSSH PRIVATE KEY-----
## abcdefghijklmnopqrxtuvwxyz1234567890qwertyuiopasdfghjklzxcvbnm09876543
## 21!!!DO NOT REUSE THIS FOR ANYTHING THIS IS AN EXAMPLE ONLY !!!abcdefg
## hijklmnopqrstuvwxyz1234567890qwertyuiopasdfghjklzxcvbnm0987654321!!!DO
## NOT REUSE THIS FOR ANYTHING THIS IS AN EXAMPLE ONLY !!!abcdefghijklmno
## pqrstuvwxyz1234567890qwertyuiopasdfghjklzxcvbnm0987654321!!!DO NOT REU
## SE THIS FOR ANYTHI
## -----END OPENSSH PRIVATE KEY-----

## example id_ed25519.pub:
#ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAQnzajgqeriBIkCvQyR77nLZ92Xq+jy/50GXPlsp9LJ qubes-remote-support-receiver-auto-generated

${output_command} ""
${output_command} "Success. Please continue as instructed below."
${output_command} ""

${output_command} "INFO: To avoid confusion, it is advised your delete folder ~/QubesIncoming in sys-whonix if it exists. In most cases no such folder exists."
${output_command} "INFO: If there is nothing you need to backup, you could run the following command in sys-whonix:"
${output_command} ""
${output_command} "rm -rf ~/QubesIncoming"
${output_command} ""
${output_command} "INFO: When done, press enter to continue."
read -r
${output_command} ""

${output_command} "INFO: Will ask to copy 1.auth_private to sys-whonix."
true "INFO: In other words, will run the following command:"
true "qvm-copy ${temp_dir}/qubes-remote-support/keys/1.auth_private"
${output_command} "INFO: When Qubes dom0 asks, answer to copy to sys-whonix."
${output_command} "INFO: Press enter to continue."
read -r
${output_command} ""

## Example 1.auth_private contents:
## pp3nxkdbekhaac6r57blbrgniramltvriuukw6g6vqpbudymk33mpnyd:descriptor:x25519:CC2Z373LXU36QEKG5JIFCFMUDOYB73U26MZ6FAQDGLOWYQAGWBBA

## TODO: qvm-copy and a dom0 prompt is not very convenient.
##       Is there any elegant way to automate that?
##
## Rely on Tor for sanitation of 1.auth_private.
qvm-copy "${temp_dir}/qubes-remote-support/keys/1.auth_private"
${output_command} ""

${output_command} "INFO: Install authenticated Tor onion v3 service private key by running the following command in sys-whonix:"
${output_command} ""
${output_command} "sudo sourcefile=~/QubesIncoming/${my_vm_name}/1.auth_private anon-server-to-client-install"
${output_command} ""
${output_command} "INFO: When done, press enter to continue."
read -r
${output_command} ""

${output_command} "INFO: Do you want to SSH to '${hostname}'?"
${output_command} "INFO: Press enter to continue."
read -r
${output_command} ""

${output_command} "INFO: Trying SSH..."
${output_command} "INFO: Will keep trying to run the following command..."
${output_command} "ssh '${hostname}'"
${output_command} "INFO: This can take up to 10 minutes."

counter=0

## Required 13 retries during testing until onion v3 service was ready.
## Took 3:30 minutes.
## Another attempt:
## Required 33 retries during testing until onion v3 service was ready.
## Took 5:30 minutes.
while true ; do
   counter="$((counter + 1))"
   if [ "${counter}" -ge "500" ]; then
      ${output_command} "ERROR: SSH connection unsuccessful!"
      exit 1
   fi
   if test -o xtrace ; then
      if ssh "${hostname}" ; then
         true "INFO: SSH success."
         break
      else
         sleep 10
      fi
   else
      if ssh "${hostname}" 2>/dev/null ; then
         true "INFO: SSH success."
         break
      else
         sleep 10
      fi
   fi
done
