Skip to content

fix(web): serve the manifest as a file so the relay csp allows it - #95

Merged
dcolinmorgan merged 1 commit into
dcolinmorgan:mainfrom
null1979:fix/pwa-manifest-csp
Oct 22, 2026
Merged

dcolinmorgan merged 1 commit into
dcolinmorgan:mainfrom
null1979:fix/pwa-manifest-csp

Conversation

@null1979

Copy link
Copy Markdown
Contributor

Chrome on Android refuses to install the web app from any relay. It shows "This app cannot be installed" and offers only a browser shortcut.

Cause

web/index.html gives the manifest as a data:application/json,... URL. The CSP from #82 (WEB_APP_CSP) names no manifest-src, so the manifest fetch falls back to default-src 'self', which blocks data:. Chrome finds no manifest.

Fix

  • Move the manifest to web/manifest.webmanifest, with the same content, and link to it.
  • Serve .webmanifest from the relay as application/manifest+json with no-cache.
  • Keep the CSP as it is. default-src 'self' covers a same-origin manifest.

The manifest needs no token, because it goes through web_asset like the icons. That matters, because Chrome fetches a manifest with no credentials.

Tests

  • New tests/test_web_install.py: serves the page with the relay's real CSP and content types. It asks Chrome through CDP for Page.getAppManifest and Page.getInstallabilityErrors. On main it reports no-manifest and manifest-parsing-or-network-error. With this change it reports none. It skips where no Chrome is found, the same as the other browser tests.
  • tests/test_web_pwa.py: reads the manifest file, and checks that the relay serves it with no token while HERDR_RELAY_TOKEN is set.
  • tests/test_web_assets.py and tests/test_web_theme.py: follow the manifest into its file.
  • tests/run.sh passes.

Checked by hand

  • Chrome on an Android phone installed the app from a relay on this branch, through an HTTPS tunnel.
  • wrangler pages dev web serves the file as application/manifest+json, and Chrome reads it with no errors.

Chrome on Android refused to install the web app from any relay. The
page gave its manifest as a data: URL. The CSP from dcolinmorgan#82 names no
manifest-src, so the fetch falls back to default-src 'self', which
blocks data:. Chrome then finds no manifest and offers only a shortcut.

Move the manifest to web/manifest.webmanifest and link to it. The CSP
stays as it is, because default-src 'self' covers a same-origin file.
The relay serves .webmanifest as application/manifest+json with
no-cache. The file needs no token, which matters because Chrome
fetches a manifest with no credentials.

test_web_install.py serves the page with the relay's real CSP and asks
Chrome through CDP for the manifest and the installability errors. On
the old page it reports no-manifest. With this change it reports none.
@dcolinmorgan
dcolinmorgan merged commit 938c08f into dcolinmorgan:main Oct 22, 2026
3 checks passed
@null1979
null1979 deleted the fix/pwa-manifest-csp branch October 23, 2026 05:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants