#!/bin/sh

changed=0
DEFAULT_DB_DIR=/etc/gecoosac/
DEFAULT_UPLOAD_DIR=/tmp/gecoosac/upload/
DEFAULT_CRT_FILE=/etc/gecoosac/tls/gecoosac.crt
DEFAULT_KEY_FILE=/etc/gecoosac/tls/gecoosac.key
DEFAULT_PID_DIR=/var/run/
OLD_CRT_FILE=/etc/gecoosac/tls/1.crt
OLD_KEY_FILE=/etc/gecoosac/tls/1.key

ensure_section() {
	uci -q get gecoosac.config >/dev/null && return 0
	uci -q set gecoosac.config=gecoosac
	changed=1
}

set_default() {
	local option="$1"
	local value="$2"

	uci -q get "gecoosac.config.${option}" >/dev/null && return 0
	uci -q set "gecoosac.config.${option}=${value}"
	changed=1
}

strip_trailing_slashes() {
	local path="$1"

	while [ "$path" != "/" ] && [ "${path%/}" != "$path" ]; do
		path="${path%/}"
	done

	printf '%s\n' "$path"
}

normalize_path() {
	local path="$1"
	local old_ifs part normalized parent

	is_abs_path "$path" || return 1
	normalized="/"
	old_ifs="$IFS"
	IFS=/
	set -- $path
	IFS="$old_ifs"

	for part in "$@"; do
		case "$part" in
			""|.) ;;
			..)
				if [ "$normalized" != "/" ]; then
					parent="${normalized%/*}"
					[ -n "$parent" ] || parent="/"
					normalized="$parent"
				fi
			;;
			*) normalized="${normalized%/}/$part" ;;
		esac
	done

	printf '%s\n' "$normalized"
}

is_abs_path() {
	case "$1" in
		/*) return 0 ;;
		*) return 1 ;;
	esac
}

is_safe_upload_dir() {
	local path

	path="$(normalize_path "$1")" || return 1
	case "$path" in
		/etc/gecoosac|/etc/gecoosac/*) return 1 ;;
	esac

	case "$path" in
		*/gecoosac/upload) return 0 ;;
	esac

	return 1
}

is_path_in_dir() {
	local path root

	path="$(normalize_path "$1")" || return 1
	root="$(normalize_path "$2")" || return 1

	[ "$root" != "/" ] || return 1
	[ "$path" = "$root" ] && return 0
	[ "${path#"$root"/}" != "$path" ]
}

is_safe_db_dir() {
	local path upload_root

	path="$(normalize_path "$1")" || return 1
	upload_root="$(normalize_path "${2:-$DEFAULT_UPLOAD_DIR}")" || return 1

	case "$path" in
		/etc/gecoosac|/etc/gecoosac/*|/tmp/gecoosac|/tmp/gecoosac/*|/var/lib/gecoosac|/var/lib/gecoosac/*) ;;
		*) return 1 ;;
	esac
	is_path_in_dir "$path" "$upload_root" && return 1

	return 0
}

is_safe_pid_dir() {
	local path upload_root

	path="$(normalize_path "$1")" || return 1
	upload_root="$(normalize_path "${2:-$DEFAULT_UPLOAD_DIR}")" || return 1

	case "$path" in
		/var/run|/var/run/*|/tmp/gecoosac|/tmp/gecoosac/*) ;;
		*) return 1 ;;
	esac
	is_path_in_dir "$path" "$upload_root" && return 1

	return 0
}

normalize_upload_dir() {
	local upload_dir normalized

	upload_dir="$(uci -q get gecoosac.config.upload_dir)"
	[ -n "$upload_dir" ] || return 0

	if is_safe_upload_dir "$upload_dir"; then
		normalized="$(normalize_path "$upload_dir")/"
	else
		normalized="$DEFAULT_UPLOAD_DIR"
	fi

	[ "$upload_dir" = "$normalized" ] && return 0
	uci -q set "gecoosac.config.upload_dir=${normalized}"
	changed=1
}

normalize_dir_option() {
	local option="$1"
	local default="$2"
	local validator="$3"
	local value normalized upload_dir

	value="$(uci -q get "gecoosac.config.${option}")"
	[ -n "$value" ] || return 0
	upload_dir="$(uci -q get gecoosac.config.upload_dir)"
	[ -n "$upload_dir" ] || upload_dir="$DEFAULT_UPLOAD_DIR"

	if "$validator" "$value" "$upload_dir"; then
		normalized="$(normalize_path "$value")/"
	else
		normalized="$default"
	fi

	[ "$value" = "$normalized" ] && return 0
	uci -q set "gecoosac.config.${option}=${normalized}"
	changed=1
}

migrate_legacy_cert_paths() {
	local crt_file key_file
	local migrate

	crt_file="$(uci -q get gecoosac.config.crt_file)"
	key_file="$(uci -q get gecoosac.config.key_file)"
	migrate=0

	if [ "$crt_file" = "$OLD_CRT_FILE" ]; then
		if [ -z "$key_file" ] || [ "$key_file" = "$OLD_KEY_FILE" ]; then
			migrate=1
		fi
	elif [ -z "$crt_file" ] && [ "$key_file" = "$OLD_KEY_FILE" ]; then
		migrate=1
	fi

	if [ "$migrate" = "1" ]; then
		uci -q set "gecoosac.config.crt_file=${DEFAULT_CRT_FILE}"
		uci -q set "gecoosac.config.key_file=${DEFAULT_KEY_FILE}"
		changed=1
	fi
}

ensure_section
migrate_legacy_cert_paths
normalize_upload_dir
normalize_dir_option db_dir "$DEFAULT_DB_DIR" is_safe_db_dir
normalize_dir_option piddir "$DEFAULT_PID_DIR" is_safe_pid_dir
set_default enabled 0
set_default port 60650
set_default isonlyoneprot 1
set_default m_port 8080
set_default https 0
set_default crt_file "$DEFAULT_CRT_FILE"
set_default key_file "$DEFAULT_KEY_FILE"
set_default upload_dir "$DEFAULT_UPLOAD_DIR"
set_default db_dir "$DEFAULT_DB_DIR"
set_default piddir "$DEFAULT_PID_DIR"
set_default lang zh
set_default debug 0
# Preserve the previous package behavior for upgraded configs that never had showtip.
set_default showtip 0
set_default log 0

[ "$changed" = "1" ] && uci -q commit gecoosac

exit 0
