diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_chat_send.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_chat_send.py | 57 |
1 files changed, 55 insertions, 2 deletions
diff --git a/packages/meshbay-hub/tests/test_chat_send.py b/packages/meshbay-hub/tests/test_chat_send.py index 4224fdb..250c9a3 100644 --- a/packages/meshbay-hub/tests/test_chat_send.py +++ b/packages/meshbay-hub/tests/test_chat_send.py @@ -1,5 +1,5 @@ """ -Sending a chat message must come back. +Sending a chat message must come back — and must go out encrypted. The node answers a chat message with a bare `{"type": "ack"}` — no request id, no type of its own — so `_dispatch` had nothing to match it on and left it to @@ -18,10 +18,26 @@ Videos tab that asked about a file the index no longer has leaves a None of that is visible in `chat-app.js`, where every line is correct, so this drives the real panel over the real transport in a browser rather than reading either source. + +Extended for MNP 2.0, where a send seals and signs before it goes anywhere. +That turned out to matter twice on its first run: + + * `chat_keys_resp` answers a `chat_keys_req` under a different type string, + so it fell through to the arrival-order guess and was handed to the very + `media_meta_req` this probe leaves outstanding — the original defect, one + feature later, in a message type that did not exist when it was written. + * `_asText` had been deleted along with an unrelated helper beside it. Its + only caller is inside `_openChatMessage`, whose rejection the panel + swallows, so the whole conversation rendered empty with nothing in the + console and the node answering perfectly. + +Neither is visible in any source file, and neither would have been caught by a +test that reads one. """ import json import shutil import subprocess +import sys from pathlib import Path import pytest @@ -36,7 +52,12 @@ pytestmark = pytest.mark.skipif( @pytest.fixture(scope="module") def probe(): - run = subprocess.run(["python3", str(HARNESS)], capture_output=True, timeout=180) + # `sys.executable`, not a bare "python3": the harness now imports + # `meshbay_common` to seal the chat keys the way the node does, and the + # system interpreter has neither that nor msgpack. The other probes get + # away with "python3" because they import nothing from this project. + run = subprocess.run([sys.executable, str(HARNESS)], + capture_output=True, timeout=180) assert run.returncode == 0, run.stderr.decode()[-2000:] data = json.loads(run.stdout.decode()) return data, {s["label"]: s for s in data["steps"]} @@ -71,3 +92,35 @@ def test_the_ack_is_not_handed_to_another_request(probe): "the chat ack was routed to the pending media_meta_req -- that request " "now believes it has an answer, and the chat send is waiting for a " "reply that already arrived") + + +def test_the_message_goes_out_sealed_and_signed(probe): + """ + What actually left the browser. A composer that let a plaintext message + through would be refused by the node, but the refusal arrives after the + fact and reads as "the message did not send" — so assert the shape here, + where the reason is visible. + """ + data, _ = probe + sent = [line for line in data["log"] if line.startswith("chat_msg ")] + assert sent, ("no chat_msg reached the stand-in node — the send did not " + f"complete. log: {data['log']}") + assert "format=1" in sent[0], "the message was not sealed" + assert "sig=64" in sent[0], "the message was not signed" + assert "ct=" in sent[0] and "ct=0" not in sent[0], "there was no ciphertext" + assert "plaintextLeak=false" in sent[0], ( + "the text the person typed appears somewhere in the message that went " + "on the wire") + + +def test_the_chat_keys_answer_is_not_handed_to_another_request(probe): + """ + The original defect's shape, in the message type that carries the group's + chat keys. An unanswered request is the ordinary case, not a rare one, and + the one this probe leaves outstanding swallowed the keys on the first run. + """ + data, _ = probe + assert not any("media_meta resolved with chat_keys_resp" in line + for line in data["log"]), ( + "chat_keys_resp was routed by arrival order and handed to the stale " + "media_meta_req — the send then waits out its own 30s timeout") |