#!/bin/bash

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

    # make sure busybox (and thus sh) are present
    # (might have been already installed by some other hook, e.g. base)
    # (other busybox applets are added also because they allocate nearly no space in initramfs)
    if [[ ! -x "$BUILDROOT/usr/bin/busybox" ]]; then
        add_binary /usr/lib/initcpio/busybox /usr/bin/busybox
        local applet
        for applet in $(/usr/lib/initcpio/busybox --list); do
            add_symlink "/usr/bin/$applet" busybox
        done
    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}' }/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 tinysshd with systemd 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.

The variables must be set somewhere in /etc/mkinitcpio.conf.
__EOF_HELP__
}
