275 lines
17 KiB
Markdown
275 lines
17 KiB
Markdown
# ShaCraft Launcher — agent context
|
|
|
|
## Purpose and scope
|
|
|
|
Cross-platform desktop launcher for the ShaCraft Minecraft network. It is a
|
|
Tauri 2 application: React/Vite is the UI and Rust owns all filesystem,
|
|
network and process-adjacent work. Profiles are **Aeronautics** (Minecraft 1.21.1, NeoForge 21.1.248, Java 21)
|
|
and **Minigames** (Minecraft 26.2, Fabric 0.19.5, Java 25). See the Minigames
|
|
integration record below and `docs/release-0.1.6.md` for publication evidence.
|
|
|
|
This repository owns the launcher only. The server-side API and published
|
|
payload are in `/root/shacraft` on the ShaCraft host; see
|
|
`docs/launcher-architecture.md` before changing an integration boundary.
|
|
|
|
## Non-negotiable boundaries
|
|
|
|
- Launcher-managed payload is limited to ShaCraft-owned configuration and
|
|
approved modpack files. Never make arbitrary URLs, shell commands, or local
|
|
paths controllable by a remote manifest.
|
|
- Do not add private keys, OAuth secrets, `.env` values, player data, or built
|
|
artifacts to Git.
|
|
|
|
## Trust model
|
|
|
|
- The only supported remote profile manifest endpoints are the fixed
|
|
`https://shacraft.ru/api/launcher/v2/profiles/aeronautics/signed-manifest` and
|
|
`https://shacraft.ru/api/launcher/v2/profiles/minigames/signed-manifest`.
|
|
The read-only Aeronautics player-count endpoint
|
|
`https://shacraft.ru/api/online/aoc` is also hardcoded in `remote.rs`; it
|
|
is display-only and is never allowed to influence downloads or launching.
|
|
- The response is an Ed25519 envelope. `src-tauri/src/remote.rs` verifies its
|
|
embedded public key and `keyId` **before** parsing the payload.
|
|
- `src-tauri/src/manifest.rs` then validates paths, SHA-256, sizes, HTTPS and
|
|
allowed ShaCraft hosts. Do not weaken this whitelist.
|
|
- `src-tauri/src/profile.rs` downloads to a temporary sibling file, verifies
|
|
size + SHA-256, and atomically replaces only launcher-managed files.
|
|
- This ShaCraft manifest is the **only** source of truth for which
|
|
Minecraft version / NeoForge version / Java major a profile needs
|
|
(`Manifest.minecraft`) and for mod/config files. It never supplies a URL
|
|
for the game itself — see `docs/game-trust-boundary.md` for the four
|
|
independent, hardcoded-host trust domains (Mojang, NeoForge, Microsoft,
|
|
Adoptium) that install and run the actual game. Do not let manifest data
|
|
control a URL in any of those domains.
|
|
- ShaCraft accounts: `src-tauri/src/shacraft_account.rs` talks only to the
|
|
hardcoded `https://shacraft.ru` origin. Passwords are never persisted. The
|
|
revocable session token is stored locally with mode 600 on Unix and never
|
|
passed to Java. The new admission flow uses fixed POST endpoints
|
|
`/api/launcher/v2/admission/nickname` and
|
|
`/api/launcher/v2/admission/tickets`; redirects are rejected. Neither the
|
|
manifest nor the webview can select their origin or URL.
|
|
- Free nicknames are claimed directly for the authenticated account. Existing
|
|
player names are reserved server-side and assigned by an administrator;
|
|
deleting a website account must not make an existing player's name free.
|
|
- After installation, `admission.rs` generates an ephemeral Ed25519 key with
|
|
the OS CSPRNG. The backend binds its public key to a one-use ticket, current
|
|
account session, canonical `aoc` nickname and server access. Only that
|
|
returned nickname selects launch identity; `settings.json` is never a fallback.
|
|
Ticket and PKCS#8 private key go only in the final Java child's environment
|
|
(`SHACRAFT_ADMISSION_TICKET`, `SHACRAFT_ADMISSION_PRIVATE_KEY`). Never put
|
|
them in global environment, argv/argfiles, settings, logs or IPC. A fresh
|
|
launch obtains a fresh ticket; there is no shared launcher secret.
|
|
- Once admission is enforced on Aeronautics, its server mod verifies the
|
|
challenge/proof before world entry, and server-side whitelist enforcement
|
|
remains a final access boundary. Replace LoginSystem only as part of the
|
|
validated `aoc` rollout; other servers are unaffected. Old launchers without
|
|
admission proof will be rejected after enforcement. This authenticates an
|
|
account's permission, not the integrity of an unmodified launcher binary.
|
|
- Application updates are a separate trust domain from Minecraft profiles.
|
|
The only channel is `https://shacraft.ru/launcher/updates/stable.json`.
|
|
Both release metadata and the installer need a valid Minisign signature
|
|
under the separate updater public key embedded in `tauri.conf.json`.
|
|
Never reuse the profile signing key, accept unsigned metadata, or allow IPC
|
|
to select an update URL, key, version, installer argument or destination.
|
|
Downloads require HTTPS without redirects on exact `shacraft.ru`, below
|
|
`/downloads/shacraft-launcher/<signed-version>/`, and are bounded to 256 MiB.
|
|
Stable versions must increase. The native layer owns every candidate.
|
|
- Linux self-update supports AppImage and an installed `sha-craft-launcher`
|
|
deb. AppImage preserves executable permissions and uses same-directory
|
|
atomic replacement after verification. Deb selects only the signed
|
|
`linux-x86_64-deb` entry; retain legacy `linux-x86_64` AppImage metadata for
|
|
installed 0.1.3 clients. Never silently switch installation formats.
|
|
- Deb elevation uses only `/usr/bin/pkexec --disable-internal-agent` and the
|
|
root-owned installed `/usr/bin/shacraft-launcher --shacraft-install-deb`.
|
|
This early helper mode never starts GTK/Tauri or account/network code. It
|
|
receives bounded metadata/package bytes over stdin, not paths or commands,
|
|
and re-verifies both signatures with the embedded key as root. Before the
|
|
fixed dpkg installation, require exact package name, architecture and signed
|
|
version, root-only staging and monotonic installed-package version; pass
|
|
`--refuse-downgrade` to dpkg to close concurrent-update races. No system
|
|
password collection, sudo fallback or permissive polkit policy is allowed.
|
|
Cancellation, denied authorization and a busy package manager stay distinct.
|
|
Windows/macOS use the pinned Tauri installer implementation; the vendored
|
|
updater change only exposes construction from already verified metadata to
|
|
avoid a second, unbounded remote JSON request. See its patch notes.
|
|
Installation holds game/install/account permits until restart. The game
|
|
permit lasts until the tracked Java child exits. These are process-local
|
|
guards; another launcher process is not a cross-process lock.
|
|
- The updater signing private key stays outside Git on the operator's local
|
|
machine; CI receives no production key. Publish only verified packages,
|
|
public signatures and signed feed. Updater signatures are separate from
|
|
Windows Authenticode and macOS code signing/notarization.
|
|
|
|
## Layout
|
|
|
|
- `src/main.tsx` — React entrypoint; `src/App.tsx` composes the screen.
|
|
- `src/components/` — presentational UI; `src/hooks/` — lifecycle/settings/account.
|
|
- `src/services/native.ts` — typed IPC and event subscriptions; keep schemas
|
|
aligned with Rust. `src/services/async.ts` — serialized writes, single-flight
|
|
account restore and listener disposal. `src/state/` — tested reducers.
|
|
- Native filesystem/network/process operations never belong in the web layer.
|
|
- `src-tauri/src/` — native commands and security-sensitive logic.
|
|
- `lib.rs` — module/command registration only; `commands/` holds adapters
|
|
for account/game/host/preferences/profiles. Unsigned sync/inspect IPC was
|
|
removed; only verified remote manifests may drive profile mutations.
|
|
- `operations.rs` — process-local install/account permits owned by workers.
|
|
The account permit covers ticket issuance through Java spawn, preventing
|
|
local logout/account switching from racing that handoff.
|
|
- `storage.rs` — unique same-directory atomic writes, owner-only Unix files.
|
|
- `trusted_http.rs` — HTTPS and exact-host redirect policy per game provider.
|
|
- `download.rs` — shared verified-download helper (temp file, hash,
|
|
atomic rename, progress callback); `manifest.rs`/`profile.rs` (ShaCraft
|
|
mods) and `mojang.rs`/`neoforge.rs`/`runtime.rs` (the game itself) all
|
|
build on this rather than each rolling their own.
|
|
- `mojang.rs` — vanilla Minecraft trust boundary + the generic
|
|
`inheritsFrom` version-JSON merge (shared with NeoForge's profile).
|
|
- `neoforge.rs` — runs NeoForge's official installer headlessly.
|
|
- `runtime.rs` — Java 21 auto-provisioning via Eclipse Adoptium.
|
|
- `msa.rs` — Microsoft/Xbox/Minecraft Services login; see
|
|
`MSA_CLIENT_ID`'s doc comment before touching login — it is currently a
|
|
placeholder pending ShaCraft's own Azure AD app registration and
|
|
Minecraft-API approval.
|
|
- `shacraft_account.rs` — local ShaCraft login/registration, session and
|
|
nickname claim/admission API; legacy link commands remain for compatibility.
|
|
- `admission.rs` — ephemeral key generation, strict ticket response validation,
|
|
canonical identity and child-only admission environment.
|
|
- `launch.rs` — builds and spawns the actual `java` process; admission secrets
|
|
must remain outside its argument substitution and JVM argfile paths.
|
|
- `updater.rs`, `commands/updater.rs` — authenticated release metadata,
|
|
bounded package download, platform installation and guarded restart.
|
|
- `deb_updater.rs` — installed-package checks, one system authentication
|
|
prompt and the bounded, signature-verifying non-GUI root helper.
|
|
- `src-tauri/src/settings.rs` — durable local preferences; maintain backward
|
|
compatibility with already-written JSON.
|
|
- `docs/manifest-v1.md` — signed manifest envelope and payload contract
|
|
(mods/config only).
|
|
- `docs/game-trust-boundary.md` — the Mojang/NeoForge/Microsoft/Adoptium
|
|
trust domains used to install and run the game itself.
|
|
- `.github/workflows/check.yml` — push/PR UI checks and Linux Rust tests.
|
|
- `.github/workflows/build.yml` — main-push/manual cross-platform CI artifacts;
|
|
updater signing is explicitly disabled there. Local release signing and
|
|
atomic feed publication are documented in `docs/launcher-updates.md`.
|
|
|
|
## Verification
|
|
|
|
Run from repository root:
|
|
|
|
```bash
|
|
npm ci
|
|
npm test
|
|
npm run build
|
|
(cd src-tauri && /home/emil/.cargo/bin/cargo test)
|
|
npm run tauri:dev
|
|
```
|
|
|
|
`tauri:dev` is for local desktop testing. A successful web build alone does
|
|
not prove Tauri commands work.
|
|
|
|
See `PLAN.md` for known gaps. Never label browser preview or unit tests as
|
|
a successful cold game install / Microsoft OAuth / Windows/macOS beta test.
|
|
The admission implementation has local unit/UI checks and unsigned Linux
|
|
0.1.2 AppImage/deb packages built on Ubuntu 26.04. Older Ubuntu compatibility
|
|
has not been tested. The backend/mod rollout is active on Aeronautics as of
|
|
2026-09-10. Real isolated NeoForge admission tests and a production rejection
|
|
without the mod passed; these do not certify a full production modpack join.
|
|
The server has a required early duplicate-login guard so unauthenticated
|
|
connections cannot evict an already-online UUID. The client mod pins the actual
|
|
socket to `135.106.154.86:25567`. See architecture and server rollout records.
|
|
|
|
## Working conventions
|
|
|
|
- Keep UI copy in Russian; code, identifiers and errors may remain English.
|
|
- Prefer a small vertical slice with tests over unused abstractions.
|
|
- Existing working-tree changes belong to the user unless this task created
|
|
them. Inspect `git status` before staging.
|
|
- Update this file and `docs/launcher-architecture.md` whenever the trust
|
|
model, endpoint contract, storage layout, or release workflow changes.
|
|
|
|
|
|
## Cross-platform release 0.1.5 (2026-09-10)
|
|
|
|
Published Windows x64 EXE/MSI, macOS aarch64 and x86_64 DMG/app.tar.gz,
|
|
and Linux x64 AppImage/DEB on https://shacraft.ru/help#launcher. The signed
|
|
stable feed includes all platforms plus the legacy/exact Linux aliases.
|
|
CI source b43fc610c43a9ec9f5f3ffce601de9604670ff8a, successful Actions run
|
|
https://github.com/emil28092005/shacraft-launcher/actions/runs/34512683651.
|
|
An initial non-Linux borrow/move compilation error in updater target selection
|
|
was fixed before the final build. Native tests: Windows70, macOS74 per arch,
|
|
Linux84; UI tests pass on all four runners. Local checks verify macOS bundle
|
|
version/CPU type, Linux package identity and every artifact signature. Public
|
|
HTTPS downloads of all eight artifacts match local SHA-256. Website418 tests
|
|
plus48 subtests pass; only backend recreated, game containers unchanged.
|
|
Updater signatures use the existing operator-held key, never uploaded to CI or
|
|
server. Windows installers have no Authenticode signature; macOS is not Apple
|
|
notarized. Native CI tests and packaging do not certify full Minecraft installs
|
|
or desktop updater/restart behavior on Windows/macOS. Older unsupported clients
|
|
need a manual installation of the current release. Previous releases immutable.
|
|
|
|
|
|
## Admission client menu 0.1.1 (2026-09-11)
|
|
|
|
The signed Aeronautics payload now contains admission mod 0.1.1 at the existing
|
|
managed path `mods/shacraft-admission-0.1.0.jar` to prevent duplicate mod IDs on
|
|
upgrade. SHA-256: `faa9ae13cb0f2d93c03dae26ab36ae20d3fb6b66c89c09254b16808d6b183f89`.
|
|
From the title screen (and vanilla safety acknowledgement), Multiplayer connects
|
|
to fixed `135.106.154.86:25567`. Cancel/errors return to TitleScreen; transitions
|
|
from other screens do not auto-connect. Client-only registration, protocol 1 and
|
|
one-use admission remain unchanged. Running game server was not restarted.
|
|
Linux Java 21 build and 8 mod tests pass. An opt-in native live test verifies
|
|
signed-manifest retrieval and download/repair/restoration of the admission jar
|
|
only in a temporary directory. Mac 0.1.5 connection failure remains unclassified
|
|
pending exact error/log; this is not a verified macOS fix or desktop UI test.
|
|
|
|
## Minigames integration (2026-09-13, published in 0.1.6)
|
|
|
|
- Native profile mapping is fixed: aeronautics → aoc; minigames → minigames.
|
|
Both display/claim the canonical existing aoc nickname. The backend enforces
|
|
the current shared aoc subscription and whitelist for Minigames as well.
|
|
Ticket requests and responses remain bound to the selected server; never
|
|
accept an aoc ticket as a Minigames ticket.
|
|
- `fabric.rs` adds independent exact HTTPS domains `meta.fabricmc.net` and
|
|
`maven.fabricmc.net`. It verifies profile identity/parent/main class, bounded
|
|
metadata, portable Maven coordinates, hashes and sizes before the existing
|
|
atomic library installer. Unknown loaders now fail manifest validation.
|
|
- Minigames launches with a native-owned Quick Play endpoint
|
|
`135.106.154.86:25568`. The manifest cannot choose a game destination.
|
|
- `admission-client/` owns the small client-only Fabric 26.2 companion. Its
|
|
configuration-phase proof uses `minigames` in the existing Ed25519 transcript,
|
|
verifies the actual socket, canonical nickname and nonce, and signs once per
|
|
process. Only a fresh launch can retry a consumed ticket. Java receives only
|
|
the ephemeral ticket and private key in its child environment, never the
|
|
website session/password. Keep server verification on Paper before world
|
|
entry with an early duplicate UUID guard.
|
|
- The standalone Paper admission adapter and backend remain server-project
|
|
responsibilities. Do not put map/SMASH source into this launcher repository.
|
|
- Production updater publication requires a separately built, monotonically
|
|
newer launcher release and existing operator signatures. Source tests or a
|
|
client jar alone do not update installed 0.1.5 launchers.
|
|
|
|
Launcher 0.1.6 was built from `799fa692` on `codex/launcher-updater`; divergent
|
|
`main` remains unchanged. All four native CI builds, UI/native checks and 18
|
|
publisher signature tests pass. The unchanged Fabric companion completed a
|
|
real Minecraft 26.2 → Paper configuration handshake with a synthetic account;
|
|
its CI artifact is byte-identical. All eight public packages and the stable
|
|
feed were signed with the existing local updater key and verified through
|
|
public HTTPS downloads. See `docs/release-0.1.6.md` and its committed receipt.
|
|
This records successful release/admission verification, not a Windows/macOS
|
|
cold install or OS signing/notarization certification.
|
|
|
|
## Server migration — launcher 0.1.7 (2026-09-17)
|
|
|
|
Minigames Quick Play now uses the fixed native endpoint `shacraft.ru:25568`.
|
|
It no longer pins the retired server IP in the application binary. The Fabric
|
|
admission client accepts the new actual socket IP `135.106.219.182` and retains
|
|
`135.106.154.86` for the temporary forwarding path; unrelated hosts and ports
|
|
remain rejected. The server published updated signed companion manifests.
|
|
|
|
The migration's full-platform packages are prepared on
|
|
`codex/server-migration-20260917`. Existing 0.1.6 installers still connect to the
|
|
old IP and need that forwarding path until upgraded. Version 0.1.7 uses a newly generated operator-held updater key and the fixed
|
|
`https://shacraft.ru/launcher/updates/stable-v2.json` channel. It requires one
|
|
manual installation. Preserve `stable.json` at the last old-key release; never
|
|
replace it with new-key metadata. Subsequent v2-channel releases use the new
|
|
key, kept only at `/home/emil/.local/share/shacraft-updater/production.key`.
|
|
Do not claim publication based on CI packages alone.
|