#!/bin/bash

build() {
    if ! pacman -Qi tinyssh >/dev/null 2>&1; then
        error "Package tinyssh not installed"
        return 1
    fi

    declare -F add_busybox >/dev/null || . /usr/lib/initcpio/functions.d/systemd-extras

    add_busybox || return $?

    local encrypted keydir="${SD_TINYSSH_KEYDIR:-/etc/tinyssh/sshkeydir}"
    if [[ -r "$keydir/ed25519.pk" && -r "$keydir/.ed25519.sk.enc" ]]; then
        add_file "$keydir/ed25519.pk" /etc/credstore/ed25519.pk
        add_file "$keydir/.ed25519.sk.enc" /etc/credstore.encrypted/.ed25519.sk
        encrypted=Encrypted
    elif [[ -r "$keydir/ed25519.pk" && -r "$keydir/.ed25519.sk" ]]; then
        add_file "$keydir/ed25519.pk" /etc/credstore/ed25519.pk
        add_file "$keydir/.ed25519.sk" /etc/credstore/.ed25519.sk
    elif [[ -z "$SD_TINYSSH_KEYDIR" && -r /etc/ssh/ssh_host_ed25519_key ]]; then
        tinyssh-convert "$BUILDROOT/etc/credstore" </etc/ssh/ssh_host_ed25519_key
        warning "Reusing the host keys from the regular operating environment poses a security risk."
        warning "See https://github.com/wolegis/mkinitcpio-systemd-extras/wiki/TinySSH-server for details."
    else
        error "Missing SSH host key"
        return 1
    fi

    add_systemd_unit tinyssh@.socket
    add_systemd_unit tinyssh@.service

    # enable tinysshd listening on TCP port $SD_TINYSSH_PORT (if set to legal port number)
    SD_TINYSSH_PORT="${SD_TINYSSH_PORT:-22}"
    if (( SD_TINYSSH_PORT < 1 || SD_TINYSSH_PORT > 65535 )); then
        error "Illegal value SD_TINYSSH_PORT=$SD_TINYSSH_PORT"
        return 1
    fi
    add_symlink "/etc/systemd/system/sysinit.target.wants/tinyssh@$SD_TINYSSH_PORT.socket" /usr/lib/systemd/system/tinyssh@.socket

    local drop_in=(
        '[Unit]'
        'Requires=systemd-networkd.service'
        'After=systemd-networkd.service'
        'DefaultDependencies=no'
    )
    printf "%s\n" "${drop_in[@]}" | add_systemd_drop_in "tinyssh@$SD_TINYSSH_PORT.socket" override

    drop_in=(
        "[Unit]"
        "DefaultDependencies=no"
        ""
        "[Service]"
        "ExecStart="
        "ExecStart=-/usr/bin/tinysshd ${SD_TINYSSH_COMMAND:+-e '${SD_TINYSSH_COMMAND}' }\${CREDENTIALS_DIRECTORY}"
        "LoadCredential=ed25519.pk"
        "LoadCredential${encrypted}=.ed25519.sk"
    )
    printf "%s\n" "${drop_in[@]}" | add_systemd_drop_in tinyssh@.service override

    SD_TINYSSH_AUTHORIZED_KEYS=${SD_TINYSSH_AUTHORIZED_KEYS:-/root/.ssh/authorized_keys}
    if [[ ! -r "$SD_TINYSSH_AUTHORIZED_KEYS" ]]; then
        error "Keys file '$SD_TINYSSH_AUTHORIZED_KEYS' does not exist (or not readable)"
        return 1
    fi
    add_dir /root/.ssh
    grep '^ssh-ed25519 ' "$SD_TINYSSH_AUTHORIZED_KEYS" >"$BUILDROOT/root/.ssh/authorized_keys"
    if [[ -s "$BUILDROOT/root/.ssh/authorized_keys" ]]; then
        chmod 600 "$BUILDROOT/root/.ssh/authorized_keys"
        chmod 700 "$BUILDROOT/root/.ssh"
    else
        error "No ED25519 key found for root"
        return 1
    fi

    if [[ -z "$SD_TINYSSH_COMMAND" && -r "$SD_TINYSSH_SCRIPT" ]]; then
        add_file "$SD_TINYSSH_SCRIPT" /root/.profile 600
    fi
}

help() {
    cat <<__EOF_HELP__
This hook enables tinyssh during the initramfs phase. It is only applicable for
a systemd based intramfs phase, i.e. hook 'systemd' must be given in the HOOKS
array in mkinitcpio.conf.

See https://github.com/wolegis/mkinitcpio-systemd-extras/wiki/TinySSH-server
for details.

The hook copies all files and binaries required by tinyssh to the initramfs
image and enables listening TCP port 22 (or some other).

Host keys are copied from \$SD_TINYSSH_KEYDIR (default /etc/tinyssh/sshkeydir).
A secret host key '.ed25519.sk.enc' encrypted with systemd-creds is preferred.
As a last resort the OpenSSH host key /etc/ssh/ssh_host_ed25519_key is
converted on the fly.  This last option requires python to be installed.

By default tinyssh presents the busybox shell after successful login. Two
variables can be used to alter this behavior:

SD_TINYSSH_COMMAND defines a shell command. The string is appended to 'sh -c',
i.e. it may contain blanks, quotes and all kinds of special characters that are
interpreted by the shell.  Example: To allow to unlock LUKS encrypted volumes
from remote (but nothing else, especially no shell access) set:
SD_TINYSSH_COMMAND="systemd-tty-ask-password-agent --query --watch"

SD_TINYSSH_SCRIPT defines a file with shell commands that are executed before
the interactive shell is presented. Example: To allow to unlock LUKS encrypted
volumes from remote but also escape to an interactive shell with CTRL-C specify
a file that contains:
systemd-tty-ask-password-agent --query --watch

SD_TINYSSH_COMMAND takes precedence.

Set SD_TINYSSH_PORT to specify a port other than 22.

Set SD_TINYSSH_AUTHORIZED_KEYS to specify a keys file other than
/root/.ssh/authorized_keys.

If required the above mentioned variables must be set in /etc/mkinitcpio.conf.
__EOF_HELP__
}
