From a2821f2bbcedc8277b961cce2a7413d542df7094 Mon Sep 17 00:00:00 2001 From: Oier Bravo Urtasun Date: Tue, 9 Jun 2026 03:06:59 +0200 Subject: [PATCH] feat(tooling): fetch-authlib.sh to download authlib-injector.jar The server JVM agent (runtime/authlib-injector.jar, mounted at /extras) is gitignored and was previously fetched by the deleted build-stack.sh prep. A fresh checkout had no jar, so minecraft crashlooped with "Error opening zip file or JAR manifest missing". Add a standalone fetch tool: resolves the latest release asset, downloads, and verifies it's a real zip/jar (PK magic) before trusting it. Idempotent (skips if valid, --force to re-download). Wire it into the deploy skill and README launch steps. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/deploy/SKILL.md | 4 +++ README.md | 2 +- runtime/README.md | 5 ++-- tooling/fetch-authlib.sh | 51 ++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 3 deletions(-) create mode 100755 tooling/fetch-authlib.sh diff --git a/.claude/skills/deploy/SKILL.md b/.claude/skills/deploy/SKILL.md index 844c610..b1622a4 100644 --- a/.claude/skills/deploy/SKILL.md +++ b/.claude/skills/deploy/SKILL.md @@ -37,6 +37,7 @@ invoking this skill is the authorization to proceed, but: cd /home/ubuntu/mc/ulicraft-server-v1 git pull --ff-only tooling/render-config.sh + tooling/fetch-authlib.sh docker compose down --remove-orphans docker compose up -d --build' ``` @@ -45,6 +46,9 @@ invoking this skill is the authorization to proceed, but: - `render-config.sh` re-renders drasl/nmsr/packwiz configs from `.env` (needs `.env` complete: `BASE_DOMAIN`, `RCON_PASSWORD`, `DISTRIBUTION_WEB_ROOT`, `CADDY_HTTP_*`). + - `fetch-authlib.sh` ensures `runtime/authlib-injector.jar` exists (gitignored; + skips if already valid). Missing jar = minecraft crashloops with "Error + opening zip file or JAR manifest missing". 3. **Verify.** ```bash diff --git a/README.md b/README.md index 40cadfc..580e36b 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ cp .env.example .env # set BASE_DOMAIN, RCON_PASSWORD, DISTRIBUTION_W tooling/render-config.sh # drasl + nmsr + packwiz configs from *.tmpl ( cd landing && pnpm install && BASE_DOMAIN="$BASE_DOMAIN" pnpm run build ) # → www/ tooling/fetch-launcher.sh # FjordLauncher assets → launcher/ (served at /launcher/) -# authlib-injector.jar → runtime/ (server JVM agent; see drasl docs) +tooling/fetch-authlib.sh # authlib-injector.jar → runtime/ (server JVM agent) docker compose up -d --build # first run installs NeoForge + mods, builds nmsr docker compose down # stop diff --git a/runtime/README.md b/runtime/README.md index 49bb5d5..e723fda 100644 --- a/runtime/README.md +++ b/runtime/README.md @@ -4,8 +4,9 @@ Runtime drop-ins mounted read-only into the Minecraft container at `/extras`. ## Required files -- `authlib-injector.jar` — download latest from - https://github.com/yushijinhun/authlib-injector/releases +- `authlib-injector.jar` — fetch with `tooling/fetch-authlib.sh` (downloads the + latest from https://github.com/yushijinhun/authlib-injector/releases and + verifies it's a valid jar). Gitignored. Mods are no longer listed here; the pack is served via packwiz (`PACKWIZ_URL`, see plan/04-packwiz.md). diff --git a/tooling/fetch-authlib.sh b/tooling/fetch-authlib.sh new file mode 100755 index 0000000..bf8992a --- /dev/null +++ b/tooling/fetch-authlib.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# fetch-authlib.sh — download the latest authlib-injector.jar into runtime/. +# +# The Minecraft container mounts ./runtime read-only at /extras and loads the +# server JVM agent from /extras/authlib-injector.jar (points the server at Drasl +# for session validation). The jar is gitignored, so a fresh checkout needs this. +# +# Usage: +# tooling/fetch-authlib.sh # download if missing (or invalid) +# tooling/fetch-authlib.sh --force # re-download even if present +# +# Cautious by design: resolves the release asset by name, halts on any error, +# and verifies the result is a real zip/jar before trusting it (a half-written +# or HTML error body would otherwise surface later as the cryptic +# "Error opening zip file or JAR manifest missing"). +set -euo pipefail + +cd "$(dirname "$0")/.." # repo root + +log() { printf '\n\033[1;32m==>\033[0m %s\n' "$*"; } +warn() { printf '\033[1;33m!!\033[0m %s\n' "$*" >&2; } +die() { printf '\033[1;31mxx\033[0m %s\n' "$*" >&2; exit 1; } + +command -v curl >/dev/null || die "curl required" +command -v jq >/dev/null || die "jq required" + +DEST="runtime/authlib-injector.jar" +API="https://api.github.com/repos/yushijinhun/authlib-injector/releases/latest" + +# A valid jar is a zip — first two bytes are "PK". Reject anything else. +is_jar() { [ -s "$1" ] && [ "$(head -c2 "$1" 2>/dev/null)" = "PK" ]; } + +if [ "${1:-}" != "--force" ] && is_jar "$DEST"; then + log "$DEST already present and valid — skipping (use --force to re-download)" + exit 0 +fi + +log "resolving latest authlib-injector release asset" +url="$(curl -fsSL "$API" \ + | jq -r '.assets[] | select(.name|test("authlib-injector-[0-9].*\\.jar$")) | .browser_download_url' \ + | head -1)" +[ -n "$url" ] && [ "$url" != "null" ] || die "could not resolve authlib-injector release asset" + +mkdir -p runtime +tmp="${DEST}.part" +log "downloading $(basename "$url")" +curl -fSL --retry 3 -o "$tmp" "$url" + +is_jar "$tmp" || { rm -f "$tmp"; die "downloaded file is not a valid jar (zip) — aborting"; } +mv -f "$tmp" "$DEST" +log "done → $DEST ($(wc -c <"$DEST") bytes)"