diff --git a/deploy/.DS_Store b/deploy/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/deploy/.DS_Store differ diff --git a/deploy/SETUP.md b/deploy/SETUP.md deleted file mode 100644 index f0b20c9..0000000 --- a/deploy/SETUP.md +++ /dev/null @@ -1,130 +0,0 @@ -# orbisRPC — Deploy + setup guide - -Target: GoldHEN 2.3+ jailbroken PS4, **GoldHEN plugin route** (the native, -auto-starting mechanism — same one the GTA mod menu uses). - -**Why a plugin and not a payload:** `/data/GoldHEN/payloads/` is NOT an -auto-load folder (PPPwn stage2 only loads `goldhen.bin` from there; payload -auto-loading from a folder is an unimplemented GoldHEN feature request #296). -The only auto-start mechanism that works on-boot with zero PC involvement is -the GoldHEN **plugin loader**, driven by `/data/GoldHEN/plugins.ini`. - -## 1. Copy the plugin to the console - -Via FTP (console must be awake and online), build it first: - -``` -OO_PS4_TOOLCHAIN=~/PS4Toolchain/OpenOrbis/PS4Toolchain \ - GOLDHEN_SDK=/tmp/ghsdk LLD=/Users/mac/lldbuild/build/bin/ld.lld \ - make -C plugin -# -> plugin/build/orbisrpc_plugin.prx -``` - -Then deploy: - -``` -put plugin/build/orbisrpc_plugin.prx -> /data/GoldHEN/plugins/orbisrpc_plugin.prx -``` - -## 2. plugins.ini - -`/data/GoldHEN/plugins.ini` must list the plugin. The `[default]` section loads -it for ANY game title, so presence auto-starts every time a game launches: - -``` -[default] -/data/GoldHEN/plugins/orbisrpc_plugin.prx=true -``` - -Existing per-title sections (e.g. the GTA menu `[CUSA00411]`) are untouched. -A ready-made file lives at `plugin/plugins.ini.ps4`. - -## 3. Seed the config - -``` -mkdir /data/orbisRPC -put config/config.json -> /data/orbisRPC/config.json -``` - -The plugin reads `/data/orbisRPC/config.json` (cfg.h: `CFG_PATH`), logs to -`/data/orbisRPC/log.txt` (`LOG_PATH`), and caches per-game state in -`/data/orbisRPC/.lastgame/`. - -## 4. One-time Discord setup: your user token - -The daemon authenticates to the gateway with your **Discord user session -token**. There is no developer app / OAuth flow anymore — the public gateway -rejects OAuth2 access tokens with close `4004` (that was v1's fatal bug). - -1. Get your user token from a logged-in Discord session (search "how to obtain - discord user token"; only follow steps you understand). -2. Edit `/data/orbisRPC/config.json` over FTP/USB and set: - - `"token"`: your user token - - `"application_id"`: optional, only for custom uploaded asset images - -## 5. Launch a game + validate - -Launch any game (e.g. GTA V). The plugin loads into the game process, reads the -title id via the GoldHEN SDK, and starts the daemon. Check: - -``` -get /data/orbisRPC/log.txt -``` - -Expected lines: - -``` -[..] ws: connected (handshake ok) -[..] discord: identify sent, hb=41s -[..] discord: gateway ready -[..] presence: -``` - -Your Discord profile now shows **Playing ** with an elapsed timer. -Exit to the home screen and presence clears while you stay shown as online -(the plugin unloads with the game process). - -## 6. Token lifecycle - -A user session token is long-lived; there is nothing to refresh. It becomes -invalid if you change your password or "log out of all devices" — grab a fresh -one when the log shows close code `4004` (the daemon exits instead of -hammering the gateway, since repeated bad auth can earn an IP ban). - -Config lives on the PS4 at `/data/orbisRPC/config.json` — no PC needed at runtime. - -## Troubleshooting - -| Symptom | Cause / fix | -|---|---| -| no `log.txt` at all after launching a game | plugin didn't load: check `plugins.ini` has the `[default]` section + correct path, and GoldHEN has `[PluginLoader] PluginLoader_Enabled=1` in its config.ini. | -| `FATAL: ... put your Discord user token` | config missing or `token` still `SET_ME`. Fill in step 4. | -| `gateway closed during auth: 4004` | token wrong/expired/revoked. Re-do step 4. | -| `no 101:` in log | Discord blocked the TLS handshake — check clock / network. | -| `heartbeat timeout` / `gateway dropped` loops | network instability; reconnect is automatic with backoff. | -| game name shows `CUSAxxxxx` | app.xml/app.db lookup didn't find a human name; titleId fallback. | -| presence shows the wrong game | payload-mode detection picks the most-recently-installed title (`/data/app` mtime heuristic) — use the plugin route, which knows the exact title id. | - -## Build on Mac (if rebuilding) - -``` -OO_PS4_TOOLCHAIN=~/PS4Toolchain/OpenOrbis/PS4Toolchain \ - LLD=/Users/mac/lldbuild/build/bin/ld.lld \ - ./scripts/build.sh -# -> build/orbisrpc.elf (payload ELF, BinLoader route — not auto-loaded) - -OO_PS4_TOOLCHAIN=~/PS4Toolchain/OpenOrbis/PS4Toolchain \ - GOLDHEN_SDK=/tmp/ghsdk LLD=/Users/mac/lldbuild/build/bin/ld.lld \ - make -C plugin -# -> plugin/build/orbisrpc_plugin.prx (the deployed artifact) -``` - -## Repo layout - -``` -orbisrpc/daemon.c shared daemon loop (payload + plugin use it) -orbisrpc/detect.c foreground detection + titleid->name resolution -plugin/plugin.c GoldHEN plugin entry (plugin_load / plugin_unload) -plugin/Makefile builds orbisrpc_plugin.prx against GoldHEN SDK -plugin/plugins.ini.ps4 ready-to-deploy plugins.ini with [default] section -``` \ No newline at end of file diff --git a/orbisrpc/daemon.c b/orbisrpc/daemon.c index 846ff21..1d43752 100644 --- a/orbisrpc/daemon.c +++ b/orbisrpc/daemon.c @@ -38,6 +38,7 @@ int daemon_run(const char *fixed_game_name){ s_stop = 0; mkdir(DATA_DIR, 0777); log_init(LOG_PATH); + log_msg("orbisRPC daemon start — build %s %s", __DATE__, __TIME__); cfg_load(CFG_PATH, &g_cfg); if(!g_cfg.enabled){ log_msg("disabled in config; exiting"); log_close(); return 0; } if(!have_token(&g_cfg)){ diff --git a/orbisrpc/tls.c b/orbisrpc/tls.c index beb53c3..3178f11 100644 --- a/orbisrpc/tls.c +++ b/orbisrpc/tls.c @@ -26,6 +26,12 @@ typedef struct { const br_x509_class *vtable; br_x509_decoder_context dc; br_x509_pkey pkey; + /* Deep-copied key bytes: br_x509_decoder_get_pkey() returns pointers + * INTO the decoder's scratch buffers, which the next certs in the chain + * overwrite. Capturing the leaf key must own its bytes. */ + unsigned char qbuf[133]; /* max EC point (P-521) */ + unsigned char nbuf[512]; /* max RSA modulus (BR_MAX_RSA_SIZE/8) */ + unsigned char ebuf[8]; unsigned key_usages; int have_leaf; } mini_x509; @@ -47,7 +53,24 @@ static void mx_end_cert(const br_x509_class **ctx){ const br_x509_pkey *pk = br_x509_decoder_get_pkey(&m->dc); /* keep only the FIRST cert's key — that's the leaf whose key verifies * the ServerKeyExchange signature */ - if(pk && !m->have_leaf){ m->pkey = *pk; m->have_leaf = 1; } + if(pk && !m->have_leaf){ + m->pkey = *pk; + if(pk->key_type == BR_KEYTYPE_EC && pk->key.ec.q + && pk->key.ec.qlen <= sizeof m->qbuf){ + memcpy(m->qbuf, pk->key.ec.q, pk->key.ec.qlen); + m->pkey.key.ec.q = m->qbuf; + }else if(pk->key_type == BR_KEYTYPE_RSA && pk->key.rsa.n && pk->key.rsa.e + && pk->key.rsa.nlen <= sizeof m->nbuf + && pk->key.rsa.elen <= sizeof m->ebuf){ + memcpy(m->nbuf, pk->key.rsa.n, pk->key.rsa.nlen); + memcpy(m->ebuf, pk->key.rsa.e, pk->key.rsa.elen); + m->pkey.key.rsa.n = m->nbuf; + m->pkey.key.rsa.e = m->ebuf; + }else{ + return; /* unusable key: leave have_leaf unset */ + } + m->have_leaf = 1; + } } static unsigned mx_end_chain(const br_x509_class **ctx){(void)ctx; return 0;} static const br_x509_pkey *mx_get_pkey(const br_x509_class *const *ctx, unsigned *usages){ @@ -220,6 +243,11 @@ int tls_write(tls_ctx_t *t, const void *buf, size_t len){ if(time(NULL) > dl){ log_msg("tls: write timeout"); return -1; } usleep(10000); } + /* Encrypt any acked plaintext into a pending record NOW: BearSSL only + * does this on br_ssl_engine_flush() — current_state() alone never + * converts SENDAPP data, so without this the bytes never reach SENDREC + * and are silently dropped. */ + br_ssl_engine_flush(&t->cc.eng, 1); /* flush records out promptly */ int64_t t2 = time(NULL) + 5; for(;;){