mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-09-04 02:01:48 +03:00
fix(matrix): bind and bound SAS requests
This commit is contained in:
@@ -80,6 +80,7 @@ _MSGTYPE_MAP = {"m.image": "image", "m.audio": "audio", "m.video": "video", "m.f
|
||||
_SAS_METHOD = "m.sas.v1"
|
||||
_SAS_REQUEST_MAX_AGE_MS = 10 * 60 * 1000
|
||||
_SAS_REQUEST_MAX_FUTURE_MS = 5 * 60 * 1000
|
||||
_SAS_REQUEST_MAX_PENDING = 256
|
||||
|
||||
MATRIX_MEDIA_EVENT_FILTER = (RoomMessageMedia, RoomEncryptedMedia)
|
||||
MatrixMediaEvent: TypeAlias = RoomMessageMedia | RoomEncryptedMedia
|
||||
@@ -759,6 +760,16 @@ class MatrixChannel(BaseChannel):
|
||||
if request.timestamp_ms >= oldest_allowed
|
||||
}
|
||||
|
||||
def _remember_sas_verification_request(
|
||||
self,
|
||||
transaction_id: str,
|
||||
request: _SasVerificationRequest,
|
||||
) -> None:
|
||||
self._sas_verification_requests[transaction_id] = request
|
||||
while len(self._sas_verification_requests) > _SAS_REQUEST_MAX_PENDING:
|
||||
oldest_transaction_id = next(iter(self._sas_verification_requests))
|
||||
self._sas_verification_requests.pop(oldest_transaction_id)
|
||||
|
||||
async def _send_sas_control_message(
|
||||
self,
|
||||
*,
|
||||
@@ -849,7 +860,7 @@ class MatrixChannel(BaseChannel):
|
||||
},
|
||||
)
|
||||
if sent:
|
||||
self._sas_verification_requests[transaction_id] = request
|
||||
self._remember_sas_verification_request(transaction_id, request)
|
||||
return
|
||||
|
||||
if event_type == "m.key.verification.done":
|
||||
@@ -882,6 +893,16 @@ class MatrixChannel(BaseChannel):
|
||||
return
|
||||
|
||||
if isinstance(event, KeyVerificationStart):
|
||||
request = self._sas_verification_requests.get(transaction_id)
|
||||
from_device = str(getattr(event, "from_device", "") or "")
|
||||
if request is not None and (
|
||||
request.sender != sender or request.device_id != from_device
|
||||
):
|
||||
self.logger.warning(
|
||||
"Ignoring Matrix SAS start for transaction {} from unexpected device",
|
||||
transaction_id,
|
||||
)
|
||||
return
|
||||
if "emoji" not in (getattr(event, "short_authentication_string", None) or []):
|
||||
self.logger.info(
|
||||
"Ignoring Matrix SAS verification from {} without emoji support",
|
||||
|
||||
@@ -241,10 +241,12 @@ class _FakeKeyVerificationStart:
|
||||
*,
|
||||
sender: str = "@alice:matrix.org",
|
||||
transaction_id: str = "tx1",
|
||||
from_device: str = "ALICEDEVICE",
|
||||
short_authentication_string: list[str] | None = None,
|
||||
) -> None:
|
||||
self.sender = sender
|
||||
self.transaction_id = transaction_id
|
||||
self.from_device = from_device
|
||||
self.short_authentication_string = short_authentication_string or ["emoji"]
|
||||
|
||||
|
||||
@@ -477,6 +479,65 @@ async def test_sas_verification_request_sends_ready_to_allowed_device(monkeypatc
|
||||
assert channel._sas_verification_requests["tx1"].device_id == "ALICEDEVICE"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sas_verification_requests_are_bounded(monkeypatch) -> None:
|
||||
monkeypatch.setattr(matrix_module.time, "time", lambda: 1_000.0)
|
||||
channel = MatrixChannel(
|
||||
_make_config(
|
||||
allow_from=["@alice:matrix.org"],
|
||||
e2ee_enabled=True,
|
||||
sas_verification=True,
|
||||
),
|
||||
MessageBus(),
|
||||
)
|
||||
client = _FakeAsyncClient("", "", "", None)
|
||||
client.device_id = "BOTDEVICE"
|
||||
channel.client = client
|
||||
|
||||
for index in range(matrix_module._SAS_REQUEST_MAX_PENDING + 1):
|
||||
await channel._handle_key_verification_event(_unknown_verification_event(
|
||||
"m.key.verification.request",
|
||||
transaction_id=f"tx-{index}",
|
||||
from_device="ALICEDEVICE",
|
||||
methods=["m.sas.v1"],
|
||||
timestamp=1_000_000,
|
||||
))
|
||||
|
||||
assert len(channel._sas_verification_requests) == matrix_module._SAS_REQUEST_MAX_PENDING
|
||||
assert "tx-0" not in channel._sas_verification_requests
|
||||
assert f"tx-{matrix_module._SAS_REQUEST_MAX_PENDING}" in channel._sas_verification_requests
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sas_verification_start_must_match_requested_device(monkeypatch) -> None:
|
||||
_patch_key_verification_events(monkeypatch)
|
||||
monkeypatch.setattr(matrix_module.time, "time", lambda: 1_000.0)
|
||||
channel = MatrixChannel(
|
||||
_make_config(
|
||||
allow_from=["@alice:matrix.org"],
|
||||
e2ee_enabled=True,
|
||||
sas_verification=True,
|
||||
),
|
||||
MessageBus(),
|
||||
)
|
||||
client = _FakeAsyncClient("", "", "", None)
|
||||
client.device_id = "BOTDEVICE"
|
||||
channel.client = client
|
||||
|
||||
await channel._handle_key_verification_event(_unknown_verification_event(
|
||||
"m.key.verification.request",
|
||||
from_device="ALICEDEVICE",
|
||||
methods=["m.sas.v1"],
|
||||
timestamp=1_000_000,
|
||||
))
|
||||
await channel._handle_key_verification_event(
|
||||
_FakeKeyVerificationStart(from_device="OTHERDEVICE")
|
||||
)
|
||||
|
||||
assert client.accept_key_verification_calls == []
|
||||
assert channel._sas_verification_requests["tx1"].device_id == "ALICEDEVICE"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
("sender", "methods", "timestamp"),
|
||||
|
||||
Reference in New Issue
Block a user