fix: send Cache-Control so a stale Nix mtime can't pin visitors to old JS

This commit is contained in:
randogoth 2026-09-26 20:42:42 +03:00
parent a24c143fd0
commit a3378def50

View file

@ -96,8 +96,17 @@ async def relay(request: web.Request) -> web.WebSocketResponse:
# The client loads no inline script, no inline style and no foreign origin, so a
# strict policy costs nothing. form-action stays 'self' rather than 'none' so the
# compose dialog's method="dialog" form is untouched.
#
# Nix normalizes every built file's mtime to the same fixed epoch for
# reproducibility, so Last-Modified is identical across every deploy — with no
# explicit Cache-Control, a browser's heuristic freshness calculation (based on
# that ~56-year-old timestamp) can treat a page as fresh indefinitely and never
# revalidate again, silently pinning a visitor to whatever JS they first
# loaded across every future deploy. no-cache forces a conditional GET each
# time rather than disabling caching outright — the ETag aiohttp already sends
# still turns an unchanged file into a bodyless 304.
@web.middleware
async def csp(request: web.Request, handler):
async def headers(request: web.Request, handler):
response = await handler(request)
response.headers.setdefault("Content-Security-Policy", "; ".join([
"default-src 'self'",
@ -107,6 +116,7 @@ async def csp(request: web.Request, handler):
"object-src 'none'",
"frame-ancestors 'none'",
]))
response.headers.setdefault("Cache-Control", "no-cache")
return response
@ -128,7 +138,7 @@ def main() -> int:
args = parser.parse_args()
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
app = web.Application(middlewares=[csp])
app = web.Application(middlewares=[headers])
app["web_dir"], app["relay_ports"] = args.dir, set(args.allow_ports)
app["allow_origins"] = set(args.allow_origins)
app.router.add_get("/", index)