#!/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 $?

    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}' }/etc/tinyssh/sshkeydir"
    )
    printf "%s\n" "${drop_in[@]}" | add_systemd_drop_in tinyssh@.service override

    if [[ -r /etc/tinyssh/sshkeydir/ed25519.pk && -r /etc/tinyssh/sshkeydir/.ed25519.sk ]]; then
        add_file /etc/tinyssh/sshkeydir/ed25519.pk
        add_file /etc/tinyssh/sshkeydir/.ed25519.sk
    elif [[ -r /etc/ssh/ssh_host_ed25519_key ]]; then
        add_dir /etc/tinyssh
        tinyssh-convert "$BUILDROOT/etc/tinyssh/sshkeydir" </etc/ssh/ssh_host_ed25519_key
    else
        error "Missing tinyssh host key"
        return 1
    fi

    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 within a systemd based initramfs.

It copies all files and binaries required by tinyssh to initramfs and enables
listening TCP port 22.  Host keys are either

 o  copied from /etc/tinyssh/sshkeydir if they exist or

 o  converted on the fly from the corresponding openssh ED25519 host key
    /etc/ssh/ssh_host_ed25519_key. This requires python to be installed.

If none of the two sources exists the hook aborts.

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

 o  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"

 o  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

Only one of the two variables is taken into account. 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__
}
