#!/usr/bin/env bash set -Eeuo pipefail handleCurlError() { local code="$1" local server="$2" local reason="${3:-}" local signal if [ -n "$reason" ] && (( code <= 125 )); then error "Request to $server servers failed: ${reason%.}." return 1 fi case "$code" in 126) error "The curl command could not be executed." ;; 127) error "The curl command was not found." ;; *) if (( code < 129 )); then error "Request to $server servers failed with curl exit status $code." return 1 fi signal=$(kill -l "$((code - 128))" 2>/dev/null || true) case "$signal" in INT) error "Curl was interrupted." ;; SEGV | ABRT) error "Curl crashed with signal $signal." ;; "") error "Curl terminated with exit status $code." ;; *) error "Curl terminated due to signal $signal." ;; esac ;; esac return 1 } curlRequest() { local output="$1" local server="$2" local agent="$3" shift 3 local log reason response if ! log=$(mktemp -p "$QEMU_DIR"); then error "Failed to create a temporary curl log." return 1 fi { response=$(LC_ALL=C curl \ --silent \ --show-error \ --max-time 30 \ --user-agent "$agent" \ --fail \ --proto =https \ --tlsv1.2 \ --http1.1 \ "$@" 2>"$log") local rc=$? } || : if (( rc != 0 )); then reason=$(sed -nE 's/^curl: \([0-9]+\) //p' "$log" | tail -n 1) rm -f "$log" handleCurlError "$rc" "$server" "$reason" return 1 fi rm -f "$log" if [ -n "$output" ]; then printf -v "$output" '%s' "$response" fi return 0 } downloadWindows() { local id="$1" local lang="$2" local desc="$3" local ovToken="" ovTicks="" ovTime local skuId skuJson local linkJson link local language ovData local session agent local type winVer local page productId local profile="606624d44113" agent=$(getAgent) language=$(getLanguage "$lang" "name") case "${id,,}" in "win11x64" ) winVer="11" && type="1" ;; "win11arm64" ) winVer="11arm64" && type="2" ;; * ) error "Invalid VERSION specified, value \"$id\" is not recognized!" && return 1 ;; esac local url="https://www.microsoft.com/en-us/software-download/windows$winVer" # uuidgen: For MacOS (installed by default) and other systems (e.g. with no /proc) that don't have a kernel interface for generating random UUIDs if ! session=$(cat /proc/sys/kernel/random/uuid 2> /dev/null || uuidgen --random); then error "Failed to generate session ID!" return 1 fi session="${session//[![:print:]]/}" if [ -z "$session" ]; then error "Failed to generate session ID!" return 1 fi # Get product edition ID for latest release of given Windows version enabled "$DEBUG" && echo "Parsing download page: ${url}" curlRequest page "Microsoft" "$agent" \ --header "Accept:" \ --max-filesize 1M \ -- "$url" || return 1 enabled "$DEBUG" && echo -n "Getting Product edition ID: " productId=$(echo "$page" | grep -Eo '