#!/bin/sh /etc/rc.common
# SPDX-License-Identifier: Apache-2.0

START=98
USE_PROCD=1

TAG="isecurity-settings"
VPN_SERVICE="/etc/init.d/isecurity"

_resolve_bin() {
	if command -v isecurity >/dev/null 2>&1; then
		command -v isecurity
		return 0
	fi
	for p in /usr/bin/isecurity /usr/sbin/isecurity; do
		[ -x "$p" ] && { echo "$p"; return 0; }
	done
	return 1
}

_get() {
	local v
	v="$(uci -q get "isecurity.settings.$1" 2>/dev/null)"
	if [ -z "$v" ] && [ -n "$2" ]; then
		echo "$2"
	else
		echo "$v"
	fi
}

_bool() {
	local v
	v="$(uci -q get "isecurity.settings.$1" 2>/dev/null)"
	if [ -z "$v" ]; then
		return "$2"
	fi
	[ "$v" = "1" ]
}

_tf() {
	if _bool "$1" "$2"; then
		echo true
	else
		echo false
	fi
}

_ntf() {
	if _bool "$1" "$2"; then
		echo false
	else
		echo true
	fi
}

_tf_sub() {
	if _bool "$1" "$2"; then
		_tf "$3" "$4"
	else
		echo false
	fi
}

_ntf_sub() {
	if _bool "$1" "$2"; then
		_ntf "$3" "$4"
	else
		echo false
	fi
}

_UP_HELP=""

_load_up_help() {
	_UP_HELP="$("$1" up --help 2>&1)"
}

_has_flag() {
	echo "$_UP_HELP" | grep -qE "(^|[[:space:]])$1([[:space:]]|=|\$)"
}

_redact_psk() {
	sed 's/--preshared-key [^ ]*/--preshared-key ***/g'
}

_render_and_apply() {
	local bin="$1"
	local port iface host mgmt loglevel psk psk_disp tmp rc

	_load_up_help "$bin"

	port="$(_get wireguard_port 51820)"
	iface="$(_get interface_name wt0)"
	host="$(_get hostname)"
	mgmt="$(_get management_url)"
	loglevel="$(_get log_level info)"
	psk="$(_get preshared_key)"

	set -- up
	if _has_flag --no-browser; then
		set -- "$@" --no-browser
	fi
	if _has_flag --wireguard-port && [ -n "$port" ]; then
		set -- "$@" --wireguard-port "$port"
	fi
	if _has_flag --interface-name && [ -n "$iface" ]; then
		set -- "$@" --interface-name "$iface"
	fi
	[ -n "$host" ] && set -- "$@" --hostname "$host"
	[ -n "$mgmt" ] && set -- "$@" --management-url "$mgmt"
	[ -n "$loglevel" ] && set -- "$@" --log-level "$loglevel"

	psk_disp=""
	[ -n "$psk" ] && psk_disp=" --preshared-key ***"

	if _has_flag --disable-firewall; then
		set -- "$@" "--disable-firewall=$(_ntf enable_firewall 0)"
	fi
	if _has_flag --block-inbound; then
		set -- "$@" "--block-inbound=$(_tf block_inbound 1)"
	fi

	if _has_flag --allow-server-ssh; then
		set -- "$@" "--allow-server-ssh=$(_tf allow_ssh 1)"
	fi
	if _has_flag --enable-ssh-root; then
		set -- "$@" --enable-ssh-root="$(_tf_sub allow_ssh 1 ssh_root 1)"
	fi
	if _has_flag --enable-ssh-sftp; then
		set -- "$@" --enable-ssh-sftp="$(_tf_sub allow_ssh 1 ssh_sftp 1)"
	fi
	if _has_flag --enable-ssh-local-port-forwarding; then
		set -- "$@" --enable-ssh-local-port-forwarding="$(_tf_sub allow_ssh 1 ssh_local_fwd 1)"
	fi
	if _has_flag --enable-ssh-remote-port-forwarding; then
		set -- "$@" --enable-ssh-remote-port-forwarding="$(_tf_sub allow_ssh 1 ssh_remote_fwd 1)"
	fi
	if _has_flag --disable-ssh-auth; then
		set -- "$@" --disable-ssh-auth="$(_ntf_sub allow_ssh 1 enable_ssh_auth 0)"
	fi

	if _has_flag --disable-dns; then
		set -- "$@" "--disable-dns=$(_ntf enable_dns 1)"
	fi
	if _has_flag --block-lan-access; then
		set -- "$@" "--block-lan-access=$(_ntf access_lan 0)"
	fi
	if _has_flag --disable-client-routes; then
		set -- "$@" "--disable-client-routes=$(_ntf accept_client_routes 0)"
	fi
	if _has_flag --disable-server-routes; then
		set -- "$@" "--disable-server-routes=$(_ntf accept_server_routes 0)"
	fi

	if _has_flag --disable-ipv6; then
		set -- "$@" "--disable-ipv6=$(_ntf enable_ipv6 0)"
	fi

	if _has_flag --enable-rosenpass; then
		set -- "$@" "--enable-rosenpass=$(_tf rosenpass_enabled 1)"
	fi
	if _has_flag --rosenpass-permissive; then
		set -- "$@" --rosenpass-permissive="$(_tf_sub rosenpass_enabled 1 rosenpass_permissive 1)"
	fi

	if [ "${ISEC_DRY_RUN:-0}" = "1" ]; then
		echo "DRY_RUN: $bin $*$psk_disp"
		logger -t "$TAG" "dry-run: $*$psk_disp"
		return 0
	fi

	"$bin" down >/dev/null 2>&1

	logger -t "$TAG" "applying: $*$psk_disp"
	tmp="$(mktemp 2>/dev/null || echo /tmp/isec-settings-$$.log)"
	if [ -n "$psk" ]; then
		"$bin" "$@" --preshared-key "$psk" >"$tmp" 2>&1
	else
		"$bin" "$@" >"$tmp" 2>&1
	fi
	rc=$?
	[ -s "$tmp" ] && head -c 4096 "$tmp" | _redact_psk | logger -t "$TAG"
	rm -f "$tmp"
	return $rc
}

