diff --git a/server/README.md b/server/README.md index 5edc5cb..7bd2437 100644 --- a/server/README.md +++ b/server/README.md @@ -57,6 +57,7 @@ undoes that. - `shell/` - the shell configuration, `~/.zshrc` and `~/.zshenv`, which is where the prompt is set. - `resources/` - the copies the cleanup restores from: the shell configuration and the four text files. - `scripts/make_files.py` - builds the resources. +- `scripts/deploy.sh` - deploys the cleanup to the server and installs it. - `scripts/install_restore_task.ps1` - installs the scheduled task. The resources are built from the website's pages and the shell configuration: @@ -65,7 +66,14 @@ The resources are built from the website's pages and the shell configuration: ## Installing the cleanup on the server -Copy `server/scripts` and `server/resources` to the server and run this in an elevated PowerShell: + server/scripts/deploy.sh + +The script logs in as `Administrator` - whose shell is a Windows one - copies the scripts and the resources to the +Administrator's home directory and runs the installer there. It uses the key the website uses, which is authorized +for the Administrator account as well, and checks the host key against the one the website pins. `--uninstall` +removes the task again. + +The installer can also be run by hand, in an elevated PowerShell on the server: powershell -ExecutionPolicy Bypass -File .\scripts\install_restore_task.ps1 diff --git a/server/scripts/deploy.sh b/server/scripts/deploy.sh new file mode 100755 index 0000000..fb457fc --- /dev/null +++ b/server/scripts/deploy.sh @@ -0,0 +1,62 @@ +#!/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. +set -euo pipefail + +HOST=nowhere.wirs.ing +USER=Administrator +KEYFILE='' +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 [ -z "$KEYFILE" ]; then + # The key the website uses is authorized for the Administrator account as well. + KEYFILE=$(mktemp) + chmod 600 "$KEYFILE" + temporary+=("$KEYFILE") + 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' > "$KEYFILE" +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 + +ssh=(ssh -i "$KEYFILE" -o UserKnownHostsFile="$known" -o StrictHostKeyChecking=yes "$USER@$HOST") +scp=(scp -i "$KEYFILE" -o UserKnownHostsFile="$known" -o StrictHostKeyChecking=yes) + +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"