Cherry-picked from PR #4338 by nepenth, resolved against current main.
Adds:
- Processing lifecycle reactions (eyes/checkmark/cross) via MATRIX_REACTIONS env
- Reaction send/receive with ReactionEvent + UnknownEvent fallback for older nio
- Fire-and-forget read receipts on text and media messages
- Message redaction, room history fetch, room creation, user invite
- Presence status control (online/offline/unavailable)
- Emote (/me) and notice message types with HTML rendering
- XSS-hardened markdown-to-HTML converter (strips raw HTML preprocessor,
sanitizes link URLs against javascript:/data:/vbscript: schemes)
- Comprehensive regex fallback with full block/inline markdown support
- Markdown>=3.6 added to [matrix] extras in pyproject.toml
- 46 new tests covering all features and security hardening
Cherry-picked from PR #3140 by chalkers, resolved against current main.
Registers RoomEncryptedImage/Audio/Video/File callbacks, decrypts
attachments via nio.crypto, caches all media types (images, audio,
documents), prevents ciphertext URL fallback for encrypted media.
Unifies the separate voice-message download into the main cache block.
Preserves main's MATRIX_REQUIRE_MENTION, auto-thread, and mention
stripping features. Includes 355 lines of encrypted media tests.
When the Matrix adapter receives encrypted events it can't decrypt
(MegolmEvent), it now:
1. Requests the missing room key from other devices via
client.request_room_key(event) instead of silently dropping the message
2. Buffers undecrypted events (bounded to 100, 5 min TTL) and retries
decryption after each E2EE maintenance cycle when new keys arrive
3. Auto-trusts/verifies all devices after key queries so other clients
share session keys with the bot proactively
4. Exports Megolm keys on disconnect and imports them on connect, so
session keys survive gateway restarts
This addresses the 'could not decrypt event' warnings that caused the
bot to miss messages in encrypted rooms.
* fix(matrix): harden e2ee access-token handling
* fix: patch nio mock in e2ee maintenance sync loop test
The sync_loop now imports nio for SyncError checking (from PR #3280),
so the test needs to inject a fake nio module via sys.modules.
---------
Co-authored-by: Cortana <andrew+cortana@chalkley.org>