mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-11 05:53:23 -05:00
Every other manifest field was treated as hostile input, but standalone_copies targets were only length-checked before being expanded and written to: a traversal component or a symlink already sitting at the destination sent the copy outside the directory the user opted into. Targets are now validated like the other paths and a symlinked destination is never followed. RETROBIOS_BASE_URL serves the manifest and the files it declares, so it now has to be HTTPS the way both bootstraps already require of the installer URL; loopback stays open for the end-to-end tests. install.ps1 left TLS at the Windows PowerShell 5.1 default, which GitHub refuses, so the download failed before any hash was checked. check_local read every file once per declared digest, single threaded. One read now feeds both, across the same pool the downloads use. RetroPie had no manifest, so the one-line installer answered 'unknown platform' for a frontend whose packs do ship.
97 lines
3.1 KiB
Bash
Executable File
97 lines
3.1 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
# One-line bootstrap and local wrapper. The downloaded installer is accepted
|
|
# only when it matches the SHA-256 embedded in this wrapper.
|
|
INSTALLER=""
|
|
# When sourced from stdin, $0 is the shell name and the working directory is
|
|
# not a trusted location for install.py. Reuse an adjacent installer only for
|
|
# an actual local install.sh invocation.
|
|
case "$0" in
|
|
install.sh|*/install.sh)
|
|
if [ -f "$0" ]; then
|
|
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
|
INSTALLER="$SCRIPT_DIR/install.py"
|
|
fi
|
|
;;
|
|
esac
|
|
TEMP_INSTALLER=""
|
|
TEMP_DIRECTORY=""
|
|
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
|
DEFAULT_INSTALL_SHA256="b83e7422b8516d666017964cf18fc9ef8c4f8bbdb6a594ed9da0c04158eff870"
|
|
MAX_INSTALLER_BYTES=2097152
|
|
|
|
cleanup() {
|
|
if [ -n "$TEMP_INSTALLER" ] && [ -f "$TEMP_INSTALLER" ]; then
|
|
rm -f -- "$TEMP_INSTALLER"
|
|
fi
|
|
if [ -n "$TEMP_DIRECTORY" ] && [ -d "$TEMP_DIRECTORY" ]; then
|
|
rmdir -- "$TEMP_DIRECTORY" 2>/dev/null || true
|
|
fi
|
|
}
|
|
trap cleanup EXIT HUP INT TERM
|
|
|
|
if [ -z "$INSTALLER" ] || [ ! -f "$INSTALLER" ]; then
|
|
install_url=${RETROBIOS_INSTALL_URL:-$DEFAULT_INSTALL_URL}
|
|
expected=${RETROBIOS_INSTALL_SHA256:-$DEFAULT_INSTALL_SHA256}
|
|
case "$install_url" in
|
|
https://*) ;;
|
|
*) echo "Error: installer URL must use HTTPS." >&2; exit 1 ;;
|
|
esac
|
|
case "$expected" in
|
|
*[!0-9A-Fa-f]*)
|
|
echo "Error: installer SHA-256 must contain exactly 64 hexadecimal characters." >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
if [ "${#expected}" -ne 64 ]; then
|
|
echo "Error: installer SHA-256 must contain exactly 64 hexadecimal characters." >&2
|
|
exit 1
|
|
fi
|
|
TEMP_DIRECTORY=$(mktemp -d)
|
|
TEMP_INSTALLER="$TEMP_DIRECTORY/install.py"
|
|
if command -v curl >/dev/null 2>&1; then
|
|
curl --fail --location --proto '=https' --tlsv1.2 \
|
|
"$install_url" --output "$TEMP_INSTALLER"
|
|
elif command -v wget >/dev/null 2>&1; then
|
|
wget --https-only --output-document="$TEMP_INSTALLER" "$install_url"
|
|
else
|
|
echo "Error: curl or wget is required." >&2
|
|
exit 1
|
|
fi
|
|
actual_size=$(wc -c < "$TEMP_INSTALLER" | tr -d ' ')
|
|
if [ "$actual_size" -gt "$MAX_INSTALLER_BYTES" ]; then
|
|
echo "Error: downloaded installer exceeds the size limit." >&2
|
|
exit 1
|
|
fi
|
|
if command -v sha256sum >/dev/null 2>&1; then
|
|
actual=$(sha256sum "$TEMP_INSTALLER" | awk '{print $1}')
|
|
elif command -v shasum >/dev/null 2>&1; then
|
|
actual=$(shasum -a 256 "$TEMP_INSTALLER" | awk '{print $1}')
|
|
else
|
|
echo "Error: sha256sum or shasum is required." >&2
|
|
exit 1
|
|
fi
|
|
expected=$(printf '%s' "$expected" | tr '[:upper:]' '[:lower:]')
|
|
if [ "$actual" != "$expected" ]; then
|
|
echo "Error: install.py SHA-256 mismatch." >&2
|
|
exit 1
|
|
fi
|
|
INSTALLER="$TEMP_INSTALLER"
|
|
fi
|
|
|
|
PYTHON=""
|
|
for command_name in python3 python; do
|
|
if command -v "$command_name" >/dev/null 2>&1 \
|
|
&& "$command_name" -c 'import sys; raise SystemExit(sys.version_info < (3, 8))' 2>/dev/null; then
|
|
PYTHON=$command_name
|
|
break
|
|
fi
|
|
done
|
|
if [ -z "$PYTHON" ]; then
|
|
echo "Error: Python 3 is required." >&2
|
|
exit 1
|
|
fi
|
|
|
|
"$PYTHON" "$INSTALLER" "$@"
|