#!/usr/bin/env bash
#
# bt-access - network access controls for ButtonTask.
#
# Usage:
#   bt-access status
#   bt-access icmp <on|off>
#   bt-access ssh <on|off>
#   bt-access ssh-port <port>
set -euo pipefail

err() { echo "bt-access: $*" >&2; exit 1; }

SSH_DROPIN="/etc/ssh/sshd_config.d/99-buttontask.conf"
SYSCTL_DROPIN="/etc/sysctl.d/99-buttontask-access.conf"

valid_port() {
    [[ "${1:-}" =~ ^[0-9]{1,5}$ ]] && [ "$1" -ge 1 ] && [ "$1" -le 65535 ]
}

ssh_unit() {
    if systemctl list-unit-files ssh.service &>/dev/null; then
        echo ssh.service
    elif systemctl list-unit-files sshd.service &>/dev/null; then
        echo sshd.service
    else
        echo ssh.service
    fi
}

ssh_port() {
    local port
    if command -v sshd >/dev/null 2>&1; then
        port="$(sshd -T 2>/dev/null | awk '$1 == "port" {print $2; exit}')"
        if valid_port "${port:-}"; then
            echo "$port"
            return 0
        fi
    fi
    port="$(awk 'tolower($1) == "port" {print $2; found=1} END {if (!found) print 22}' \
        /etc/ssh/sshd_config "$SSH_DROPIN" 2>/dev/null | tail -n1)"
    valid_port "${port:-}" && echo "$port" || echo 22
}

write_icmp() {
    local state="$1" value
    case "$state" in
        on) value=0 ;;
        off) value=1 ;;
        *) err "icmp expects on or off" ;;
    esac
    printf 'net.ipv4.icmp_echo_ignore_all=%s\n' "$value" > "$SYSCTL_DROPIN"
    sysctl -w "net.ipv4.icmp_echo_ignore_all=$value" >/dev/null
}

write_ssh_port() {
    local port="$1"
    valid_port "$port" || err "invalid ssh port"
    install -d -m 0755 "$(dirname "$SSH_DROPIN")"
    printf 'Port %s\n' "$port" > "$SSH_DROPIN"
    systemctl restart "$(ssh_unit)" >/dev/null 2>&1 || true
}

set_ssh() {
    local state="$1" unit
    unit="$(ssh_unit)"
    case "$state" in
        on)
            systemctl enable "$unit" >/dev/null 2>&1 || update-rc.d ssh defaults >/dev/null 2>&1 || true
            systemctl start "$unit" >/dev/null 2>&1 || service ssh start >/dev/null 2>&1 || true
            ;;
        off)
            systemctl stop "$unit" >/dev/null 2>&1 || service ssh stop >/dev/null 2>&1 || true
            systemctl disable "$unit" >/dev/null 2>&1 || update-rc.d -f ssh remove >/dev/null 2>&1 || true
            ;;
        *) err "ssh expects on or off" ;;
    esac
}

status() {
    local icmp ssh_state port unit
    icmp="$(sysctl -n net.ipv4.icmp_echo_ignore_all 2>/dev/null || echo 0)"
    unit="$(ssh_unit)"
    if systemctl is-active --quiet "$unit"; then
        ssh_state=on
    else
        ssh_state=off
    fi
    port="$(ssh_port)"
    printf '{"icmp":"%s","ssh":"%s","sshPort":%s}\n' \
        "$([ "$icmp" = "1" ] && echo off || echo on)" \
        "$ssh_state" \
        "$port"
}

case "${1:-}" in
    status) status ;;
    icmp) [ "$#" -eq 2 ] || err "usage: bt-access icmp <on|off>"; write_icmp "$2"; status ;;
    ssh) [ "$#" -eq 2 ] || err "usage: bt-access ssh <on|off>"; set_ssh "$2"; status ;;
    ssh-port) [ "$#" -eq 2 ] || err "usage: bt-access ssh-port <port>"; write_ssh_port "$2"; status ;;
    *) err "usage: bt-access {status|icmp <on|off>|ssh <on|off>|ssh-port <port>}" ;;
esac
