Skip to content

fix(sync): cache screenshots under the key the app store hands out - #31

Open
martin-rueegg wants to merge 1 commit into
nextcloud:masterfrom
metaworx:fix/unwrap-proxied-screenshot-urls
Open

martin-rueegg wants to merge 1 commit into
nextcloud:masterfrom
metaworx:fix/unwrap-proxied-screenshot-urls

Conversation

@martin-rueegg

Copy link
Copy Markdown

Since nextcloud/appstore@fd69d12680 the app store stores and serves screenshot URLs already rewritten to https://usercontent.apps.nextcloud.com/<base64url of the source>. sync.php still treats every url in apps.json as the source: it base64-encodes the proxy URL a second time and fetches the proxy itself. The source image is never fetched, and nothing is written under the key the store links to, so every screenshot URL first published since the store switched answers File not found. Screenshots cached before the switch keep working, which is why only new apps and new releases are affected.

Measured 2026-09-25 against /api/v1/platform/33.0.0/apps.json:

  • all 1267 screenshot URLs are in proxy form;
  • 70 answer File not found, and they belong to exactly the 18 apps whose newest release is 2026-09-20 or later;
  • the source host does not matter: GitHub, Codeberg, gitlab.com and self-hosted GitLab URLs are served or not by the same rule.

The fix takes the cache key from the proxy URL's path and fetches its decoded form. URLs not in proxy form are handled as before. A key that is not base64url is skipped, so the path cannot leave cache/.

Checked: for every screenshot in the current apps.json, the resolved key equals the path the store links to, and its decoded source is an https:// URL that re-encodes to the same key.

Fixes #27
Fixes #29
Refs #30 (the report is a PDF; same symptom)
Refs nextcloud/appstore#1913 (the screenshot part; its stale-description part is separate)

Not addressed here:

  • Screenshot mirror returns an empty body for a quarter of all apps #26 (HTTP 200 with an empty body) is a separate symptom: 314 URLs today, most of them cached long before this regression.
  • The key of a source URL longer than 189 characters exceeds the 255-byte file name limit, so such a screenshot can never be cached; info.xsd allows 256.
  • nextcloud/server apps/appstore/lib/Controller/ApiController.php wraps the (now already proxied) screenshot URL in the proxy again, with plain base64_encode, so the app management page of a Nextcloud instance links to a key that will never exist.

🤖 Generated with Claude Code

The app store now serves screenshot URLs already rewritten to point at
this proxy. sync.php encoded that proxy URL a second time and fetched the
proxy itself, so no screenshot published since the switch was ever
fetched, and requests for it answer "File not found".

Take the cache key from the proxy URL's path and fetch its decoded form;
URLs not in proxy form are handled as before.

Assisted-by: Claude Code:Claude Opus 5.5
Signed-off-by: Martin Rüegg <martin.rueegg@metaworx.ch>
@martin-rueegg

Copy link
Copy Markdown
Author

Direct evidence from the live proxy: files exist under the double-encoded keys, i.e. base64url of the proxy URLs the store hands out. Of 60 random screenshots from today's apps.json, looked up under that key:

  • 44 are an empty file,
  • 13 are the sync's own "Preview not available / Image not recognized" placeholder, whose last line is the base64 path of a proxy URL, so the sync fetched the proxy itself,
  • 3 answer 403, because the doubled key exceeds the 255-byte file name limit.

Nextcloud instances wrap the store's URL in the proxy a second time too, so their Apps page links to exactly these double keys; that is fixed in nextcloud/server#64771. Both are needed: with only this PR, the instances' previews turn from placeholders into "File not found".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant