mirror of
https://github.com/SirHumza/orbisRPC.git
synced 2026-10-06 09:00:37 +02:00
orbisRPC v1.0.0: signed-only updates, heap fix, plugin name fallback, dead code purge, production release key, secret guard, docs accuracy
This commit is contained in:
1 parent
3e0f4b492c
commit
4989941642
17 files changed
+79
-171
No files matched your search
@@ -11,6 +11,8 @@ jobs:
|
||||
run: make -C tests asan
|
||||
- name: e2e contracts
|
||||
run: python3 tests/e2e_consumer.py
|
||||
env:
|
||||
ORBISRPC_STRICT_SECRETS: "1"
|
||||
sdk-payload:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -28,3 +28,4 @@ installer/pkg.gp4
|
||||
installer/assets/daemon.elf
|
||||
installer/assets/evict.elf
|
||||
installer/sce_sys/param.sfo
|
||||
tests/test_utils_asan
|
||||
@@ -2,6 +2,8 @@
|
||||
<img src="config/icons/logo.png" width="420" alt="orbisRPC">
|
||||
</p>
|
||||
|
||||
# orbisRPC — Discord Rich Presence for PS4 (GoldHEN RPC)
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/SirHumza/orbisRPC/releases/tag/v1.0.0"><img src="https://img.shields.io/badge/version-1.0.0-ffd800?style=flat-square" alt="version"></a>
|
||||
<img src="https://img.shields.io/badge/PS4-GoldHEN-003791?style=flat-square" alt="PS4 GoldHEN">
|
||||
@@ -20,22 +22,24 @@ playing to Discord: name, cover art, timer. No PC at runtime.</p>
|
||||
1. Grab `OrbisRPC-Setup-1.0.0.pkg` from the
|
||||
[Releases page](https://github.com/SirHumza/orbisRPC/releases/tag/v1.0.0)
|
||||
and install it with Package Installer.
|
||||
2. Open **orbisRPC Setup** → say Yes. It drops the daemon into GoldHEN's
|
||||
`bin/elf` and saves your Discord token.
|
||||
3. Start **orbisrpc** from GoldHEN's payload menu, launch a game, watch Discord.
|
||||
2. Open **orbisRPC Setup**. It stages `orbisrpc.bin` + `evict.elf` in
|
||||
`/data/payloads`, writes `/data/orbisRPC/config.json`, evicts any old
|
||||
daemon, then asks for your Discord token.
|
||||
3. Launch **orbisrpc** from Payload Guest (GoldHEN's payload menu),
|
||||
launch a game, watch Discord.
|
||||
|
||||
After a reboot: re-jailbreak, then enable AutoRun for `orbisrpc` in GoldHEN's
|
||||
payload menu once — it starts itself on every jailbreak after that.
|
||||
After a reboot: re-jailbreak, then enable AutoRun for `orbisrpc` in
|
||||
Payload Guest once — it starts itself on every jailbreak after that.
|
||||
|
||||
## What you get
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 🎮 **Any game, no lists** | Names resolve from your console's own database — CUSA, PPSA, indies, all covered with zero per-game setup. |
|
||||
| 🎮 **Any game, no lists** | Names resolve from your console's metadata (SFO, app.xml) plus Sony's TMDB — CUSA, PPSA, indies, zero per-game setup. |
|
||||
| 🖼️ **Real cover art** | Game art served per title, PlayStation logo when idle. |
|
||||
| ⏱️ **True timers** | Survive reconnects and restarts, resume across quick game switches. |
|
||||
| 🧠 **Self-learning** | First-seen titles are remembered, so later boots resolve instantly. |
|
||||
| 🔄 **Self-updating** | Signed daemon updates with boot rollback. No reinstall treadmill. |
|
||||
| 🔄 **Self-updating** | Daemon updates land from GitHub releases with automatic rollback. No reinstall treadmill. |
|
||||
| 📦 **One-tap installer** | Setup PKG: install → token → payload in place. |
|
||||
|
||||
## How it works
|
||||
@@ -45,7 +49,7 @@ PS4 (GoldHEN) Discord
|
||||
┌─────────────────────────┐ ┌──────────────────┐
|
||||
│ orbisRPC daemon │ TLS │ your profile │
|
||||
│ sandbox scan → game ID │ ◄──► │ Playing Game │
|
||||
│ app.db → display name │ │ [cover] [timer] │
|
||||
│ metadata/TMDB → name │ │ [cover] [timer] │
|
||||
└─────────────────────────┘ └──────────────────┘
|
||||
```
|
||||
|
||||
|
||||
@@ -28,12 +28,12 @@ predates the fix — reinstall.
|
||||
|
||||
## Payload won't start
|
||||
|
||||
The Setup PKG only writes `/data/GoldHEN/bin/elf/orbisrpc.bin` — it never
|
||||
launches anything. Start it from GoldHEN's payload menu, or enable AutoRun
|
||||
for `orbisrpc` once so it boots with every jailbreak.
|
||||
The Setup PKG only writes `/data/payloads/orbisrpc.bin` — it never
|
||||
launches anything. Start it from Payload Guest (GoldHEN's payload menu),
|
||||
or enable AutoRun for `orbisrpc` once so it boots with every jailbreak.
|
||||
|
||||
Manual injection (see `injecting.md`) still exists and needs the loaders
|
||||
open: ports 9090/9021/9020 are closed whenever GoldHEN's BinLoader toggle
|
||||
open: ports 9021/9020 are closed whenever GoldHEN's BinLoader toggle
|
||||
is off. Flip it in GoldHEN's menu. Reboot wipes jailbreak + daemon
|
||||
(RAM-only), so re-jailbreak first.
|
||||
|
||||
|
||||
+2
-8
@@ -65,13 +65,7 @@ GoldHEN's BinLoader arms **once**. Any empty port check (`connect_ex`,
|
||||
arm** — the real payload then arrives at a dead listener. Sequence is
|
||||
always: tap → say go → fire immediately → verify. Never probe first.
|
||||
|
||||
## Method 3 — in-app injector
|
||||
|
||||
The OrbisRPC setup app injects over loopback itself
|
||||
(`127.0.0.1:9020`, fallback `9090`) from its menu. Needs a listening
|
||||
loader exactly like Method 2.
|
||||
|
||||
## Method 4 — sender page (no PC tools)
|
||||
## Method 3 — sender page (no PC tools)
|
||||
|
||||
`https://SirHumza.github.io/orbisrpc-host/` in the PS4 browser
|
||||
auto-sends the bundled backend to the console's own loader and prints
|
||||
@@ -91,7 +85,7 @@ the result on screen.
|
||||
|
||||
| Symptom | Meaning | Fix |
|
||||
|---|---|---|
|
||||
| `Connection refused` on 9020/9090 | No listener armed | Tap BinLoader / open payloader page, retry instantly |
|
||||
| `Connection refused` on 9021/9020 | No listener armed | Tap BinLoader / open payloader page, retry instantly |
|
||||
| `payload launched successfully` then silence, no log | Loader segfault (see above) | Update GoldHEN ≥ v2.4b18.5, use BinLoader server |
|
||||
| `Error handling payload` | Loader rejected the bytes | Re-check file integrity (`shasum`), resend |
|
||||
| Log exists but `FATAL: token rejected (4004)` | Token rotated/dead | Fresh token into `/data/orbisRPC/config.json`, relaunch |
|
||||
|
||||
+2
-2
@@ -68,8 +68,8 @@ $(INTDIR)/jsonlite.o: orbisrpc/jsonlite.c
|
||||
$(CC) $(CFLAGS) -o $@ $<
|
||||
|
||||
# Stage the daemon + evict payloads + config into the app image.
|
||||
# config.json is pre-populated with the Discord token so the
|
||||
# installer skips token entry on fresh installs.
|
||||
# config.json carries the SET_ME placeholder; a pre-seeded valid token
|
||||
# (kept out of the repo) makes the installer skip token entry.
|
||||
installer/assets/daemon.elf: build-sdk/orbisrpc_sdk.elf
|
||||
cp $< $@
|
||||
installer/assets/evict.elf: build-sdk/evict.elf
|
||||
|
||||
@@ -242,8 +242,8 @@ static int step_files(void){
|
||||
FILE *src = fopen("/app0/assets/config.json", "rb");
|
||||
if(src){
|
||||
fclose(src);
|
||||
copy_file("/app0/assets/config.json", ICFG_PATH);
|
||||
ilog("cfg-copy", 0, 0, 0);
|
||||
int rc = copy_file("/app0/assets/config.json", ICFG_PATH);
|
||||
ilog("cfg-copy", rc == 0 ? 0 : (errno ? errno : -1), 0, 0);
|
||||
} else {
|
||||
ilog("cfg-noasset", errno, 0, 0);
|
||||
/* Fallback: write template with pre-set token. */
|
||||
|
||||
@@ -113,39 +113,6 @@ int ui_ok(const char *msg){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Yes/No dialog. Returns 1 (Yes) or 0 (No/closed).
|
||||
* The dialog uses YESNO_FOCUS_NO which focuses the "No" button.
|
||||
* On this console, Circle=confirm and X=back. The confirm
|
||||
* button selects the focused button, so X acts as confirm
|
||||
* and selects No, while O acts as back and selects Yes.
|
||||
* Since the dialog inverts the result, this returns 1 when
|
||||
* X is pressed (Yes) and 0 when O is pressed (No) — matching
|
||||
* the system's confirm button behavior. Kept for future use. */
|
||||
int ui_confirm(const char *msg){
|
||||
OrbisMsgDialogParam param;
|
||||
OrbisMsgDialogUserMessageParam um;
|
||||
OrbisMsgDialogResult res;
|
||||
memset(&res, 0, sizeof res);
|
||||
sceMsgDialogTerminate();
|
||||
if(sceMsgDialogInitialize() < 0) return -1;
|
||||
base_init(¶m);
|
||||
memset(&um, 0, sizeof um);
|
||||
um.msg = msg;
|
||||
/* YESNO_FOCUS_NO focuses the "No" button. On a Circle-accept
|
||||
* console the confirm button selects the focused button, so
|
||||
* X (confirm) selects No and O (back) selects Yes. The
|
||||
* result is inverted: X→buttonId=NO→returns 1 (Yes). */
|
||||
um.buttonType = ORBIS_MSG_DIALOG_BUTTON_TYPE_YESNO_FOCUS_NO;
|
||||
param.userMsgParam = &um;
|
||||
if(sceMsgDialogOpen(¶m) < 0){ sceMsgDialogTerminate(); return -1; }
|
||||
while(sceMsgDialogUpdateStatus() != ORBIS_COMMON_DIALOG_STATUS_FINISHED)
|
||||
sceKernelUsleep(20000);
|
||||
sceMsgDialogClose();
|
||||
sceMsgDialogGetResult(&res);
|
||||
sceMsgDialogTerminate();
|
||||
return res.buttonId == ORBIS_MSG_DIALOG_BUTTON_ID_YES;
|
||||
}
|
||||
|
||||
static int progress_open = 0;
|
||||
|
||||
int ui_progress_open(const char *msg){
|
||||
|
||||
@@ -10,10 +10,6 @@ int ui_init(void);
|
||||
|
||||
/* Info dialog with OK. 0 shown, -1 failed to open. */
|
||||
int ui_ok(const char *msg);
|
||||
/* Yes/No dialog: X = enter (Yes), O = back (No). 1 yes, 0 no/closed,
|
||||
* -1 error. */
|
||||
int ui_confirm(const char *msg);
|
||||
|
||||
/* Progress dialog. Open once, update, close. 0 ok, -1 error. */
|
||||
int ui_progress_open(const char *msg);
|
||||
void ui_progress_msg(const char *msg);
|
||||
|
||||
@@ -83,6 +83,8 @@ static void sess_save(const char *tid, const char *name, int64_t started){ jl
|
||||
FILE *f = fopen("/data/orbisRPC/session.json.new", "wb");
|
||||
if(f){
|
||||
int ok = (fputs(s, f) >= 0) && (fflush(f) == 0);
|
||||
/* force bytes to disk before rename (same as cfg_save) */
|
||||
if(ok){ int fd = fileno(f); if(fd < 0 || fsync(fd) != 0) ok = 0; }
|
||||
if(fclose(f) != 0) ok = 0;
|
||||
if(ok) rename("/data/orbisRPC/session.json.new",
|
||||
"/data/orbisRPC/session.json");
|
||||
|
||||
+1
-1
@@ -573,7 +573,7 @@ int detect_name_for_title(const char *titleId, char *out_name, size_t cap){
|
||||
/* Game-process-safe only: small reads plus one bounded network
|
||||
* lookup; no multi-megabyte scans anywhere in this codebase. */
|
||||
if(cfg_title(&g_cfg, titleId, out_name, cap)==0){ log_msg("name: %s via config", out_name); resolve_remember(titleId, out_name, "", 1); return 0; }
|
||||
/* appdb_title(titleId, out_name, cap); */ resolve_remember(titleId, out_name, "", 1); return 0;
|
||||
/* appdb_title removed: no baked table (README "tables-none"). */
|
||||
if(pronunc_title(titleId, out_name, cap)==0){ log_msg("name: %s via appmeta", out_name); resolve_remember(titleId, out_name, "", 1); return 0; }
|
||||
else log_msg("name: appmeta miss for %s", titleId);
|
||||
if(sfo_file_title(titleId, out_name, cap)==0){ log_msg("name: %s via sfo", out_name); resolve_remember(titleId, out_name, "", 1); return 0; }
|
||||
|
||||
+10
-10
@@ -1,22 +1,22 @@
|
||||
/* release_pubkey.h - embedded release-channel public key (P-256, raw X||Y).
|
||||
*
|
||||
* DEV KEY: generated for v1.0.1 development. Before publishing a real
|
||||
* release, generate a production keypair OFFLINE, replace these bytes,
|
||||
* and keep the private key out of the repo:
|
||||
* PRODUCTION KEY: generated 2026-09-25 with
|
||||
* openssl ecparam -name prime256v1 -genkey -noout -out release_priv.pem
|
||||
* openssl ec -in release_priv.pem -pubout -out release_pub.pem
|
||||
* Sign manifest.json with scripts/make_manifest.py (or openssl dgst).
|
||||
* The private key lives OFFLINE outside the repo (macOS host:
|
||||
* ~/.config/orbisrpc/release_priv.pem) and must be backed up offline:
|
||||
* losing it bricks the on-console updater; leaking it fakes releases.
|
||||
* Sign manifest.json with scripts/make_manifest.py --priv release_priv.pem.
|
||||
*/
|
||||
#ifndef ORBISRPC_RELEASE_PUBKEY_H
|
||||
#define ORBISRPC_RELEASE_PUBKEY_H
|
||||
|
||||
/* Uncompressed P-256 X || Y (64 bytes). */
|
||||
static const unsigned char ORBISRPC_RELEASE_PUBKEY[64] = {
|
||||
0x47,0xb8,0x9d,0xb8,0x85,0x3d,0x6c,0xcf,0x7e,0x1a,0xbe,0x6e,0xd1,0x5c,0x2e,0x69,
|
||||
0x66,0x2f,0xa8,0x09,0xbf,0x6d,0xf8,0x9c,0x50,0xe4,0x10,0x0b,0x79,0x4b,0x66,0x1a,
|
||||
0xd7,0x79,0xae,0x2e,0x41,0xc9,0x35,0x5c,0x6f,0xe3,0xba,0xed,0xc9,0x93,0x9a,0xca,
|
||||
0xe8,0x18,0xd5,0x4b,0xeb,0x84,0x20,0x8d,0xb3,0xd2,0x4a,0xfc,0x65,0x81,0x6c,0x6f
|
||||
0xe7,0x31,0xa1,0x93,0x9f,0xe3,0x85,0x36,0x03,0xbf,0x3e,0xb1,0xf0,0xc0,0x55,0x80,
|
||||
0x4e,0xa9,0x19,0xc5,0xca,0xe5,0xe8,0x5c,0x36,0xdc,0x0d,0x6f,0x7e,0x46,0x03,0xdb,
|
||||
0x23,0x2b,0xb9,0x2e,0xb1,0x72,0xa8,0xc4,0x75,0x15,0x99,0x18,0x58,0x59,0xfe,0x8c,
|
||||
0x4d,0x4f,0x31,0xee,0xa3,0xdd,0xfb,0x15,0xae,0x09,0xc3,0x34,0xee,0xf9,0x16,0x54
|
||||
};
|
||||
#define ORBISRPC_RELEASE_KEY_ID "dev-2026-09-20"
|
||||
#define ORBISRPC_RELEASE_KEY_ID "prod-2026-09-25"
|
||||
|
||||
#endif
|
||||
+8
-9
@@ -281,20 +281,19 @@ int tmdb_resolve(const char *titleId, char *name, size_t name_cap,
|
||||
return name[0] ? 0 : -1;
|
||||
}
|
||||
}
|
||||
/* Live Sony CDN first (TMDB over TLS; plain HTTP is blocked
|
||||
* on-console and handled inside http_get/https fallback below).
|
||||
* No baked tables: CUSA code + Sony CDN is the source of truth. */
|
||||
/* Live Sony CDN over TLS first (plain HTTP is blocked on jailbroken
|
||||
* consoles — http_get below is last-resort only). No baked tables:
|
||||
* CUSA code + Sony CDN is the source of truth. */
|
||||
char path[128];
|
||||
if(tmdb_path(titleId, path, sizeof path) != 0) return -1;
|
||||
static char body[TMDB_BODY_MAX];
|
||||
int status = 0;
|
||||
int n = http_get(TMDB_HOST, path, body, sizeof body, &status);
|
||||
int n = https_get_tmdb(path, body, sizeof body, &status);
|
||||
if(n > 0) log_msg("tmdb: live via https for %s", titleId);
|
||||
if(n <= 0){
|
||||
/* Port 80 is blocked from jailbroken consoles; Sony also answers
|
||||
* the same paths over TLS (443). Try HTTPS before giving up so
|
||||
* new installs resolve live like everything else. */
|
||||
n = https_get_tmdb(path, body, sizeof body, &status);
|
||||
if(n > 0) log_msg("tmdb: live via https for %s", titleId);
|
||||
/* Plain HTTP (port 80): blocked from jailbroken consoles, so this
|
||||
* burns the connect timeout before giving up — keep it last. */
|
||||
n = http_get(TMDB_HOST, path, body, sizeof body, &status);
|
||||
}
|
||||
if(n <= 0){ log_msg("tmdb: fetch fail status=%d", status); return -1; }
|
||||
char iname[128] = "", iicon[256] = "";
|
||||
|
||||
+10
-83
@@ -172,7 +172,7 @@ static char *https_get_once(const char *host, const char *path,
|
||||
if(tls_write(t, req, (size_t)rl) < 0){ tls_free(t); return NULL; }
|
||||
/* Read raw response (headers + body) up to header cap + body cap. */
|
||||
size_t rawcap = UPD_HDR_MAX + cap;
|
||||
char *raw = (char*)malloc(rawcap);
|
||||
char *raw = (char*)malloc(rawcap + 1); /* +1: NUL pad when a read fills cap exactly */
|
||||
if(!raw){ tls_free(t); return NULL; }
|
||||
size_t rl2 = 0;
|
||||
int64_t dl = orbis_mono_s() + UPD_DEADLINE_S + 20;
|
||||
@@ -280,57 +280,6 @@ static int stage_file(const char *target, const unsigned char *data, size_t n){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SHA256 of a buffer, hex-encoded (64 chars + NUL). Returns 0 on success. */
|
||||
static int sha256_hex(const unsigned char *data, size_t n, char out[65]){
|
||||
unsigned char dig[32];
|
||||
mbedtls_sha256_context sc;
|
||||
mbedtls_sha256_init(&sc);
|
||||
int ok = mbedtls_sha256_starts(&sc, 0) == 0 &&
|
||||
mbedtls_sha256_update(&sc, data ? data : (const unsigned char *)"", n) == 0 &&
|
||||
mbedtls_sha256_finish(&sc, dig) == 0;
|
||||
mbedtls_sha256_free(&sc);
|
||||
if(!ok) return -1;
|
||||
for(int i=0;i<32;i++) snprintf(out+2*i, 3, "%02x", dig[i]);
|
||||
out[64]=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Look up "<filename>" in a SHA256SUMS body ("<hash> <name>\n" lines).
|
||||
* Returns 0 and fills want_hex when found. */
|
||||
static int sums_lookup(const char *sums, const char *filename, char want_hex[65]){
|
||||
size_t fnlen = strlen(filename);
|
||||
const char *p = sums;
|
||||
while(*p){
|
||||
while(*p==' '||*p=='\t'||*p=='\r'||*p=='\n') p++;
|
||||
if(!*p) break;
|
||||
if(strlen(p) < 64) break;
|
||||
char hex[65];
|
||||
memcpy(hex, p, 64); hex[64]=0;
|
||||
int ishex=1;
|
||||
for(int i=0;i<64;i++){
|
||||
char c=hex[i];
|
||||
if(!((c>='0'&&c<='9')||(c>='a'&&c<='f')||(c>='A'&&c<='F'))){ ishex=0; break; }
|
||||
}
|
||||
const char *e = strchr(p, '\n');
|
||||
size_t linelen = e ? (size_t)(e-p) : strlen(p);
|
||||
if(ishex && linelen > 65){
|
||||
const char *nl = p+64;
|
||||
while(nl<p+linelen && (*nl==' '||*nl=='\t'||*nl=='*')) nl++;
|
||||
if((size_t)(p+linelen-(nl)) >= fnlen && !memcmp(nl, filename, fnlen) &&
|
||||
(nl[fnlen]=='\n'||nl[fnlen]=='\r'||nl[fnlen]==' '||nl[fnlen]=='\t'||nl[fnlen]==0||nl[fnlen]=='*')){
|
||||
for(int i=0;i<64;i++){
|
||||
char c=hex[i];
|
||||
want_hex[i]=(c>='A'&&c<='F')?(char)(c-'A'+'a'):c;
|
||||
}
|
||||
want_hex[64]=0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
p = e ? e+1 : p+linelen;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Download a release asset by exact name. Returns heap body or NULL. */
|
||||
static char *fetch_asset(const jl_val_t *assets, const char *want_name,
|
||||
size_t cap, int *status, size_t *out_len){
|
||||
@@ -428,12 +377,14 @@ int updater_check_and_stage(void){
|
||||
free(sbody);
|
||||
if(!have_manifest){ free(mbody); mbody = NULL; }
|
||||
}
|
||||
/* Compat fallback: SHA256SUMS (unsigned but hash-pinned). */
|
||||
char *sums = NULL;
|
||||
/* Refuse unsigned updates outright. SHA256SUMS comes from the
|
||||
* same release as the binaries, so it pins nothing against
|
||||
* release-asset compromise — exactly what the signed manifest
|
||||
* defends against (ORX-UPDATE-002). */
|
||||
if(!have_manifest){
|
||||
sums = fetch_asset(assets, "SHA256SUMS", 65536, &status, NULL);
|
||||
if(!sums)
|
||||
log_msg("updater: WARN ORX-UPDATE-002: no manifest and no SHA256SUMS; refusing unsigned update");
|
||||
log_msg("updater: no valid signed manifest; refusing update (ORX-UPDATE-002)");
|
||||
jl_free(r);
|
||||
return 0;
|
||||
}
|
||||
/* Two-phase commit: download + verify EVERY asset first, then
|
||||
* activate all at once. A failure anywhere stages nothing, so
|
||||
@@ -468,31 +419,8 @@ int updater_check_and_stage(void){
|
||||
pend_fail = 1;
|
||||
break;
|
||||
}
|
||||
if(have_manifest){
|
||||
if(manifest_check(&mf, nm->str, (unsigned char*)bin, al) != 0){
|
||||
log_msg("updater: asset %s not in manifest or hash mismatch; refusing (ORX-UPDATE-002)", nm->str);
|
||||
free(bin);
|
||||
pend_fail = 1;
|
||||
break;
|
||||
}
|
||||
} else if(sums){
|
||||
char want[65];
|
||||
if(sums_lookup(sums, nm->str, want) != 0){
|
||||
log_msg("updater: asset %s not in SHA256SUMS; refusing", nm->str);
|
||||
free(bin);
|
||||
pend_fail = 1;
|
||||
break;
|
||||
}
|
||||
char got[65];
|
||||
if(sha256_hex((unsigned char*)bin, al, got) != 0 || strcmp(got, want) != 0){
|
||||
log_msg("updater: asset %s hash mismatch; refusing", nm->str);
|
||||
free(bin);
|
||||
pend_fail = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* No manifest and no SHA256SUMS: refuse unsigned bytes. */
|
||||
log_msg("updater: asset %s refused: no trust anchor (ORX-UPDATE-002)", nm->str);
|
||||
if(manifest_check(&mf, nm->str, (unsigned char*)bin, al) != 0){
|
||||
log_msg("updater: asset %s not in manifest or hash mismatch; refusing (ORX-UPDATE-002)", nm->str);
|
||||
free(bin);
|
||||
pend_fail = 1;
|
||||
break;
|
||||
@@ -519,7 +447,6 @@ int updater_check_and_stage(void){
|
||||
log_msg("updater: incomplete set; staged nothing (versions stay matched)");
|
||||
}
|
||||
for(int pi = 0; pi < pend_n; pi++) free(pend[pi].bin);
|
||||
free(sums);
|
||||
free(mbody);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ MBEDTLS_DIR := ../third_party/mbedtls/library
|
||||
MBEDTLS_SRCS := $(filter-out $(MBEDTLS_DIR)/net_sockets.c $(MBEDTLS_DIR)/timing.c $(MBEDTLS_DIR)/entropy_poll.c,$(wildcard $(MBEDTLS_DIR)/*.c))
|
||||
|
||||
ORBIS_SRCS := ../orbisrpc/jsonlite.c ../orbisrpc/b64.c ../orbisrpc/sfo.c ../orbisrpc/tmdb_crypto.c ../orbisrpc/updater_util.c ../orbisrpc/art.c ../orbisrpc/log.c ../orbisrpc/health.c ../orbisrpc/manifest.c ../orbisrpc/compat.c ../orbisrpc/cfg.c ../orbisrpc/appdb.c ../orbisrpc/discord.c
|
||||
INST_SRCS := ../installer/icfg.c ../installer/nettest.c ../installer/send.c
|
||||
INST_SRCS := ../installer/icfg.c
|
||||
# SQLite amalgamation: -O0 for host iteration speed (payload uses -O2).
|
||||
SQLITE_DIR := ../third_party/sqlite/sqlite-amalgamation-3510100
|
||||
SQLITE_FLAGS := -O0 -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_OMIT_DEPRECATED -I$(SQLITE_DIR)
|
||||
|
||||
@@ -34,6 +34,28 @@ check("host/unit-tests", r.returncode == 0 and "utility tests passed" in r.stdou
|
||||
cfg = src("config/config.json")
|
||||
check("install/template-has-no-token", "SET_ME" in cfg)
|
||||
check("install/art-pack-default", "orbisrpc-host" in cfg)
|
||||
# 2b. no Discord-session-shaped token anywhere the PKG or repo ships.
|
||||
# Fatal when ORBISRPC_STRICT_SECRETS=1 (CI); a local working copy may hold
|
||||
# a dev token and gets a warning instead.
|
||||
tok_re = re.compile(rb"MT[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{20,}")
|
||||
leaks = []
|
||||
for rel in ("installer/installer.c", "installer/config.json",
|
||||
"installer/assets/config.json", "config/config.json"):
|
||||
try:
|
||||
with open(os.path.join(ROOT, rel), "rb") as fh:
|
||||
if tok_re.search(fh.read()):
|
||||
leaks.append(rel)
|
||||
except OSError:
|
||||
pass
|
||||
if leaks:
|
||||
_msg = "token-shaped string in " + ", ".join(leaks)
|
||||
if os.environ.get("ORBISRPC_STRICT_SECRETS") == "1":
|
||||
check("secrets/no-token-in-installer", False, _msg)
|
||||
else:
|
||||
print("WARN secrets/no-token-in-installer (set ORBISRPC_STRICT_SECRETS=1 "
|
||||
"to fail) - " + _msg)
|
||||
else:
|
||||
check("secrets/no-token-in-installer", True)
|
||||
# 3. single-instance lock with recycled-PID guard
|
||||
lock = src("orbisrpc/lock.c")
|
||||
check("runtime/single-lock", "lock_acquire" in src("orbisrpc/daemon.c"))
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "../orbisrpc/discord.h"
|
||||
#include "../orbisrpc/detect.h"
|
||||
#include "../installer/icfg.h"
|
||||
#include "../installer/nettest.h"
|
||||
#include "sqlite3.h"
|
||||
#include <string.h>
|
||||
|
||||
@@ -611,11 +610,6 @@ static void test_installer_cfg(void) {
|
||||
assert(icfg_get_int(path, "poll_interval_s", &n) == 0 && n == 12);
|
||||
/* missing file: loads fail soft, save still works */
|
||||
assert(icfg_get_str("/nonexistent/x.json", "k", st, sizeof st) != 0);
|
||||
/* net probes fail soft on garbage */
|
||||
assert(net_probe(NULL, 443, 2) == 0);
|
||||
assert(net_probe("", 443, 2) == 0);
|
||||
assert(net_probe("127.0.0.1", 1, 1) == 0);
|
||||
assert(net_probe("nonexistent.invalid", 443, 1) == 0);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
Reference in new issue
Block a user