mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-11 03:03:03 +02:00
Misc bugs around dm region scope + scope display, and flood-scope leak
This commit is contained in:
@@ -1398,6 +1398,53 @@ class TestCreateDMMessageFromDecrypted:
|
||||
assert broadcast["paths"][0]["path"] == "aabbcc"
|
||||
assert broadcast["paths"][0]["received_at"] == 1700000001
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dm_includes_region_scope_in_broadcast(self, test_db, captured_broadcasts):
|
||||
"""A region-scoped (transport-routed) flood DM threads transport_code/region
|
||||
into the stored row and the broadcast, so bots see `scoped`/`region` for DMs
|
||||
(issue #300 DM half) and the UI can badge the scope."""
|
||||
from app.decoder import DecryptedDirectMessage
|
||||
from app.packet_processor import create_dm_message_from_decrypted
|
||||
|
||||
packet_id, _ = await RawPacketRepository.create(b"region_test_dm", 1700000000)
|
||||
|
||||
decrypted = DecryptedDirectMessage(
|
||||
timestamp=1700000000,
|
||||
flags=0,
|
||||
message="Scoped DM",
|
||||
dest_hash="fa",
|
||||
src_hash="a1",
|
||||
)
|
||||
|
||||
broadcasts, mock_broadcast = captured_broadcasts
|
||||
|
||||
with patch("app.packet_processor.broadcast_event", mock_broadcast):
|
||||
msg_id = await create_dm_message_from_decrypted(
|
||||
packet_id=packet_id,
|
||||
decrypted=decrypted,
|
||||
their_public_key=self.A1B2C3_PUB,
|
||||
our_public_key=self.FACE12_PUB,
|
||||
received_at=1700000001,
|
||||
outgoing=False,
|
||||
transport_code=0x1234,
|
||||
region="#Esperance",
|
||||
)
|
||||
|
||||
assert msg_id is not None
|
||||
|
||||
message_broadcasts = [b for b in broadcasts if b["type"] == "message"]
|
||||
assert len(message_broadcasts) == 1
|
||||
broadcast = message_broadcasts[0]["data"]
|
||||
# Bots derive `scoped = transport_code is not None` and read `region`.
|
||||
assert broadcast["transport_code"] == 0x1234
|
||||
assert broadcast["region"] == "#Esperance"
|
||||
|
||||
# Persisted so the scope survives a raw-packet purge, mirroring channel msgs.
|
||||
stored = await MessageRepository.get_by_id(msg_id)
|
||||
assert stored is not None
|
||||
assert stored.transport_code == 0x1234
|
||||
assert stored.region == "#Esperance"
|
||||
|
||||
|
||||
class TestDMDecryptionFunction:
|
||||
"""Test the DM decryption function with real crypto."""
|
||||
|
||||
@@ -1426,6 +1426,50 @@ class TestPathHashModeOverride:
|
||||
assert "path hash mode" in exc_info.value.detail.lower()
|
||||
mc.commands.send_chan_msg.assert_not_awaited()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_send_channel_msg_restores_scope_when_phm_apply_fails(self, test_db):
|
||||
"""A flood-scope override that was applied must still be restored when the
|
||||
subsequent path-hash-mode apply fails. Regression: the scope apply and the
|
||||
PHM apply used to sit outside the try/finally, so a PHM error left the radio
|
||||
stuck on the temporary region scope for all later traffic."""
|
||||
mc = _make_mc(name="MyNode")
|
||||
# PHM apply (first call) errors -> raises; PHM restore (second call, in the
|
||||
# finally) succeeds so this test isolates the scope-restore behavior.
|
||||
mc.commands.set_path_hash_mode = AsyncMock(
|
||||
side_effect=[
|
||||
MagicMock(type=EventType.ERROR, payload="unsupported mode"),
|
||||
_make_radio_result(),
|
||||
]
|
||||
)
|
||||
chan_key = "f6" * 16
|
||||
await ChannelRepository.upsert(key=chan_key, name="#both")
|
||||
await ChannelRepository.update_flood_scope_override(chan_key, "Esperance")
|
||||
await ChannelRepository.update_path_hash_mode_override(chan_key, 2)
|
||||
await AppSettingsRepository.update(flood_scope="Baseline")
|
||||
|
||||
radio_manager.path_hash_mode = 0
|
||||
radio_manager.path_hash_mode_supported = True
|
||||
|
||||
with (
|
||||
patch("app.routers.messages.radio_manager.require_connected", return_value=mc),
|
||||
patch.object(radio_manager, "_meshcore", mc),
|
||||
patch("app.routers.messages.broadcast_event"),
|
||||
pytest.raises(HTTPException) as exc_info,
|
||||
):
|
||||
await send_channel_message(
|
||||
SendChannelMessageRequest(channel_key=chan_key, text="hello")
|
||||
)
|
||||
|
||||
assert exc_info.value.status_code == 422
|
||||
assert "path hash mode" in exc_info.value.detail.lower()
|
||||
# The send never happens...
|
||||
mc.commands.send_chan_msg.assert_not_awaited()
|
||||
# ...but the applied region scope is restored to the global baseline.
|
||||
assert mc.commands.set_flood_scope.await_args_list == [
|
||||
call("#Esperance"),
|
||||
call("#Baseline"),
|
||||
]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_send_channel_msg_phm_restore_failure_broadcasts_error(self, test_db):
|
||||
"""Message sends OK but restore failure after 3 attempts broadcasts an error."""
|
||||
|
||||
Reference in New Issue
Block a user