#!/bin/bash

INPUT_TYPE=$1
INPUT_FILE=$2
SIGN_FILE=$INPUT_FILE
PROJECT_CONF="/lkp/scheduled/job.yaml"
POST_ADDR=""
POST_FILE_SHA256=""
POST_KEY_NAME=""
POST_KEY_TYPE=""
POST_FILE_TYPE=""
POST_SIGN_TYPE=""
POST_JOB_ID=""
POST_OS_ORIJECT=""
CONFIG_RETEST_COUNT=5
SIGN_RESULT=0
FAILED_SIGN_PERMISSION_DENIED=2

# Tool functions for JSON
get_json_value(){
	echo "$1" | \
	awk -F "[{,:}]" '{for(i=1;i<NF;i++){if($i~"'$2'"){print $(i+1)}}}' | \
	sed 's/\"//g'
}

get_post_json() {
	printf '{'
	printf '"file_sha256":"%s",' $POST_FILE_SHA256
	printf '"key_name":"%s",' $POST_KEY_NAME
	printf '"key_type":"%s",' $POST_KEY_TYPE
	printf '"file_type":"%s",' $POST_FILE_TYPE
	printf '"sign_type":"%s",' $POST_SIGN_TYPE
	printf '"job_id":"%s",' $POST_JOB_ID
	printf '"os_project":"%s"' $POST_OS_ORIJECT
	printf '}'
}

# Prepare sign functions for each sign type
module_sign_pre() {
	if [[ "$INPUT_FILE" != *.ko ]]; then
		echo "The module file must has the .ko extension"
		return 1
	fi

	SIGN_FILE="$INPUT_FILE"
	POST_KEY_NAME="openeuler-kernel-module-ee"
	POST_KEY_TYPE="x509ee"
	POST_FILE_TYPE="kernel-module"
	POST_SIGN_TYPE="cms"
}

ima_digestlist_sign_pre() {
	cp -f $INPUT_FILE $INPUT_FILE.ko
	SIGN_FILE="$INPUT_FILE.ko"
	POST_KEY_NAME="openeuler-ima-ee"
	POST_KEY_TYPE="x509ee"
	POST_FILE_TYPE="kernel-module"
	POST_SIGN_TYPE="cms"
}

efi_sign_pre() {
	SIGN_FILE="$INPUT_FILE"
	POST_KEY_NAME="default-x509ee"
	POST_KEY_TYPE="x509ee"
	POST_FILE_TYPE="efi-image"
	POST_SIGN_TYPE="authenticode"
}

kernel_sign_pre() {
	SIGN_FILE="$INPUT_FILE"
	POST_KEY_NAME="default-x509ee"
	POST_KEY_TYPE="x509ee"
	POST_FILE_TYPE="efi-image"
	POST_SIGN_TYPE="authenticode"
}

# Post sign functions for each sign type
module_sign_post() {
	:
}

ima_digestlist_sign_post() {
	rm -f $INPUT_FILE.ko
}

efi_sign_post() {
	:
}

kernel_sign_post() {
	:
}

# Global configuration
sign_config() {
	if [ -z "$INPUT_TYPE" ] || [ -z "$INPUT_FILE" ]; then
		echo "Please input the sign type and file"
		exit 1
	fi

	if [ ! -f "$INPUT_FILE" ]; then
		echo "The input file is invalid"
		exit 1
	fi

	POST_FILE_SHA256=$(sha256sum "$INPUT_FILE" | awk '{ print $1 }')
	if [ $? -ne 0 ]; then
		echo "Failed to calculate file hash"
	fi

	PUBLISHER_HOST=$(grep PUBLISHER_HOST $PROJECT_CONF | awk '{print $2}')
	PUBLISHER_PORT=$(grep PUBLISHER_PORT $PROJECT_CONF | awk '{print $2}')
	if [ -z "$PUBLISHER_HOST" ] || [ -z "$PUBLISHER_PORT" ]; then
		echo "Please set PUBLISHER_HOST and PUBLISHER_PORT"
		exit 1
	fi

	POST_ADDR="http://${PUBLISHER_HOST}:${PUBLISHER_PORT}/code-sign"

	POST_JOB_ID="$(grep -rwn 'id\:' $PROJECT_CONF | awk '{print $2}')"
	POST_OS_ORIJECT="$(grep -rwn 'os_project\:' $PROJECT_CONF | awk '{print $2}')"
	if [ -z "$POST_JOB_ID" ] || [ -z "$POST_OS_ORIJECT" ]; then
		echo "Failed to get POST_JOB_ID and POST_OS_ORIJECT"
		exit 1
	fi
}

