fix(hub): нулевой байт в пути /app/assets — 404; тесты типов файлов сборки (T1.1, T1.4, T16.1, #29)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f79494d5c6
commit
2024a66a6d
@ -194,8 +194,13 @@ def h_app(hub, conn, m, q, body):
|
|||||||
return 503, Raw("text/html; charset=utf-8", NOT_BUILT)
|
return 503, Raw("text/html; charset=utf-8", NOT_BUILT)
|
||||||
rest = unquote(m.group(1) or "")
|
rest = unquote(m.group(1) or "")
|
||||||
if rest.startswith("assets/"):
|
if rest.startswith("assets/"):
|
||||||
|
if "\x00" in rest: # T1.1: нулевой байт — 404, а не 500 из resolve()
|
||||||
|
raise ApiError(404, "not_found", "/app/" + rest.replace("\x00", "%00"))
|
||||||
assets = (hub.web_dir / "assets").resolve()
|
assets = (hub.web_dir / "assets").resolve()
|
||||||
f = (hub.web_dir / rest).resolve()
|
try:
|
||||||
|
f = (hub.web_dir / rest).resolve()
|
||||||
|
except (OSError, ValueError):
|
||||||
|
raise ApiError(404, "not_found", "/app/" + rest)
|
||||||
if not f.is_relative_to(assets) or not f.is_file():
|
if not f.is_relative_to(assets) or not f.is_file():
|
||||||
raise ApiError(404, "not_found", "/app/" + rest)
|
raise ApiError(404, "not_found", "/app/" + rest)
|
||||||
return 200, Raw(ASSET_TYPES.get(f.suffix, "application/octet-stream"), f.read_bytes(), ASSET_CACHE)
|
return 200, Raw(ASSET_TYPES.get(f.suffix, "application/octet-stream"), f.read_bytes(), ASSET_CACHE)
|
||||||
|
|||||||
@ -158,8 +158,7 @@ def test_bad_requests(hub):
|
|||||||
with pytest.raises(HubError) as e:
|
with pytest.raises(HubError) as e:
|
||||||
c.get("/issues", limit="abc")
|
c.get("/issues", limit="abc")
|
||||||
assert e.value.status == 400
|
assert e.value.status == 400
|
||||||
import urllib.request, urllib.error
|
req =urllib.request.Request(hub["base"] + "/batches", data=b"{not json", method="POST",
|
||||||
req = urllib.request.Request(hub["base"] + "/batches", data=b"{not json", method="POST",
|
|
||||||
headers={"Authorization": "Bearer " + c.token})
|
headers={"Authorization": "Bearer " + c.token})
|
||||||
with pytest.raises(urllib.error.HTTPError) as e2:
|
with pytest.raises(urllib.error.HTTPError) as e2:
|
||||||
urllib.request.urlopen(req)
|
urllib.request.urlopen(req)
|
||||||
|
|||||||
@ -36,6 +36,9 @@ def app_hub(tmp_path):
|
|||||||
(web / "assets" / "index-abc123.js").write_text("console.log('ok')", encoding="utf-8")
|
(web / "assets" / "index-abc123.js").write_text("console.log('ok')", encoding="utf-8")
|
||||||
(web / "assets" / "index-abc123.css").write_text("body{}", encoding="utf-8")
|
(web / "assets" / "index-abc123.css").write_text("body{}", encoding="utf-8")
|
||||||
(web / "assets" / "font.bin").write_bytes(b"\x00\x01")
|
(web / "assets" / "font.bin").write_bytes(b"\x00\x01")
|
||||||
|
for name, data in (("logo.svg", b"<svg/>"), ("p.png", b"\x89PNG"), ("f.ico", b"\x00"), ("f.woff2", b"wOF2"),
|
||||||
|
("index-abc123.js.map", b"{}")):
|
||||||
|
(web / "assets" / name).write_bytes(data)
|
||||||
(tmp_path / "secret.txt").write_text("секрет", encoding="utf-8")
|
(tmp_path / "secret.txt").write_text("секрет", encoding="utf-8")
|
||||||
srv, th, base = _serve(tmp_path, web)
|
srv, th, base = _serve(tmp_path, web)
|
||||||
yield base
|
yield base
|
||||||
@ -111,3 +114,16 @@ def test_old_board_addresses_redirect_to_app(app_hub, path):
|
|||||||
def test_links_page_is_gone():
|
def test_links_page_is_gone():
|
||||||
assert not hasattr(api, "PAGE")
|
assert not hasattr(api, "PAGE")
|
||||||
assert not (api.WEB_APP.parent / "links.html").exists()
|
assert not (api.WEB_APP.parent / "links.html").exists()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("name,ctype", [("logo.svg", "image/svg+xml"), ("p.png", "image/png"), ("f.ico", "image/x-icon"),
|
||||||
|
("f.woff2", "font/woff2"), ("index-abc123.js.map", "application/json")])
|
||||||
|
def test_asset_content_types(app_hub, name, ctype):
|
||||||
|
status, r, _ = _get(app_hub, "/app/assets/" + name)
|
||||||
|
assert status == 200 and r.getheader("Content-Type") == ctype
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("path", ["/app/assets/%00", "/app/assets/a%00.js", "/app/assets/%00/../index-abc123.js"])
|
||||||
|
def test_nul_in_asset_path_is_404(app_hub, path):
|
||||||
|
status, _, _ = _get(app_hub, path)
|
||||||
|
assert status == 404
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user