#!/bin/sh

BASE_DIR="/tmp/luci-app-run"
UPLOAD_DIR="$BASE_DIR/uploads"
MAX_SIZE=$((256 * 1024 * 1024))

umask 077

header() {
	printf 'Status: %s\r\n' "$1"
	printf 'Content-Type: application/json\r\n'
	printf 'Cache-Control: no-store\r\n'
	printf '\r\n'
}

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

fail() {
	header "${2:-400 Bad Request}"
	printf '{"code":1,"error":"%s"}\n' "$(json_escape "$1")"
	exit 0
}

ok() {
	header '200 OK'
	printf '{"code":0,"size":%s}\n' "$1"
	exit 0
}

urldecode() {
	local value="${1//+/ }"
	printf '%b' "${value//%/\\x}"
}

query_value() {
	local key="$1" pair name value oldifs
	oldifs="$IFS"
	IFS='&'
	for pair in $QUERY_STRING; do
		name="${pair%%=*}"
		value="${pair#*=}"
		if [ "$name" = "$key" ]; then
			IFS="$oldifs"
			urldecode "$value"
			return
		fi
	done
	IFS="$oldifs"
}

valid_id() {
	case "$1" in
		""|*[!A-Za-z0-9_-]*) return 1 ;;
	esac
	return 0
}

[ "$REQUEST_METHOD" = "POST" ] || fail "POST required" "405 Method Not Allowed"

id="$(query_value id)"
token="$(query_value token)"
valid_id "$id" || fail "Invalid upload id"
[ -n "$token" ] || fail "Missing upload token"

dir="$UPLOAD_DIR/$id"
[ -d "$dir" ] || fail "Unknown upload id" "404 Not Found"

saved_token="$(cat "$dir/token" 2>/dev/null)"
[ "$token" = "$saved_token" ] || fail "Invalid upload token" "403 Forbidden"

name="$(cat "$dir/name" 2>/dev/null)"
case "$name" in
	*.run) ;;
	*) fail "Invalid filename" ;;
esac

length="${CONTENT_LENGTH:-0}"
[ "$length" -gt 0 ] 2>/dev/null || fail "Empty upload"
[ "$length" -le "$MAX_SIZE" ] 2>/dev/null || fail "File is larger than 256 MiB"

file="$dir/$name"
tmp="$file.upload"

cat > "$tmp" || fail "Unable to receive upload"
actual="$(wc -c < "$tmp" 2>/dev/null)"
[ "$actual" -eq "$length" ] 2>/dev/null || {
	rm -f "$tmp"
	fail "Upload size mismatch"
}

mv "$tmp" "$file" || fail "Unable to save upload"
chmod 700 "$file" || fail "Unable to chmod uploaded file"

ok "$actual"