sign_pre() {
	sign_config

	case $INPUT_TYPE in
	--efi)
		efi_sign_pre
		;;
	--module)
		module_sign_pre
		;;
	--ima-digestlist)
		ima_digestlist_sign_pre
		;;
	--kernel)
		kernel_sign_pre
		;;
	*)
		echo "Unsupported sign type: $INPUT_TYPE"
		exit 1
		;;
	esac
}

sign() {
	# 1. send the request to the sign service
	# echo "curl "$POST_ADDR" \
	# 	   -F "file=@$SIGN_FILE" \
	# 	   -F "data=$(get_post_json);type=application/json""
	req="$(curl "$POST_ADDR" \
		    -F "file=@$SIGN_FILE" \
		    -F "data=$(get_post_json);type=application/json")"
	if [ $? -ne 0 ]; then
		echo "Failed to post the sign service"
		return 1
	fi

	req_err_msg=$(get_json_value "$req" "err_msg")
	if [ -n "$req_err_msg" ]; then
		echo "Failed, err_msg: [$req_err_msg]"
		if [ "$req_err_msg" == "SIGN_PERMISSION_DENIED" ]; then
			return $FAILED_SIGN_PERMISSION_DENIED
		fi
		return 1
	fi

	# 2. write the file content
	encoded_file_content=$(get_json_value "$req" "encoded_file_content")
	if [ $? -ne 0 ]; then
		echo "Failed to get encoded file content"
		return 1
	fi

	echo -ne "$encoded_file_content" | base64 -d > $INPUT_FILE.sig
	if [ $? -ne 0 ]; then
		echo "Failed to write the signed file"
		return 1
	fi

	# for test
	# cp -f $INPUT_FILE $INPUT_FILE.sig
	# req="{file_sha256:41c68fca7b3870cc9ef13a828a74af933bd8e4ff345fcfa316}"

	# 3. check the hash
	sha256_cal=$(sha256sum $INPUT_FILE.sig | awk '{print $1}')
	sha256_get=$(get_json_value "$req" "file_sha256" | tr '[:upper:]' '[:lower:]')
	if [ "$sha256_cal" != "$sha256_get" ]; then
		echo "Failed to verify the hash value"
		return 1
	fi
}

sign_post() {
	case $INPUT_TYPE in
	--efi)
		efi_sign_post
		;;
	--module)
		module_sign_post
		;;
	--ima-digestlist)
		ima_digestlist_sign_post
		;;
	--kernel)
		kernel_sign_post
		;;
	esac
}

# Main function
sign_pre

for ((i=1; i<=$CONFIG_RETEST_COUNT; i++)); do
	sign
	ret_sign=$?
	if [ $ret_sign -eq 0 ]; then
		echo "Succeed to sign file"
		break;
	elif [ $ret_sign -eq $FAILED_SIGN_PERMISSION_DENIED ]; then
		echo "Failed to sign file, permission denied"
		SIGN_RESULT=$FAILED_SIGN_PERMISSION_DENIED
		break;
	elif [ $i -ne $CONFIG_RETEST_COUNT ]; then
		echo "Failed to sign file, try again"
	elif [ $i -eq $CONFIG_RETEST_COUNT ]; then
		echo "Failed to sign file"
		SIGN_RESULT=1
	fi
done

sign_post
exit $SIGN_RESULT
