#!/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)
    ;;
    *.sh)
    ;;
    *.ipk)
    ;;
    *.apk)
    ;;
    *)
        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"
