#!/bin/sh /etc/rc.common

START=95
STOP=10
USE_PROCD=1

PROG="/usr/bin/peervpnd"
UCI_CONFIG="lionvpn"
UCI_SECTION="main"
CONFIG_JSON="/var/etc/lionvpn/peervpnd.json"
RUNTIME_MANIFEST="/etc/peervpn/runtime-dependencies.json"
RUNTIME_SIGNATURE="/etc/peervpn/runtime-dependencies.json.sig"
RUNTIME_PUBLIC_KEY="/etc/peervpn/runtime-dependencies.pub"
RUNTIME_TARGET="/etc/peervpn/runtime-dependencies.target"

extra_command "doctor" "Generate config and run peervpnd preflight"
extra_command "print_config" "Print generated peervpnd JSON config"

json_escape() {
	printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
}

reject_control_chars() {
	local name="$1"
	local value="$2"
	if printf '%s' "$value" | grep -q '[[:cntrl:]]'; then
		echo "$name contains control characters" >&2
		return 1
	fi
}

uci_string() {
	local __var="$1"
	local __option="$2"
	local __default="$3"
	config_get "$__var" "$UCI_SECTION" "$__option" "$__default"
}

uci_string_default_if_empty() {
	local __var="$1"
	local __option="$2"
	local __default="$3"
	config_get "$__var" "$UCI_SECTION" "$__option" "$__default"
	eval "[ -n \"\${$__var}\" ] || $__var=\"\$__default\""
}

load_lionvpn_config() {
	config_load "$UCI_CONFIG"
	config_get_bool enabled "$UCI_SECTION" enabled 0
}

