#
# Copyright (C) 2012 OpenWrt.org
# Copyright (C) 2018 devolo AG
#

. /lib/delos-functions.sh

signatureFile="/tmp/signature.bin"
publicKeyFile="/etc/keys/fw_pub_key.pem"

# get the first 4 bytes (magic) of a given file starting at offset in hex format
delos_get_magic_long_at() {
	dd if="$1" skip=$2 bs=1 count=4 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
}

# scan through the update image pages until matching magic 'deadc0de' @ page start. return the offset.
delos_get_jffs2_trailer_offset() {
	local magiclong
	local offsetcount=0
	local offset
	if [ -n "$2" ]; then
		offsetcount=$2
	fi
	while magiclong=$(delos_get_magic_long_at "$1" "$offsetcount") && [ -n "$magiclong" ]; do
		[ "$magiclong" = "deadc0de" ] && {
			offset="$offsetcount"
		}
		offsetcount=$(( $offsetcount + $CI_BLKSZ ))
	done
	[ -n "$offset" ] && echo "$offset"
}

delos_check_image_dvl() {
	# check for valid matching dvl image.
	local ret
	case "$board" in
	dlan-pro-1200-ac)
		chunk -F "$1" -s inspect || {
			echo "Invalid image type."
			return 1
		}
		chunk -F "$1" -s dump -d "$1.$$.device" -v "$1.$$.oem"
		ret=$?
		if [ $ret = 0 ] ; then
			[ -e "$1.$$.device" ] &&
			[ -e "$1.$$.oem" ] &&
			[ "$(uci_get_state delos baptization DeviceType)" = "$(cat "$1.$$.device")" ] &&
			[ "$(uci_get_state delos baptization OemVariant)" = "$(cat "$1.$$.oem")" ] || ret=1
		fi
		if [ $ret != 0 ] ; then
			echo "Invalid image type."
		fi
		# cleanup working files
		rm -f "$1".$$.*
		return $ret
		;;

	esac
	echo "Invalid image type."
	return 1
}

delos_unpack_image_dvl() {
	# convert to image in sysupgrade format
	# (only works if image is a file!)
	case "$board" in
	dlan-pro-1200-ac)
		local magicl="$(get_magic_long "$1")"
		[ "$magicl" != "8664564c" ] && return
		chunk -F "$1" -s dump -k - -f - >"$1.$$.fw"
		ret=$?
		if [ $ret = 0 ] ; then
			rm -f "$1"
			mv "$1.$$.fw" "$1"
		fi
		;;
	esac
}

platform_check_image_delos() {
	local magicl="$(get_magic_long "$1")"
	local magic="$(echo "$magicl" | head -c 4)"

	[ "$magicl" = "8664564c" ] && {
		delos_check_image_dvl "$1"
		return
	}

	[ "$magic" != "2705" ] && {
		echo "Invalid image type."
		return 1
	}

	# Find trailer
	local offsetTrailer="$(delos_get_jffs2_trailer_offset "$1")"
	if [ -z "$offsetTrailer" ]; then
		echo "Invalid image contents."
		return 1
	fi

	trailerLength=$(dd if=$1 skip=$offsetTrailer bs=1 2> /dev/null | tr "\0" "\n" | sed -e '/^SIG:/,$d' | wc -c)
	signatureOffset=$((offsetTrailer+trailerLength))

	# Extract signature; Verify signature; There is a \0 before SIG: => signatureOffset-1
	dd if="$1" skip=$(( $signatureOffset + 4 )) bs=1 2>/dev/null |
	openssl base64 -A -d -out "$signatureFile"
	if [ ! -s "$signatureFile" ]; then
		echo "No signature found."
		return 1
	fi

	output=$(head -c $(($signatureOffset-1)) "$1" | openssl dgst -sha256 -verify /etc/keys/fw_pub_key.pem -signature "$signatureFile")
	opensslExitCode="$?"
	rm "$signatureFile"
	[ "$opensslExitCode" != 0 ] || [ "$output" != "Verified OK" ] && {
		echo "Invalid signature."
		return 1
	}

	# Extract trailer
	local trailer="$(dd if="$1" skip=$(( $offsetTrailer + 4 )) bs=1 count=$(( $signatureOffset - $offsetTrailer - 4 )) 2>/dev/null)"
	if [ -z "$trailer" ]; then
		echo "Invalid image contents."
		return 1
	fi
	(
		. /usr/share/libubox/jshn.sh
		json_load "$trailer"

		# compare current and image platform device type / oem variant
		json_get_var dev_img device_type
		DEVICE_TYPE=
		. /etc/delos-image
		if [ "$dev_img" = "$DEVICE_TYPE" ] && dvl_check_oemvariant "$trailer"; then
			:
		else
			echo "Image is not qualified for this device."
			return 1
		fi
	) || return 1

	return 0
}

platform_do_upgrade_delos() {
	default_do_upgrade "$@"
}

platform_check_config_delos() {
	# all in one check for gzip, tar, delos config
	tar -xzf "$1" -O etc/config/delos >/tmp/config-delos 2>/dev/null || {
		return 1
	}
	local type
	type="$(uci -c /tmp -q get config-delos.delos.device_type)" || {
		# backward compatibility accept config w/o device-type
		return 0
	}
	. /etc/delos-image
	[ "$type" != "$DEVICE_TYPE" ] && {
		return 1
	}
	return 0
}

platform_pre_upgrade_delos() {
	delos_unpack_image_dvl "$1"
	. /lib/functions/leds.sh
	led_set_attr "devolo:status:wlan" operation update
}
