summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/tests/test_security_regressions.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/tests/test_security_regressions.py')
-rw-r--r--packages/meshbay-node/tests/test_security_regressions.py33
1 files changed, 32 insertions, 1 deletions
diff --git a/packages/meshbay-node/tests/test_security_regressions.py b/packages/meshbay-node/tests/test_security_regressions.py
index 77d544b..e13dec0 100644
--- a/packages/meshbay-node/tests/test_security_regressions.py
+++ b/packages/meshbay-node/tests/test_security_regressions.py
@@ -92,12 +92,43 @@ def test_upload_rejects_unsafe_filenames(name):
"My Holiday Video.mkv",
"report-2026.pdf",
"track_01.flac",
+ # Reported 2026-08-16: an upload refused as "Invalid filename". The rule was
+ # ASCII-only, so most of the world could not send a file, and — worse — it
+ # rejected the "name (1).ext" form that _free_name produces itself, so the
+ # node refused names it had chosen.
+ "été.txt",
+ "naïve café.jpg",
+ "Ich möchte.pdf",
+ "日本語.mp4",
+ "rapport (1).pdf",
])
def test_upload_accepts_ordinary_filenames(name):
- """The allowlist must not break normal use."""
+ """The allowlist must not break normal use, in any script."""
assert _safe_name_re().match(name), f"should be accepted: {name!r}"
+@pytest.mark.parametrize("name", [
+ "trailing space ",
+ "ends.with.dot.",
+ "..",
+ "a\u202eexe.txt", # right-to-left override: hides the real extension
+])
+def test_upload_rejects_names_that_lie_about_themselves(name):
+ """Widening to Unicode must not admit names that misrepresent the file."""
+ assert not _safe_name_re().match(name), f"should be rejected: {name!r}"
+
+
+def test_the_node_never_generates_a_name_it_would_refuse(tmp_path):
+ """_free_name resolves a collision by appending " (n)"; that has to be legal."""
+ from meshbay_node.transport.webrtc_server import _free_name
+ (tmp_path / "clip.mp4").touch()
+ (tmp_path / "clip (1).mp4").touch()
+ chosen = _free_name(tmp_path, "clip.mp4")
+ assert chosen not in ("clip.mp4", "clip (1).mp4")
+ assert _safe_name_re().match(chosen), (
+ f"the node picked {chosen!r} and would then reject it on the next upload")
+
+
def _session(tmp_path: Path, user_id: str) -> WebRTCPeerSession:
"""A peer session wired to a real shared root, with sending stubbed out."""
shared_root = tmp_path / "shared"