The Microsoft Store doesn't update EXE installs, so the app updates itself with Tauri's updater. It reads updater/latest.json from the Kestrove Gitea a minute after startup and once a day. A new version shows as a banner and in Settings > Updates, and installs only on "Update and restart". The vault locks before the installer takes over. The installer must be signed with the Kestrove updater key, with the signature bound to its version (requireSignedVersion), so a compromised download server can hold updates back but can't ship one or replay an old installer. Signing is a release step, after Authenticode: gitea-release.sh signs, uploads the .sig, and writes latest.json last. Plain builds need no key. Checks reveal only the IP address and app version, and can be turned off in Settings. endpoints is a list, so a mirror can be added. Linux packages update through their package manager. Co-Authored-By: Claude Opus 5.5 <[email protected]>
61 lines
4.1 KiB
Bash
Executable File
61 lines
4.1 KiB
Bash
Executable File
#!/bin/sh
|
|
# Creates (or reuses) the Gitea release for this version, uploads the desktop bundles to it, and writes
|
|
# updater/latest.json, which the Windows app checks for updates (src-tauri/src/updates.rs).
|
|
#
|
|
# GITEA_TOKEN=… TAURI_SIGNING_PRIVATE_KEY_PATH=… scripts/gitea-release.sh [dir-with-files] (default ../release/desktop)
|
|
#
|
|
# GITEA_TOKEN: a Gitea access token with the write:repository scope (Settings → Applications). The tag
|
|
# v<version> must already be pushed. Files: *.AppImage, *.deb, *.rpm, *-setup.exe, kestrove-nmh-*, SHA256SUMS.
|
|
#
|
|
# Updates: the Windows installer needs an updater signature (<installer>.sig) from the Kestrove updater key, whose
|
|
# public half is in src-tauri/tauri.conf.json. Sign after Authenticode signing: the signature covers the final
|
|
# file. With TAURI_SIGNING_PRIVATE_KEY_PATH set, a missing .sig is made here (the key's password is asked for, or
|
|
# read from TAURI_SIGNING_PRIVATE_KEY_PASSWORD). Optional NOTES: the text shown with the update.
|
|
# Users get the update only once updater/latest.json is committed and pushed to main (printed at the end).
|
|
set -eu
|
|
cd "$(dirname "$0")/.."
|
|
: "${GITEA_TOKEN:?set GITEA_TOKEN (Gitea → Settings → Applications → token with write:repository)}"
|
|
API=${GITEA_API:-https://gitea.samialabri.com/api/v1}
|
|
REPO=${GITEA_REPO:-kestrove/kestrove-desktop}
|
|
DIR=${1:-../release/desktop}
|
|
V=$(node -p 'require("./package.json").version')
|
|
TAG="v$V"
|
|
AUTH="Authorization: token $GITEA_TOKEN"
|
|
SETUP="$DIR/Kestrove_${V}_x64-setup.exe"
|
|
|
|
if [ -f "$SETUP" ] && [ ! -f "$SETUP.sig" ]; then
|
|
: "${TAURI_SIGNING_PRIVATE_KEY_PATH:?$SETUP.sig is missing: set TAURI_SIGNING_PRIVATE_KEY_PATH to the updater key to sign it}"
|
|
# --app-version binds the signature to this version (the app requires it), so an older signed installer can't
|
|
# be offered again under a newer version number.
|
|
npx tauri signer sign -f "$TAURI_SIGNING_PRIVATE_KEY_PATH" ${TAURI_SIGNING_PRIVATE_KEY_PASSWORD+-p "$TAURI_SIGNING_PRIVATE_KEY_PASSWORD"} \
|
|
--app-version "$V" "$SETUP"
|
|
fi
|
|
|
|
(cd "$DIR" && rm -f SHA256SUMS && shasum -a 256 -- *.AppImage *.deb *.rpm *-setup.exe kestrove-nmh-* 2>/dev/null > SHA256SUMS; cat SHA256SUMS)
|
|
|
|
ID=$(curl -fsS -H "$AUTH" "$API/repos/$REPO/releases/tags/$TAG" 2>/dev/null | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{try{console.log(JSON.parse(s).id||"")}catch{console.log("")}})')
|
|
if [ -z "$ID" ]; then
|
|
BODY=$(node -e 'console.log(JSON.stringify({tag_name: process.argv[1], name: "Kestrove " + process.argv[2], body: "Kestrove desktop " + process.argv[2] + " for Windows and Linux. On a Mac, use the Kestrove app from the Mac App Store instead.\n\nVerify downloads with SHA256SUMS.", draft: false, prerelease: false}))' "$TAG" "$V")
|
|
ID=$(curl -fsS -X POST -H "$AUTH" -H "Content-Type: application/json" -d "$BODY" "$API/repos/$REPO/releases" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).id))')
|
|
fi
|
|
for f in "$DIR"/*.AppImage "$DIR"/*.deb "$DIR"/*.rpm "$DIR"/*-setup.exe "$DIR"/*-setup.exe.sig "$DIR"/kestrove-nmh-* "$DIR"/SHA256SUMS; do
|
|
[ -f "$f" ] || continue
|
|
echo "uploading $(basename "$f")"
|
|
curl -fsS -X POST -H "$AUTH" -F "attachment=@$f" "$API/repos/$REPO/releases/$ID/assets?name=$(basename "$f")" >/dev/null
|
|
done
|
|
echo "Release: ${API%/api/v1}/$REPO/releases/tag/$TAG"
|
|
|
|
# The update manifest, written only after the installer it points to is uploaded.
|
|
if [ -f "$SETUP.sig" ]; then
|
|
mkdir -p updater
|
|
node -e '
|
|
const [v, url, sigFile, notes] = process.argv.slice(1);
|
|
const signature = require("fs").readFileSync(sigFile, "utf8").trim();
|
|
const doc = { version: v, notes, pub_date: new Date().toISOString().replace(/\.\d+Z$/, "Z"),
|
|
platforms: { "windows-x86_64": { signature, url } } };
|
|
require("fs").writeFileSync("updater/latest.json", JSON.stringify(doc, null, 2) + "\n");
|
|
' "$V" "${API%/api/v1}/$REPO/releases/download/$TAG/$(basename "$SETUP")" "$SETUP.sig" "${NOTES:-Kestrove $V}"
|
|
echo "Wrote updater/latest.json. To offer the update, commit it and push to main:"
|
|
echo " git add updater/latest.json && git commit -m \"Offer $V as an update\" && git push origin main"
|
|
fi
|