Home-screen icon: the piper replaces iOS's letter tile

iOS asks for apple-touch-icon when saving to the home screen and we
served nothing — hence the gray "B". A 180x180 PNG cropped from the
mascot logo is linked from the shell, served from /static/, and also
answers the cookie-less root probes (/apple-touch-icon*.png) the guard
already treats as public. apple-mobile-web-app-title trims the clip
name to "bggpipe".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
Eric Wagoner
2026-08-03 16:59:27 -04:00
co-authored by Claude Fable 5
parent 44dd03d06a
commit bd1bc5e020
4 changed files with 24 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

+2
View File
@@ -5,6 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><!--TITLE--></title>
<link rel="icon" type="image/png" href="/static/favicon.png">
<link rel="apple-touch-icon" href="/static/apple-touch-icon.png">
<meta name="apple-mobile-web-app-title" content="bggpipe">
<link rel="stylesheet" href="/static/app.css">
</head>
<body>
+11
View File
@@ -1089,8 +1089,19 @@ def create_app(
"logo.jpg": "image/jpeg",
"logo-full.jpg": "image/jpeg",
"favicon.png": "image/png",
"apple-touch-icon.png": "image/png",
}
@app.get("/apple-touch-icon.png")
@app.get("/apple-touch-icon-precomposed.png")
def apple_touch_icon() -> Response:
# iOS probes these root paths (cookie-less) when saving to the
# home screen; the guard already treats them as public
data = (
resources.files("bggpipe") / "static" / "apple-touch-icon.png"
).read_bytes()
return Response(content=data, media_type="image/png")
@app.get("/static/{name}")
def static_asset(name: str) -> Response:
media_type = _STATIC.get(name) # allowlist: no traversal possible
+11
View File
@@ -1048,3 +1048,14 @@ def test_lan_403_is_html_for_navigations(tmp_path):
res = phone.get("/titles", headers={"accept": "text/html,application/xhtml+xml"})
assert res.status_code == 403
assert "access key needed" in res.text # a person sees prose, not JSON
def test_home_screen_icon_is_served_and_public(tmp_path):
cfg = make_cfg(tmp_path)
app = create_app(cfg, client=unauthorized_client(tmp_path), lan_token="sekret")
phone = TestClient(app, base_url="http://192.168.1.99:8377")
# iOS probes cookie-less; both the root probe and the linked path work
assert phone.get("/apple-touch-icon.png").status_code == 200
assert phone.get("/static/apple-touch-icon.png").status_code == 200
page = phone.get("/?k=sekret", follow_redirects=True)
assert 'rel="apple-touch-icon"' in page.text