diff --git a/README.md b/README.md index dd906f6..936eb3a 100644 --- a/README.md +++ b/README.md @@ -1,156 +1,62 @@ # orbisRPC — Discord Rich Presence for the PS4 -## Status (Sep 2026) +A background daemon that runs **entirely on your jailbroken PS4** and posts +what you're playing to your Discord profile — game name, cover art, elapsed +timer. No PC, no phone bridge at runtime. v1.0.0. -Backend verified working on hardware: TLSv1.3 through Cloudflare, -8MB READY handling, JSON-safe gateway parsing, heartbeats, reconnects -with the timer intact. User flow is token plus `.elf` injection. +## Install (5 minutes, one try) -Names resolve in cost tiers (param.sfo, appmeta, app cache, baked -table, Sony TMDB, raw titleId last resort). Cover art uses Sony CDN -icon URLs from the same lookup, falling back to a hosted pack or -uploaded app assets. On-console proof for sandboxed processes and -rendered-art proof are still pending. +1. Install `OrbisRPC-Setup-1.0.0.pkg` (Releases page) via Package Installer. +2. Open **orbisRPC Setup** on the home screen. +3. Say Yes: it copies the daemon everywhere loaders look, checks WiFi, + asks for your Discord token, saves it, and starts the daemon. +4. Launch a game. Watch Discord. -A background daemon that runs **entirely on your jailbroken PS4** and posts what you're -playing to your Discord profile as Rich Presence — "Playing *Call of Duty: Black -Ops III* — 1h 23m". No laptop, no phone bridge, no secondary device at runtime. -Just the console. - -It's Discord's "now-playing" integration, the way the PS5 does it — but for a -9.00 / GoldHEN PS4. - ---- +After a reboot, re-jailbreak, then enable AutoRun for `orbisrpc` in +GoldHEN's payload menu — it starts itself on every jailbreak from then on. ## How it works -The PS4 only runs one foreground app at a time, so a normal homebrew app gets -suspended the moment you launch a game and can't report your activity while you -play. orbisRPC avoids that by running as a **GoldHEN payload daemon**: it loads at -boot (from `GoldHEN/payloads/`) and keeps running in the background while games -launch in the foreground. - ``` - +--------------------------+ HTTPS/WebSocket +-------------------+ - | orbisRPC (payload daemon) | wss://gateway.discord.gg | Discord | - | on your PS4 @ 192.168.1.136 | <-- presence --> | (your profile) | - +-------------+--------------+ +-----------------+ - | - detects running game (process list + app.db) | config + token (/data/orbisRPC) - v - +--------------------------+ - | /user/app/CUSAxxxx | - | /system_data/priv/mms | - +--------------------------+ +PS4 (GoldHEN) Discord ++----------------------------------+ +------------------+ +| orbisRPC daemon (payload) | | your profile | +| sandbox scan -> CUSA id | TLS | Playing Spider- | +| app.db -> display name | <--> | Man — 1h 23m | +| art pack/CDN -> mp: cover | | [cover] [timer] | ++----------------------------------+ +------------------+ ``` -1. The daemon notices which game is running. -2. Looks up its title + cover. -3. Connects to the Discord gateway over TLS. -4. Sets your activity: `Playing ` with an elapsed timer. -5. Clears it when the game exits. +- **Detection:** the running game's `/mnt/sandbox` mount + eboot fast-switch + + 2-poll debounce. No tables, no per-game setup — any title works. +- **Names:** system app.db (SQLite, read-only) → local files → Sony TMDB + live → raw ID fallback. First authoritative hit self-learns into config. +- **Home:** PlayStation logo tile with "On PS4" when idle. +- Full design: `docs/DAEMON.md`. Installer: `docs/INSTALLER.md`. + Symptoms table: `docs/TROUBLESHOOTING.md`. -Everything stays on the PS4. Your Mac only touches this repo to *build* it. +## Config (`/data/orbisRPC/config.json`) ---- +Only `token` is required (your Discord user session token). Everything else +has working defaults: `presence_state`, `home_art`, `poll_interval_s`, +`application_id`, `debug`, plus the self-learned `titles` map (hands off — +the daemon maintains it). -## Status +## Building -| Milestone | Progress | -|---|---| -| Toolchain / build (OpenOrbis, macOS native, LLVM 21 + lld) | **done** | -| M1 — network + TLS (SceNet + LibreSSL/OpenSSL-ABI) | **done** | -| M2 — auth: Discord user session token | **done** (v1's OAuth2 flow was dead-on-arrival: the public gateway rejects OAuth2 access tokens with close 4004) | -| M3 — gateway: connect / heartbeat / presence | **done** (handshake + close-code behavior verified against the live gateway) | -| M4 — game detection (foreground user → CUSA → title) | **done (compiles + links)** | -| M5 — GoldHEN autoload + package + install | pending (needs on-console test) | -| On-console validation (TLS + detection against live FW) | pending | +Daemon + tools: `./scripts/build_sdk.sh` (needs `ps4-payload-sdk`). +Installer PKG: `make -f installer/Makefile` +(`OO_PS4_TOOLCHAIN`, llvmshim — no brew). Host tests: +`make -C tests test && make -C tests asan`, contracts: +`python3 tests/e2e_consumer.py`. -`build/orbisrpc.elf` (182 KiB) and `build/orbisrpc.fself` (188 KiB) link successfully -against OpenOrbis v0.5.4; the TLS layer uses `libSceLibreSSL`'s OpenSSL-ABI -exports (`SSL_CTX_new` / `SSL_connect` / `SSL_write` / `SSL_read`). +## Safety ---- - -## Building (macOS, native — no Docker needed) - -Verified path on this Mac (LLVM 21 via brew + OpenOrbis toolchain v0.5.4): - -```bash -# 1. one-time toolchain (OpenOrbis v0.5.4, ~160 MB) -mkdir -p ~/PS4Toolchain && cd ~/PS4Toolchain -curl -L -o toolchain-llvm-18.tar.gz \ - https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain/releases/download/v0.5.4/toolchain-llvm-18.tar.gz -tar -xzf toolchain-llvm-18.tar.gz # -> ~/PS4Toolchain/OpenOrbis/PS4Toolchain - -# 2. one-time toolchain deps -brew install llvm # clang 21 -# lld 21 (linker) — built from source or brew lld@21, see scripts/build.sh - -# 3. build -OO_PS4_TOOLCHAIN=~/PS4Toolchain/OpenOrbis/PS4Toolchain \ - LLD=/Users/mac/lldbuild/build/bin/ld.lld \ - ./scripts/build.sh -# -> build/orbisrpc.elf (raw payload), build/orbisrpc.fself, build/orbisrpc-eboot.bin -``` - -The GoldHEN payload to deploy is the **raw ELF**, `build/orbisrpc.elf`, -uploaded as `orbisrpc.bin` (the `orbisrpc.fself`/`orbisrpc-eboot.bin` outputs -are for the PKG/fself route, not GoldHEN's auto-payload loader). No toolchain -= no build. - ---- - -## Installing on the PS4 (no PC after first build) - -1. Build `orbisrpc.pkg` (or grab the `.elf` payload) on any Mac/computer. -2. Transfer to the PS4 over FTP, or on a USB stick. -3. **Daemon route (recommended):** put `orbisrpc.elf` in - `/data/GoldHEN/payloads/` (named `orbisrpc.bin`) — it auto-loads on every - boot and runs in the background while you game. (GoldHEN 2.2.) -4. Or install `orbisrpc.pkg` like any homebrew app if you prefer a foreground - launcher (note: it suspends once a game opens, so the daemon route is what - powers presence-during-play). - -Config lives at `/data/orbisRPC/config.json` — edit it over FTP or on a USB stick. -Logs go to `/data/orbisRPC/log.txt`. - ---- - -## One-time setup: your Discord user token - -The daemon connects to Discord's gateway as *you*, so it needs your **user -session token** (the same string the Discord client itself uses). This is the -only auth Discord accepts on the gateway without a running client — OAuth2 -app tokens are rejected with close `4004` (v1 of this repo tried and failed -exactly that way). - -1. Get your user token from a logged-in Discord session (search "how to obtain - discord user token" — many guides exist; only follow steps you understand). -2. Paste it into `/data/orbisRPC/config.json` over FTP: - `"token": "your-token-here"`. -3. Reboot / relaunch the game. The log prints `discord: gateway ready`, then - `presence: `. - -That's it — no developer app, no OAuth dance, nothing else. - -Optional: `"application_id"` in config is only needed if you upload custom -asset images to a Discord application and want them attached to the activity. - -## Safety / ToS notes - -- Using your user token programmatically is technically against Discord's - Terms of Service. This is exactly how every working headless presence tool - operates (multi-scrobbler's headless mode, etc.). There is no precedent of - bans for non-spam presence usage, but the risk is yours. -- Treat the token like a password: it grants full account access. Never share - the config file or commit a real token to this repo. -- Changing your password or "log out of all devices" invalidates the token; - grab a fresh one if the log shows close code `4004`. - ---- +A user session token grants full account access: never share the config, +never commit a real token. Token use for presence is against Discord's ToS +(Standard practice for headless presence tools; risk is yours — see docs). ## License -MIT — see `LICENSE`. Headers + minimal JSON parser (`jsonlite`) are self-contained -(no third-party runtime deps beyond the Orbis toolchain). +Project license to be finalized (MIT vs GPL). No GPL source is copied into +this tree; the OpenOrbis toolchain it builds against is GPL-3.0. diff --git a/docs/DAEMON.md b/docs/DAEMON.md new file mode 100644 index 0000000..1574073 --- /dev/null +++ b/docs/DAEMON.md @@ -0,0 +1,45 @@ +# Daemon design (v1.0.0) + +## Loop + +Outer connect cycles (jittered exponential backoff, 60 s cap ×10, then +10-minute cadence, never exits) wrap an inner 1 s session loop. Token-4004 +never kills the daemon at either level: it backs off and retries so a fixed +token lands on its own. + +## States + +`NONE -> HOME <-> GAME`, every transition logged. Game commits need 2 +consecutive polls; closes need 2 misses. Home posts once (timerless logo +tile) and re-posts after every reconnect (a drop can never leave a blank +tile). Every 15 min the current state reposts regardless (reconciliation). + +## Detection + +1. `/mnt/sandbox/_000` mount = authoritative running ID. +2. eboot-process count change = launch/close right now (fast-switch). +3. Save/appdir/app.pkg-atime signals disambiguate. + +## Names (first hit wins, no baked tables ever) + +1. `titles` map in config (manual override + self-learned). +2. System app.db, read-only SQLite: `tbl_appbrowse.titleName`, then + `tbl_appinfo` TITLE keys, then `/user/appmeta//param.json`. +3. Local pronunciation.xml / param.sfo / app.xml. +4. Sony TMDB live (`_00` + HMAC-SHA1 URL — byte-identical to the PC + tools; unreachable from most consoles, kept as fallback). +5. Raw ID (never shown twice; retried after 5 min, never frozen). + +## Art + +mp: proxy via external-assets → uploaded asset key → icon-pack pattern. +Dangling keys/URLs are dropped, never sent (they blank the activity). +Game tile carries a small system badge. 7-day disk cache + memory cache. + +## Time, sessions, health + +SNTP (connected UDP, Nov 2023–Dec 2034 window) drives timer ms. Sessions +persist atomically with validation; 10-min resume window; playtime ledger. +Health: dirty-boot marker (marker-first ordering), crash counter, 3-strike +safe mode, signed all-or-nothing updates with boot rollback. +Single-instance lock with sysctl liveness + exact-name check. diff --git a/docs/INSTALLER.md b/docs/INSTALLER.md new file mode 100644 index 0000000..de08c5f --- /dev/null +++ b/docs/INSTALLER.md @@ -0,0 +1,40 @@ +# Installer (Setup PKG, `ORPC00001`) + +## What it does + +One linear flow, forward-only (every No skips ahead, nothing loops back): +confirm → copy daemon to `/data/orbisRPC/orbisrpc.elf` + every payload dir +(`GoldHEN/payloads`, `GoldHEN/bin/elf`, `/data/payloads`, `/data/bin/elf`, +`/user/data/payloads`) with a per-path OK/denied report → WiFi check → +token prompt (skipped when valid) → evict rotation → loopback inject +(127.0.0.1:9090→9021→9020) → boot proof (waits for first log heartbeat) +→ done. Declining install offers a read-only status screen instead. + +## Navigation law + +No branch ever returns to start. Cancel/skip always moves forward. The only +exits are Done, explicit close, or fatal boot failure. + +## Console facts encoded + +- Splash must hide before dialogs (`sceSystemServiceHideSplashScreen`) + + 3 s foreground settle, or the first dialog flash-dismisses. +- Dialog/IME/IME-backend sysmodules + internal SYSTEM/USER/COMMON modules + load before use (unloaded calls panic). +- Network stack: internal NET module + `sceNetInit` + pool, verified with a + probe socket. All connects non-blocking with hard deadlines (blocking + connect ignores timeouts on filtered hosts — 75 s hole). +- Config writes are atomic (tmp+fsync+rename) with read-back proof. +- IME wait is bounded; EAGAIN send retries are capped; asset key charset + validated (bad keys blank the activity). + +## Auto-start + +GoldHEN PayLoader AutoRun (2.4b18.10+): enable it for `orbisrpc` once and +the daemon starts on every jailbreak. The queue is menu-managed; the +installer shows where, it can't write the queue itself. + +## Building + +`make -f installer/Makefile` (`OO_PS4_TOOLCHAIN`, llvmshim). Staged assets: +daemon + evict ELFs. Output: `IV0000-ORPC00001_00-ORBISRPCSETUP000.pkg`. diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md new file mode 100644 index 0000000..545b2c2 --- /dev/null +++ b/docs/TROUBLESHOOTING.md @@ -0,0 +1,41 @@ +# Troubleshooting + +## `?` tile / missing art + +1. Daemon log first: `art: resolved mp` = our side fine, look downstream. +2. Vesktop (desktop mod) shows `?` for tiles the official clients and + phone render correctly. Check phone before reporting. +3. Black/blank idle tile = `home_art` empty or pointing at a dead URL. + Set it to a live PNG (default: project PlayStation logo). + +## Name shows raw ID (CUSA…) + +Chain: config `titles` → app.db → local files → Sony TMDB → fallback. +TMDB is TCP-filtered from most consoles (proven, not fixable in code). +If app.db misses too, add one line to `titles` — or wait: first-hit +self-learns, so one manual entry fixes a title forever. + +## Installer opens then instantly exits + +The first dialog was auto-dismissed (system transition). Current builds +hide the splash + settle 3 s first. Reinstall the latest PKG. + +## Kernel panic on installer launch (fixed) + +Called dialogs without loading sysmodules. Fixed: module loads in +`ui_init`, app exits quietly if they fail. If you still panic, your PKG +predates the fix — reinstall. + +## Loaders closed (9090/9021/9020) + +Normal when GoldHEN's BinLoader toggle is off. Flip it in GoldHEN's menu. +Reboot wipes jailbreak + daemon (RAM-only); re-jailbreak, then inject. + +## Token rejected (close 4004) + +Token dead (password change / logout-all). Paste a fresh one; the daemon +survives 4004s and picks it up without reinstall. + +## No FTP (connection refused) + +GoldHEN FTP toggle off, or console rebooted to stock. Re-jailbreak.