mirror of
https://github.com/saymrwulf/proof-aware-crypto-tooling-agent.git
synced 2026-09-04 20:03:40 +00:00
web: unlisted operator-dropped documents from <log>/site/
Generic mechanism: bare-name PDFs placed in the log directory's site/ folder are served by name, checked LAST in the route chain (can never shadow an API route), traversal-safe, noindex, and deliberately absent from the endpoint index and the docs page - the operator decides who receives a link. Tested: serve, unlisted-in-404, traversal rejected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
5e8eba8e52
commit
920485eb83
2 changed files with 48 additions and 0 deletions
|
|
@ -132,6 +132,8 @@ def make_handler(log: TransparencyLog, base_path: str, docs_html: str, paper_pdf
|
||||||
for entry in entries
|
for entry in entries
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
elif self._serve_site_document(route, log):
|
||||||
|
pass # operator-dropped document; checked LAST so it can never shadow an API route
|
||||||
else:
|
else:
|
||||||
self._send(404, {
|
self._send(404, {
|
||||||
"error": "unknown endpoint",
|
"error": "unknown endpoint",
|
||||||
|
|
@ -150,6 +152,32 @@ def make_handler(log: TransparencyLog, base_path: str, docs_html: str, paper_pdf
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def _serve_site_document(self, route: str, log_obj: TransparencyLog) -> bool:
|
||||||
|
"""Serve operator-dropped PDFs from ``<log>/site/`` by bare name.
|
||||||
|
|
||||||
|
Deliberately UNLISTED: these documents do not appear in the
|
||||||
|
endpoint index or anywhere on the docs page - the operator
|
||||||
|
decides who receives a link. The name must be a single plain
|
||||||
|
path segment (no traversal); only ``.pdf`` payloads are served.
|
||||||
|
Returns True when it handled the request.
|
||||||
|
"""
|
||||||
|
name = route.lstrip("/")
|
||||||
|
if not name or not name.replace("-", "").replace("_", "").isalnum():
|
||||||
|
return False
|
||||||
|
candidate = (log_obj.log_dir / "site" / f"{name}.pdf").resolve()
|
||||||
|
site_dir = (log_obj.log_dir / "site").resolve()
|
||||||
|
if site_dir not in candidate.parents or not candidate.is_file():
|
||||||
|
return False
|
||||||
|
body = candidate.read_bytes()
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header("Content-Type", "application/pdf")
|
||||||
|
self.send_header("Content-Disposition", f'inline; filename="{name}.pdf"')
|
||||||
|
self.send_header("Content-Length", str(len(body)))
|
||||||
|
self.send_header("X-Robots-Tag", "noindex, nofollow")
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(body)
|
||||||
|
return True
|
||||||
|
|
||||||
def _send(self, code: int, payload: dict[str, Any], code_if_error: int | None = None) -> None:
|
def _send(self, code: int, payload: dict[str, Any], code_if_error: int | None = None) -> None:
|
||||||
if code_if_error and "error" in payload:
|
if code_if_error and "error" in payload:
|
||||||
code = code_if_error
|
code = code_if_error
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,26 @@ def test_web_endpoints_and_online_proof_roundtrip(tmp_path):
|
||||||
page = r.read().decode()
|
page = r.read().decode()
|
||||||
assert "BEGIN PUBLIC KEY" in page
|
assert "BEGIN PUBLIC KEY" in page
|
||||||
assert "pin this key" in page.lower()
|
assert "pin this key" in page.lower()
|
||||||
|
# operator-dropped documents: served by bare name, absent from the
|
||||||
|
# endpoint index, traversal-safe
|
||||||
|
site = tmp_path / "log" / "site"
|
||||||
|
site.mkdir()
|
||||||
|
(site / "extra.pdf").write_bytes(b"%PDF-1.4 dummy")
|
||||||
|
with urllib.request.urlopen(base + "/extra", timeout=10) as r:
|
||||||
|
assert r.read().startswith(b"%PDF-")
|
||||||
|
assert r.headers["X-Robots-Tag"].startswith("noindex")
|
||||||
|
try:
|
||||||
|
urllib.request.urlopen(base + "/nope-not-there", timeout=10)
|
||||||
|
raise AssertionError("expected 404")
|
||||||
|
except urllib.error.HTTPError as exc:
|
||||||
|
listing = json.loads(exc.read())
|
||||||
|
assert exc.code == 404
|
||||||
|
assert not any("extra" in e for e in listing["endpoints"]) # unlisted
|
||||||
|
try:
|
||||||
|
urllib.request.urlopen(base + "/..%2fsth", timeout=10)
|
||||||
|
raise AssertionError("expected 404")
|
||||||
|
except urllib.error.HTTPError as exc:
|
||||||
|
assert exc.code == 404
|
||||||
finally:
|
finally:
|
||||||
server.shutdown()
|
server.shutdown()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue