mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-06-30 19:16:07 +00:00
Compare commits
3 Commits
981acc4b44
...
2f6ca5478b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f6ca5478b | ||
| 1d4b137dad | |||
| 90512da938 |
|
|
@ -1,3 +1,12 @@
|
||||||
|
secubox-toolbox (2.6.49-1~bookworm1) bookworm; urgency=medium
|
||||||
|
|
||||||
|
* Banner fix (#639): inject the transparency banner only into top-level
|
||||||
|
documents (Sec-Fetch-Dest: document, or absent for old UAs) — skip iframes
|
||||||
|
/ sub-documents / sub-resources so a visit gets ONE banner, not one per
|
||||||
|
frame. Gates both the stream_inject and legacy buffer paths.
|
||||||
|
|
||||||
|
-- Gerald KERMA <devel@cybermind.fr> Wed, 17 Jun 2026 21:00:00 +0200
|
||||||
|
|
||||||
secubox-toolbox (2.6.48-1~bookworm1) bookworm; urgency=medium
|
secubox-toolbox (2.6.48-1~bookworm1) bookworm; urgency=medium
|
||||||
|
|
||||||
* R3 banner fix (#636): the mitm now serves /__toolbox/loader.js +
|
* R3 banner fix (#636): the mitm now serves /__toolbox/loader.js +
|
||||||
|
|
|
||||||
|
|
@ -404,6 +404,14 @@ def _detect_csp_strict(flow: http.HTTPFlow) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _is_top_level_document(flow: http.HTTPFlow) -> bool:
|
||||||
|
"""True if the response is a top-level navigation (so the banner belongs).
|
||||||
|
Skip iframes/sub-documents/sub-resources so we inject ONE banner per visit.
|
||||||
|
Sec-Fetch-Dest absent (old UAs) → assume top-level (best-effort, prior behavior)."""
|
||||||
|
dest = (flow.request.headers.get("sec-fetch-dest", "") or "").lower()
|
||||||
|
return dest in ("", "document")
|
||||||
|
|
||||||
|
|
||||||
# Per-level visual theme (#545). R3 — and the planned R4 — get the
|
# Per-level visual theme (#545). R3 — and the planned R4 — get the
|
||||||
# neon-tube treatment (dark glass bar, glowing tube border + neon
|
# neon-tube treatment (dark glass bar, glowing tube border + neon
|
||||||
# text-shadow). R2 keeps the original amber flat bar. All values are inline
|
# text-shadow). R2 keeps the original amber flat bar. All values are inline
|
||||||
|
|
@ -800,6 +808,10 @@ class InjectBanner:
|
||||||
# that survives strict CSP.
|
# that survives strict CSP.
|
||||||
if _detect_csp_strict(flow):
|
if _detect_csp_strict(flow):
|
||||||
return
|
return
|
||||||
|
# #639 — only inject into top-level navigations; iframes/sub-documents
|
||||||
|
# each get their own responseheaders call → multiple banners per visit.
|
||||||
|
if not _is_top_level_document(flow):
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
resp.stream = _LoaderInjector(_loader_script(flow))
|
resp.stream = _LoaderInjector(_loader_script(flow))
|
||||||
flow.metadata["sbx_streamed"] = True
|
flow.metadata["sbx_streamed"] = True
|
||||||
|
|
@ -832,6 +844,10 @@ class InjectBanner:
|
||||||
return
|
return
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
# #639 — only inject into top-level navigations; iframes/sub-documents
|
||||||
|
# share the same buffer path and would each get a banner.
|
||||||
|
if not _is_top_level_document(flow):
|
||||||
|
return
|
||||||
# Phase 10 perf : cheap pre-flight check on Content-Length to avoid
|
# Phase 10 perf : cheap pre-flight check on Content-Length to avoid
|
||||||
# reading multi-MB bodies into RAM just to discover we'd skip them.
|
# reading multi-MB bodies into RAM just to discover we'd skip them.
|
||||||
# `flow.response.content` would buffer the whole body before returning.
|
# `flow.response.content` would buffer the whole body before returning.
|
||||||
|
|
|
||||||
48
packages/secubox-toolbox/tests/test_banner_toplevel.py
Normal file
48
packages/secubox-toolbox/tests/test_banner_toplevel.py
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# SPDX-License-Identifier: LicenseRef-CMSD-1.0
|
||||||
|
import sys, pathlib, importlib, json
|
||||||
|
ADDON_DIR = pathlib.Path(__file__).resolve().parents[1] / "mitmproxy_addons"
|
||||||
|
sys.path.insert(0, str(ADDON_DIR))
|
||||||
|
|
||||||
|
from mitmproxy.test import tflow, tutils # noqa: E402
|
||||||
|
from secubox_toolbox import filters # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
|
def _addon(monkeypatch, tmp_path):
|
||||||
|
fp = tmp_path / "filters.json"
|
||||||
|
fp.write_text(json.dumps({"banner": True, "stream_inject": True}))
|
||||||
|
monkeypatch.setattr(filters, "FILTERS_PATH", str(fp))
|
||||||
|
filters.get_filters(force=True)
|
||||||
|
import inject_banner
|
||||||
|
importlib.reload(inject_banner)
|
||||||
|
monkeypatch.setattr(inject_banner, "_client_level", lambda flow: "r3")
|
||||||
|
return inject_banner
|
||||||
|
|
||||||
|
|
||||||
|
def _html(dest=None):
|
||||||
|
f = tflow.tflow(resp=tutils.tresp())
|
||||||
|
f.response.headers["content-type"] = "text/html; charset=utf-8"
|
||||||
|
f.response.status_code = 200
|
||||||
|
if dest is not None:
|
||||||
|
f.request.headers["sec-fetch-dest"] = dest
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
def test_iframe_not_streamed(monkeypatch, tmp_path):
|
||||||
|
ib = _addon(monkeypatch, tmp_path)
|
||||||
|
f = _html(dest="iframe")
|
||||||
|
ib.InjectBanner().responseheaders(f)
|
||||||
|
assert not f.metadata.get("sbx_streamed") # iframe → no banner
|
||||||
|
|
||||||
|
|
||||||
|
def test_document_streamed(monkeypatch, tmp_path):
|
||||||
|
ib = _addon(monkeypatch, tmp_path)
|
||||||
|
f = _html(dest="document")
|
||||||
|
ib.InjectBanner().responseheaders(f)
|
||||||
|
assert f.metadata.get("sbx_streamed") is True # top-level → banner
|
||||||
|
|
||||||
|
|
||||||
|
def test_missing_dest_streamed(monkeypatch, tmp_path):
|
||||||
|
ib = _addon(monkeypatch, tmp_path)
|
||||||
|
f = _html(dest=None)
|
||||||
|
ib.InjectBanner().responseheaders(f)
|
||||||
|
assert f.metadata.get("sbx_streamed") is True # absent → assume top-level
|
||||||
Loading…
Reference in New Issue
Block a user