_sync_openwrt_zone_device() {
	local want="$1" cur
	echo "$want" | grep -qE '^[a-zA-Z][a-zA-Z0-9_-]{0,14}$' || return 0
	[ "$(uci -q get firewall.isecurity 2>/dev/null)" = "zone" ] || return 0
	cur="$(uci -q get firewall.isecurity.device 2>/dev/null)"
	[ "$cur" = "$want" ] && return 0
	uci -q delete firewall.isecurity.device 2>/dev/null
	uci -q add_list firewall.isecurity.device="$want" || return 0
	uci -q commit firewall
	/etc/init.d/firewall reload >/dev/null 2>&1
	logger -t "$TAG" "synced firewall.isecurity.device: ${cur:-<unset>} -> $want"
}

start_service() {
	return 0
}

service_triggers() {
	procd_add_reload_trigger "isecurity"
}

reload_service() {
	local bin rc

	bin="$(_resolve_bin)" || {
		echo "$TAG: client binary not found" >&2
		logger -t "$TAG" "client binary not found, abort apply"
		return 1
	}

	if ! _bool service_enabled 0; then
		logger -t "$TAG" "service_enabled=0: down + stop + disable daemon"
		"$bin" down >/dev/null 2>&1
		if [ -x "$VPN_SERVICE" ]; then
			"$VPN_SERVICE" stop >/dev/null 2>&1
			"$VPN_SERVICE" disable >/dev/null 2>&1
		fi
		return 0
	fi

	if [ -x "$VPN_SERVICE" ]; then
		"$VPN_SERVICE" enabled >/dev/null 2>&1 || "$VPN_SERVICE" enable >/dev/null 2>&1
		"$VPN_SERVICE" start >/dev/null 2>&1
	fi

	_sync_openwrt_zone_device "$(_get interface_name wt0)"

	_render_and_apply "$bin"
	rc=$?
	if [ "$rc" -ne 0 ]; then
		echo "$TAG: connect failed (exit $rc)" >&2
		logger -t "$TAG" "connect failed, exit $rc"
		return "$rc"
	fi
	logger -t "$TAG" "apply ok"
	return 0
}
