From b115c0fd4b843d91aa5403254d3cfb73ba5aa437 Mon Sep 17 00:00:00 2001 From: Knutwurst <36196269+knutwurst@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:05:44 +0200 Subject: [PATCH] Drop leftovers of the "shared master can't install" assumption /api/pkgmeta now calls a package installable when its embedded title id matches the installed game, which is what AppInstallPkg goes by, instead of flagging every shared-master package. The unused UI message for the old refusal is gone, and web/README.md describes the current policy: Shadowmount, unknown and fake titles get neither download nor install, and shared-master packages install like any other. --- src/patchdl_websrv.c | 12 ++++++------ web/README.md | 22 ++++++++++++---------- web/app.js | 1 - 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/patchdl_websrv.c b/src/patchdl_websrv.c index 51ed659..196b32c 100644 --- a/src/patchdl_websrv.c +++ b/src/patchdl_websrv.c @@ -2647,7 +2647,9 @@ on_request(void *cls, struct MHD_Connection *conn, const char *url, } /* Read-only: report the .pkg's embedded content id / title id vs the target - (installed app) ids, to expose the cross-region linkage. No install. */ + (installed app) ids. AppInstallPkg installs by the id inside the package, + so it lands on the game only when they match; where the CDN stores the + pieces (storage_title_id) doesn't matter. No install. */ if (!strncmp(url, "/api/pkgmeta/", 13)) { const char *tid = url + 13; char purl[768] = {0}, durl_[512] = {0}; @@ -2670,13 +2672,11 @@ on_request(void *cls, struct MHD_Connection *conn, const char *url, snprintf(resp, sizeof resp, "{\"ok\":%s,\"pkg_content_id\":\"%s\",\"pkg_title_id\":\"%s\"," "\"is_app\":%s,\"target_content_id\":\"%s\",\"target_title_id\":\"%s\"," - "\"storage_title_id\":\"%s\",\"installable\":%s,\"install_plan\":\"%s\"," - "\"msg\":\"%s\"}", + "\"storage_title_id\":\"%s\",\"installable\":%s," + "\"install_plan\":\"appinstallpkg\",\"msg\":\"%s\"}", rc == 0 ? "true" : "false", ecid, etid, is_app ? "true" : "false", cid, tid, psti, - (psti[0] && strncmp(psti, tid, 9) != 0) ? "false" : "true", - (psti[0] && strncmp(psti, tid, 9) != 0) ? - "cross_region_storage_unsupported" : "installbypackage", + (rc == 0 && !strncmp(etid, tid, 9)) ? "true" : "false", msg); return queue_json_owned(conn, MHD_HTTP_OK, strdup(resp)); } diff --git a/web/README.md b/web/README.md index f0cfdd9..295f644 100644 --- a/web/README.md +++ b/web/README.md @@ -39,8 +39,9 @@ The UI assumes deny-by-default behavior: "source_policy": { "official": { "allow_check": true, "allow_download": true, "allow_install": true }, "external": { "allow_check": true, "allow_download": true, "allow_install": true }, - "shadowmount": { "allow_check": true, "allow_download": true, "allow_install": false }, - "unknown": { "allow_check": true, "allow_download": false, "allow_install": false } + "shadowmount": { "allow_check": true, "allow_download": false, "allow_install": false }, + "unknown": { "allow_check": true, "allow_download": false, "allow_install": false }, + "fake": { "allow_check": true, "allow_download": false, "allow_install": false } }, "cdn_allowlist": [ "sgst.prod.dl.playstation.net", @@ -70,7 +71,7 @@ Per-title source fields: "source_path": "/system_ex/app/PPSA90001_00", "mount_from": "/mnt/usb0/itemzflow/Shadowmounted Test Title", "enabled": true, - "mode": "download_only" + "mode": "disabled" } ``` @@ -83,16 +84,17 @@ shadowmount unknown ``` -The frontend treats `shadowmount` as download-only and `unknown` as blocked for -downloads and installs. Backend code should enforce the same policy even if a -client sends a forged request. +The frontend lists `shadowmount`, `unknown` and `fake` titles under *Not +supported* and offers neither download nor install for them. The backend refuses +both as well, even if a client sends a forged request. For PS5 game updates, the backend may turn a Sony `manifest_url` into a merged local `.pkg` by downloading all manifest pieces. The `delta_url` `*-DP.pkg` is not shown as a separate user action because it can bootstrap the storage/master title instead of the installed regional target. -If `patch_storage_match` is false, the UI keeps download/verify available but -does not offer install or auto-install. Those shared-master packages are signed -for a different storage title id and cannot be retargeted by standalone -AppInstUtil on firmware 11.60. +If `patch_storage_match` is false, the CDN stores the patch pieces under another +regional (master) title id. That is fine: the merged `.pkg` assembled from the +manifest carries the installed title's own content id, and AppInstUtil +`AppInstallPkg` installs it onto that title. The UI only adds a "Shared master" +label. diff --git a/web/app.js b/web/app.js index 2fb496f..40977ea 100644 --- a/web/app.js +++ b/web/app.js @@ -1102,7 +1102,6 @@ async function postJson(url, body) { const REASON_TEXT = { patch_title_mismatch: "Patch metadata targets a different title - install blocked.", - cross_region_storage_unsupported: "Patch bytes are signed for a shared master title; this standalone installer cannot retarget them.", install_not_allowed_for_source: "Install blocked for this source.", source_unknown: "Source unknown — blocked.", source_fake: "Fake packages are not supported.",