--- /dev/null
+#!/bin/sh
+# Prepare a firmware update file so it can be used for GameStick firmware updates
+set -e
+
+if ! command -v xortool-xor 2>&1 > /dev/null; then
+ echo "Error: xortool-xor not found (pip install xortool)"
+ exit 3
+fi
+if ! command -v xxd 2>&1 > /dev/null; then
+ echo "Error: xxd not found"
+ exit 3
+fi
+
+if [ $# -lt 1 ]; then
+ echo "Error: Firmware directory missing (www/firmware/x.y.z)"
+ exit 1
+fi
+
+if [ ! -d "$1" ]; then
+ echo "Error: Firmware directory does not exist"
+ exit 2
+fi
+
+fwDir=$1
+fwFile=$1/update.img
+
+if [ ! -f "$fwFile" ]; then
+ echo "Error: Firmware directory has no update.img"
+ exit 2
+fi
+
+cd "$fwDir"
+rm chunk-* || true
+rm tmp-* || true
+split --bytes=102400 --numeric-suffixes --suffix-length=4 $(basename "$fwFile") tmp-part-
+
+#xor the files with the secret key
+for partfile in tmp-part-*; do
+ #"91" (hex 5b, binary 1011011) is the xor key
+ xortool-xor -h 5b --no-newline -f "$partfile" > "tmp-xor-$partfile"
+done
+#"sign" the files by prefixing the binary sha1sum
+for xorfile in tmp-xor-*; do
+ #"91" (hex 5b, binary 1011011) is the xor key
+ num=$(echo $xorfile | sed 's/tmp-xor-tmp-part-//')
+ sha1sum "$xorfile" |cut -d' ' -f 1 | xxd -r -p > chunk-$num
+ cat $xorfile >> chunk-$num
+done
+
+rm tmp-* || true
+
+#remove leading zeros
+for num in $(seq 0 999); do
+ if [ -f "chunk-0$num" ]; then
+ mv "chunk-0$num" "chunk-$num"
+ elif [ -f "chunk-00$num" ]; then
+ mv "chunk-00$num" "chunk-$num"
+ elif [ -f "chunk-000$num" ]; then
+ mv "chunk-000$num" "chunk-$num"
+ fi
+done
+
+#those files may not contain newlines
+ls -1 chunk-* | wc -l | tr -d '\n' > numchunks
+stat --printf=%s update.img > filesize
<?php
-header('Content-type: application/json');
-/*
-{
- 'available': false,
- 'major': 0,
- 'minor': 9,
- 'revision': 2058,
- 'forced': false,
- 'name': 'v2058',
- 'description': 'bar',
- 'timestamp': 12345678,
- 'url': 'http://update.gamestickservices.net/firmware/v2058/GameStick-Software-v2058.img?'
+/**
+ * Firmware update check
+ *
+ * Custom firmware versions need a folder in www/firmware/,
+ * e.g. www/firmware/0.9.2071/.
+ * Each folder needs to contain:
+ * - changelog.txt
+ * - update.img
+ *
+ * $GLOBALS['forceFirmwareVersion'] can be set to a custom version
+ */
+header('HTTP/1.0 500 Internal Server Error');
+
+$rootDir = dirname(__FILE__, 2);
+require_once $rootDir . '/config.php';
+
+if (!isset($_POST['v'])) {
+ header('HTTP/1.0 400 Bad Request');
+ header('Content-Type: text/plain');
+ echo "POST data missing\n";
+ exit(1);
}
-*/
-?>
-{"available":false}
+
+$gsData = json_decode($_POST['v']);
+if ($gsData === null) {
+ header('HTTP/1.0 400 Bad Request');
+ header('Content-Type: text/plain');
+ echo "POST data invalid\n";
+ exit(1);
+}
+
+if (!isset($gsData->hwid)
+ || !isset($gsData->major)
+ || !isset($gsData->minor)
+ || !isset($gsData->revision)
+ || !isset($gsData->platform)
+) {
+ header('HTTP/1.0 400 Bad Request');
+ header('Content-Type: text/plain');
+ echo "POST data incomplete\n";
+ exit(1);
+}
+
+$gsVersion = $gsData->major . '.' . $gsData->minor . '.' . $gsData->revision;
+
+$requireUpdate = false;
+if (isset($GLOBALS['firmwareVersion'])) {
+ $expectedVersion = $GLOBALS['firmwareVersion'];
+ if ($gsVersion != $expectedVersion) {
+ $requireUpdate = true;
+ }
+} else {
+ $expectedVersion = '0.9.2071';
+ if (version_compare($expectedVersion, $gsVersion, '>')) {
+ $requireUpdate = true;
+ }
+}
+if (!$requireUpdate) {
+ header('HTTP/1.0 200 OK');
+ header('Content-type: application/json');
+ echo '{"available":false}' . "\n";
+ exit(0);
+}
+
+list($major, $minor, $revision) = explode('.', $expectedVersion);
+
+
+$firmwareDir = $rootDir . '/www/firmware/' . $expectedVersion;
+$firmwareFile = $firmwareDir . '/update.img';
+
+if (!file_exists($firmwareFile)) {
+ header('HTTP/1.0 200 OK');
+ header('Content-type: application/json');
+ header('X-Problem: Firmware file missing');
+ echo '{"available":false}' . "\n";
+ exit(0);
+}
+
+$data = [
+ 'available' => true,
+ 'major' => $major,
+ 'minor' => $minor,
+ 'revision' => $revision,
+ 'forced' => false,
+ 'name' => $expectedVersion,
+ 'description' => file_get_contents($firmwareDir . '/changelog.txt'),
+ 'timestamp' => filemtime($firmwareFile),
+ 'url' => 'http://update.gamestickservices.net/firmware/download?version=' . $expectedVersion,
+];
+
+$json = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+
+header('HTTP/1.0 200 OK');
+header('Content-Type: application/json');
+echo $json . "\n";