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

START=52
STOP=52

USE_PROCD=1

TORRC_FILE=/var/run/tor/torrc_generated # file with torrc config
HS_DIR_PATH=/etc/tor/hidden_service # onion services directory
TOR_USER=tor

config_tor() {
	local restart_tor update_config
	config_get_bool restart_tor common RestartTor
	config_get_bool update_config common UpdateTorConf

	tail_conf=$(uci show tor.conf.tail_include 2>/dev/null)
	head_conf=$(uci show tor.conf.head_include 2>/dev/null)

	if [ "$update_config" = "1" ]; then
		if [ -n "$(echo $tail_conf | grep $TORRC_FILE)" ] || [ -n "$(echo $head_conf | grep $TORRC_FILE)" ]; then
			echo "Info. Not updating tor configuration"
		else
			echo "Info. Updating tor configuration"
			uci add_list tor.conf.tail_include="$TORRC_FILE"
			uci commit tor
		fi
	fi

	if [ "$restart_tor" = "1" ]; then
		/etc/init.d/tor restart
	fi
}

handle_hs_ports_conf() {
	local public_port local_port
	local value="$1"
	local ipv4="$2"

	public_port="${value#*;}"
	local_port="${value%;*}"
	echo "HiddenServicePort $public_port $ipv4:$local_port" >> "$TORRC_FILE"
}

parse_hs_conf() {
	local name public_port local_port enable_hs ipv4
	local config="$1"

	config_get name "$config" Name
	[ -z "$name" ] && return 0
	config_get_bool enable_hs "$config" Enabled 0
	config_get ipv4 "$config" IPv4

	if [ "$enable_hs" = "1" ]; then
		if [ ! -d "$HS_DIR_PATH/$name" ]; then
			echo "New onion service dir is $HS_DIR_PATH/$name"
			mkdir -p -m 700 "$HS_DIR_PATH/"
			mkdir -m 700 "$HS_DIR_PATH/$name"
			chown -R "$TOR_USER:$TOR_USER" "$HS_DIR_PATH/"
		fi

		echo "HiddenServiceDir $HS_DIR_PATH/$name" >> "$TORRC_FILE"
		config_list_foreach "$config" PublicLocalPort handle_hs_ports_conf "$ipv4"
	fi
}

parse_hs_conf_hooks() {
	local name hook_script enable_hs hostname_file
	local config="$1"

	config_get name "$config" Name
	[ -z "$name" ] && return 0
	config_get_bool enable_hs "$config" Enabled 0
	config_get hook_script "$config" HookScript

	hostname_file="$HS_DIR_PATH/$name/hostname"

	# check if we should run hook_script
	if [ "$enable_hs" = "1" ] && [ -x "$hook_script" ] && [ -f "$hostname_file" ]; then
		hostname_uri=$(cat "$hostname_file")
		# call hook script
		$hook_script "--update-onion" "$hostname_uri"
	fi
}

parse_common_conf() {
	local hs_dir generated_config
	config_get generated_config common GenConf
	config_get hs_dir common HSDir
	[ -n "$hs_dir" ] && HS_DIR_PATH="$hs_dir"
	[ -n "$generated_config" ] && TORRC_FILE="$generated_config"
}

start_service() {
	# create runtime dir
	mkdir -p -m 700 /var/run/tor
	chown -R "$TOR_USER:$TOR_USER" /var/run/tor
	config_load tor-hs
	validate_common_section || {
		echo "validation failed"
		return 1
	}
	# load common config
	parse_common_conf
	# clean config
	echo -n "" > "$TORRC_FILE"
	chown "$TOR_USER:$TOR_USER" "$TORRC_FILE"
	# load hs service
	config_foreach validate_hidden_service_section hidden-service parse_hs_conf
	# update tor config
	config_tor
	# load and run tor-hs hooks
	config_foreach parse_hs_conf_hooks hidden-service
}

validate_common_section() {
	uci_validate_section tor-hs tor-hs common \
		'GenConf:string:/var/run/tor/torrc_generated' \
		'HSDir:string:/etc/tor/hidden_service' \
		'RestartTor:bool:1' \
		'UpdateTorConf:bool:1'
}

validate_hidden_service_section() {
	uci_load_validate tor-hs hidden-service "$1" "$2" \
		'Name:string(1)' \
		'Description:string' \
		'Enabled:bool:0' \
		'IPv4:host:127.0.0.1' \
		'PublicLocalPort:list(string)' \
		'HookScript:string'
}