generate_config() {
	load_lionvpn_config
	if [ "$enabled" != "1" ]; then
		echo "lionvpn is disabled in /etc/config/lionvpn" >&2
		return 1
	fi

	uci_string socket_path socket_path "/var/run/peervpn/peervpnd.sock"
	uci_string access_url access_url ""
	uci_string access_protocol access_protocol "socks"
	uci_string xray_binary xray_binary "/usr/lib/lionvpn/runtime/xray"
	uci_string tun2socks_binary tun2socks_binary "/usr/lib/lionvpn/runtime/tun2socks"
	uci_string state_dir state_dir "/etc/peervpn/state"
	uci_string tun_name tun_name "peervpn0"
	uci_string tun_address tun_address "10.128.225.1/32"
	uci_string tun_mtu tun_mtu "1350"
	uci_string dns_servers dns_servers "1.1.1.1,8.8.8.8"
	uci_string kill_switch_mode kill_switch_mode "nft"
	uci_string gateway_lan_interface gateway_lan_interface "br-lan"
	uci_string gateway_lan_cidr gateway_lan_cidr "192.168.50.0/24"
	uci_string gateway_dns_listen gateway_dns_listen "192.168.50.1:53"
	config_get_bool gateway_boot_fail_closed "$UCI_SECTION" gateway_boot_fail_closed 1

	runtime_deps_manifest_default=""
	runtime_deps_signature_default=""
	runtime_deps_public_key_file_default=""
	runtime_deps_root_default=""
	runtime_deps_target_file_default=""
	if [ -f "$RUNTIME_MANIFEST" ] && [ -f "$RUNTIME_SIGNATURE" ] && [ -f "$RUNTIME_PUBLIC_KEY" ] && [ -f "$RUNTIME_TARGET" ]; then
		runtime_deps_manifest_default="$RUNTIME_MANIFEST"
		runtime_deps_signature_default="$RUNTIME_SIGNATURE"
		runtime_deps_public_key_file_default="$RUNTIME_PUBLIC_KEY"
		runtime_deps_root_default="/usr/lib/lionvpn/runtime"
		runtime_deps_target_file_default="$RUNTIME_TARGET"
	fi
	uci_string_default_if_empty runtime_deps_manifest runtime_deps_manifest "$runtime_deps_manifest_default"
	uci_string_default_if_empty runtime_deps_signature runtime_deps_signature "$runtime_deps_signature_default"
	uci_string_default_if_empty runtime_deps_public_key_file runtime_deps_public_key_file "$runtime_deps_public_key_file_default"
	uci_string_default_if_empty runtime_deps_root runtime_deps_root "$runtime_deps_root_default"
	uci_string_default_if_empty runtime_deps_target_file runtime_deps_target_file "$runtime_deps_target_file_default"

	case "$tun_mtu" in
		''|*[!0-9]*) tun_mtu="1350" ;;
	esac
	case "$gateway_boot_fail_closed" in
		1|true|TRUE|True|yes|YES|Yes|on|ON|On) gateway_boot_fail_closed_json="true" ;;
		*) gateway_boot_fail_closed_json="false" ;;
	esac

	for field in socket_path access_url access_protocol xray_binary tun2socks_binary state_dir tun_name tun_address dns_servers kill_switch_mode gateway_lan_interface gateway_lan_cidr gateway_dns_listen runtime_deps_manifest runtime_deps_signature runtime_deps_public_key_file runtime_deps_root runtime_deps_target_file; do
		eval "value=\${$field}"
		reject_control_chars "$field" "$value" || return 1
	done

	mkdir -p "$(dirname "$CONFIG_JSON")" "$(dirname "$socket_path")" "$state_dir" /etc/peervpn
	chmod 0755 "$(dirname "$CONFIG_JSON")" "$(dirname "$socket_path")" /etc/peervpn
	chmod 0700 "$state_dir"

	cat > "$CONFIG_JSON" <<EOF
{
  "socket_path": "$(json_escape "$socket_path")",
  "access_url": "$(json_escape "$access_url")",
  "access_protocol": "$(json_escape "$access_protocol")",
  "xray_binary": "$(json_escape "$xray_binary")",
  "tun2socks_binary": "$(json_escape "$tun2socks_binary")",
  "tun2socks_mode": "external",
  "state_dir": "$(json_escape "$state_dir")",
  "tun_name": "$(json_escape "$tun_name")",
  "tun_mode": "open",
  "tun_address": "$(json_escape "$tun_address")",
  "tun_mtu": $tun_mtu,
  "dns_mode": "disabled",
  "dns_servers": "$(json_escape "$dns_servers")",
  "netops_mode": "apply",
  "kill_switch_mode": "$(json_escape "$kill_switch_mode")",
  "gateway_mode": "router",
  "gateway_lan_interface": "$(json_escape "$gateway_lan_interface")",
  "gateway_lan_cidr": "$(json_escape "$gateway_lan_cidr")",
  "gateway_dns_listen": "$(json_escape "$gateway_dns_listen")",
  "gateway_boot_fail_closed": $gateway_boot_fail_closed_json,
  "runtime_deps_manifest": "$(json_escape "$runtime_deps_manifest")",
  "runtime_deps_signature": "$(json_escape "$runtime_deps_signature")",
  "runtime_deps_public_key_file": "$(json_escape "$runtime_deps_public_key_file")",
  "runtime_deps_root": "$(json_escape "$runtime_deps_root")",
  "runtime_deps_target_file": "$(json_escape "$runtime_deps_target_file")"
}
EOF
	chmod 0600 "$CONFIG_JSON"
}

start_service() {
	load_lionvpn_config
	if [ "$enabled" != "1" ]; then
		echo "lionvpn is disabled in /etc/config/lionvpn"
		return 0
	fi

	generate_config || return 1
	procd_open_instance
	procd_set_param command "$PROG" -config "$CONFIG_JSON"
	procd_set_param file /etc/config/lionvpn "$CONFIG_JSON"
	procd_set_param respawn 3600 5 5
	procd_set_param stdout 1
	procd_set_param stderr 1
	procd_close_instance
}

service_triggers() {
	procd_add_reload_trigger "$UCI_CONFIG"
}

reload_service() {
	stop
	start
}

doctor() {
	generate_config || return 1
	"$PROG" -config "$CONFIG_JSON" -doctor
}

print_config() {
	generate_config || return 1
	cat "$CONFIG_JSON"
}
