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

    local warn keydir="${SD_TINYSSH_KEYDIR:-/etc/tinyssh/sshkeydir}"
    if [[ -r "$keydir/ed25519.pk" && -r "$keydir/.ed25519.sk" ]]; then
        add_file "$keydir/ed25519.pk" /etc/tinyssh/sshkeydir/ed25519.pk
        add_file "$keydir/.ed25519.sk" /etc/tinyssh/sshkeydir/.ed25519.sk
        [[ -z "$SD_TINYSSH_KEYDIR" ]] && warn=true
    elif [[ -z "$SD_TINYSSH_KEYDIR" && -r /etc/ssh/ssh_host_ed25519_key ]]; then
        add_dir /etc/tinyssh
        tinyssh-convert "$BUILDROOT/etc/tinyssh/sshkeydir" </etc/ssh/ssh_host_ed25519_key
        warn=true
    else
        error "Missing SSH host key"
        return 1
    fi
    if [[ "$warn" ]]; then
        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."
    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 (or some other).  Host keys are either

 o  copied from $SD_TINYSSH_KEYDIR if they exist or

 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.

Option 2 and 3 are not taken into account when SD_TINYSSH_KEYDIR has been set.
If none of these options yield a server key 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.

Use SD_TINYSSH_KEYDIR to specify the location of a pair of tinyssh server keys
to be used in initramfs. Not using this variable causes a security warning.

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

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