#!/usr/bin/env bash # Deploys the cleanup job to the shell server and installs it there. # # server/scripts/deploy.sh [-i KEYFILE] [-h HOST] [--uninstall] # # The job runs on the box as SYSTEM, never as the root user. The Administrator account sets it up; its shell is a # Windows one, so the commands we run there are Windows commands. # # The Administrator logs in with the personal key of the deployer, by default ~/.ssh/id_ed25519. The key of the # website never gets administrator rights: it only logs in as the root user. set -euo pipefail HOST=nowhere.wirs.ing USER=Administrator KEYFILE="$HOME/.ssh/id_ed25519" UNINSTALL=0 while [ $# -gt 0 ]; do case $1 in -i) KEYFILE=$2; shift 2 ;; -h) HOST=$2; shift 2 ;; --uninstall) UNINSTALL=1; shift ;; *) echo "usage: $(basename "$0") [-i KEYFILE] [-h HOST] [--uninstall]" >&2; exit 2 ;; esac done repo=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) server="$repo/server" remote='C:\Users\Administrator\kik' # where the installer is put, in the home of the Administrator remotePath='/c/Users\Administrator\kik' # the same place, as the file transfer sees it temporary=() if [ ! -f "$KEYFILE" ]; then echo "no key file for the login as $USER: $KEYFILE" >&2 exit 1 fi # The host key is the one the website pins, so that the deployment cannot be intercepted. expected=$(sed -n "s/.*const HOST_KEY = '\([^']*\)'.*/\1/p" "$repo/src/scripts/terminal.ts") known=$(mktemp) temporary+=("$known") trap 'rm -f "${temporary[@]}"' EXIT ssh-keyscan -t ed25519 "$HOST" > "$known" 2>/dev/null actual=$(ssh-keygen -lf "$known" | awk '{print $2}') if [ "$actual" != "$expected" ]; then echo "the host key of $HOST is $actual, but $expected is expected" >&2 exit 1 fi # The site logs in with the key in the authorized_keys of the user on the box, so the two have to be the same. site=$(mktemp) chmod 600 "$site" temporary+=("$site") boring=$(sed -n "s/.*const boringData = '\([^']*\)'.*/\1/p" "$repo/src/scripts/terminal.ts") printf '%s' "$boring" | base64 -d | tr 'A-Za-z' 'N-ZA-Mn-za-m' > "$site" public=$(ssh-keygen -y -f "$site" | awk 'NF {print $1" "$2}') if ! awk 'NF {print $1" "$2}' "$server/resources/.ssh/authorized_keys" | grep -qxF "$public"; then echo "the key in server/resources/.ssh/authorized_keys is not the one the website uses" >&2 exit 1 fi options=(-i "$KEYFILE" -o "UserKnownHostsFile=$known" -o StrictHostKeyChecking=yes) ssh=(ssh "${options[@]}" "$USER@$HOST") scp=(scp "${options[@]}") if [ "$UNINSTALL" = 1 ]; then "${ssh[@]}" "if exist $remote\\scripts\\install_restore_task.ps1 (powershell -NoProfile -ExecutionPolicy Bypass -File $remote\\scripts\\install_restore_task.ps1 -Uninstall) else (echo Nothing is installed.)" exit fi # The installer looks for the resources next to itself, so both directories go to the server. "${ssh[@]}" "if not exist $remote mkdir $remote" "${scp[@]}" -r "$server/scripts" "$server/resources" "$USER@$HOST:$remotePath/" "${ssh[@]}" "powershell -NoProfile -ExecutionPolicy Bypass -File $remote\\scripts\\install_restore_task.ps1" # The Administrator logs in with the key of the deployer, so that it is there after every deployment. keyline=$(ssh-keygen -y -f "$KEYFILE") blob=$(echo "$keyline" | awk 'NF {print $2}') "${ssh[@]}" "if not exist C:\\Users\\Administrator\\.ssh mkdir C:\\Users\\Administrator\\.ssh" "${ssh[@]}" "findstr /c:\"$blob\" C:\\Users\\Administrator\\.ssh\\authorized_keys >nul 2>&1 || echo $keyline >> C:\\Users\\Administrator\\.ssh\\authorized_keys"