Mercurial > libervia-backend
comparison libervia/backend/plugins/plugin_xep_0384.py @ 4219:1b5cf2ee1d86
plugin XEP-0384, XEP-0391: download missing devices list:
when a peer jid was not in our roster, devices list was not retrieved, resulting in failed
en/decryption. This patch does check it and download missing devices list in necessary.
There is no subscription managed yet, so the list won't be updated in case of new devices,
this should be addressed at some point.
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 05 Mar 2024 17:31:36 +0100 |
parents | c0f3f29377f1 |
children | e11b13418ba6 |
comparison
equal
deleted
inserted
replaced
4218:c0f3f29377f1 | 4219:1b5cf2ee1d86 |
---|---|
20 from datetime import datetime | 20 from datetime import datetime |
21 import enum | 21 import enum |
22 import logging | 22 import logging |
23 import time | 23 import time |
24 from typing import \ | 24 from typing import \ |
25 Any, Dict, FrozenSet, List, Literal, NamedTuple, Optional, Set, Type, Union, cast | 25 Any, Dict, FrozenSet, Iterable, List, Literal, NamedTuple, Optional, Set, Type, Union, cast |
26 import uuid | 26 import uuid |
27 import xml.etree.ElementTree as ET | 27 import xml.etree.ElementTree as ET |
28 from xml.sax.saxutils import quoteattr | 28 from xml.sax.saxutils import quoteattr |
29 | 29 |
30 from typing_extensions import Final, Never, assert_never | 30 from typing_extensions import Final, Never, assert_never |
94 } | 94 } |
95 | 95 |
96 | 96 |
97 PARAM_CATEGORY = "Security" | 97 PARAM_CATEGORY = "Security" |
98 PARAM_NAME = "omemo_policy" | 98 PARAM_NAME = "omemo_policy" |
99 | |
100 NamespaceType = Literal["urn:xmpp:omemo:2", "eu.siacs.conversations.axolotl"] | |
99 | 101 |
100 | 102 |
101 class LogHandler(logging.Handler): | 103 class LogHandler(logging.Handler): |
102 """ | 104 """ |
103 Redirect python-omemo's log output to Libervia's log system. | 105 Redirect python-omemo's log output to Libervia's log system. |
2477 self.__xep_0334.add_hint_elements(stanza, [ "store" ]) | 2479 self.__xep_0334.add_hint_elements(stanza, [ "store" ]) |
2478 | 2480 |
2479 # Let the flow continue. | 2481 # Let the flow continue. |
2480 return True | 2482 return True |
2481 | 2483 |
2484 async def download_missing_device_lists( | |
2485 self, | |
2486 client: SatXMPPClient, | |
2487 namespace: NamespaceType, | |
2488 recipients: Iterable[jid.JID], | |
2489 session_manager: omemo.SessionManager, | |
2490 ) -> None: | |
2491 """Retrieves missing device lists for recipients outside the profile's roster. | |
2492 | |
2493 @param client: XMPP client. | |
2494 @param namespace: The namespace of the OMEMO version to use. | |
2495 @param recipients: Recipients to verify device list presence. | |
2496 @param session_manager: OMEMO session manager. | |
2497 """ | |
2498 recipients = [j.userhostJID() for j in recipients] | |
2499 not_in_roster = [j for j in recipients if not client.roster.is_jid_in_roster(j)] | |
2500 for bare_jid in not_in_roster: | |
2501 device_information = await session_manager.get_device_information( | |
2502 bare_jid.userhost() | |
2503 ) | |
2504 if ( | |
2505 not device_information | |
2506 or not all(namespace in di.namespaces for di in device_information) | |
2507 ): | |
2508 if namespace == self.NS_TWOMEMO: | |
2509 algo, node = "OMEMO", TWOMEMO_DEVICE_LIST_NODE | |
2510 elif namespace == self.NS_OLDMEMO: | |
2511 algo, node = "OMEMO_legacy", OLDMEMO_DEVICE_LIST_NODE | |
2512 else: | |
2513 raise ValueError(f"Invalid namespace: {namespace!r}") | |
2514 | |
2515 try: | |
2516 items, __ = await self._j.get_items(client, bare_jid, node, 1) | |
2517 | |
2518 except Exception: | |
2519 log.exception(f"Can't find {algo} devices list for {bare_jid}.") | |
2520 else: | |
2521 await self._update_device_list(client, bare_jid, items) | |
2522 log.warning(f"{algo} devices list updated for {bare_jid}.") | |
2523 | |
2482 async def encrypt( | 2524 async def encrypt( |
2483 self, | 2525 self, |
2484 client: SatXMPPClient, | 2526 client: SatXMPPClient, |
2485 namespace: Literal["urn:xmpp:omemo:2", "eu.siacs.conversations.axolotl"], | 2527 namespace: NamespaceType, |
2486 stanza: domish.Element, | 2528 stanza: domish.Element, |
2487 recipient_jids: Union[jid.JID, Set[jid.JID]], | 2529 recipient_jids: Union[jid.JID, Set[jid.JID]], |
2488 is_muc_message: bool, | 2530 is_muc_message: bool, |
2489 stanza_id: Optional[str] | 2531 stanza_id: Optional[str] |
2490 ) -> None: | 2532 ) -> None: |
2600 return | 2642 return |
2601 | 2643 |
2602 log.debug(f"Plaintext to encrypt: {plaintext}") | 2644 log.debug(f"Plaintext to encrypt: {plaintext}") |
2603 | 2645 |
2604 session_manager = await self.get_session_manager(client.profile) | 2646 session_manager = await self.get_session_manager(client.profile) |
2647 await self.download_missing_device_lists(client, namespace, recipient_jids, session_manager) | |
2605 | 2648 |
2606 try: | 2649 try: |
2607 messages, encryption_errors = await session_manager.encrypt( | 2650 messages, encryption_errors = await session_manager.encrypt( |
2608 frozenset(recipient_bare_jids), | 2651 frozenset(recipient_bare_jids), |
2609 { namespace: plaintext }, | 2652 { namespace: plaintext }, |
2677 @param profile: The profile this event belongs to. | 2720 @param profile: The profile this event belongs to. |
2678 """ | 2721 """ |
2679 | 2722 |
2680 sender = cast(jid.JID, items_event.sender) | 2723 sender = cast(jid.JID, items_event.sender) |
2681 items = cast(List[domish.Element], items_event.items) | 2724 items = cast(List[domish.Element], items_event.items) |
2725 client = self.host.get_client(profile) | |
2726 await self._update_device_list(client, sender, items) | |
2727 | |
2728 async def _update_device_list( | |
2729 self, | |
2730 client: SatXMPPEntity, | |
2731 sender: jid.JID, | |
2732 items: list[domish.Element] | |
2733 ) -> None: | |
2682 | 2734 |
2683 if len(items) > 1: | 2735 if len(items) > 1: |
2684 log.warning("Ignoring device list update with more than one element.") | 2736 log.warning("Ignoring device list update with more than one element.") |
2685 return | 2737 return |
2686 | 2738 |
2717 f"Malformed device list update item:" | 2769 f"Malformed device list update item:" |
2718 f" {ET.tostring(item_elt, encoding='unicode')}" | 2770 f" {ET.tostring(item_elt, encoding='unicode')}" |
2719 ) | 2771 ) |
2720 return | 2772 return |
2721 | 2773 |
2722 session_manager = await self.get_session_manager(profile) | 2774 session_manager = await self.get_session_manager(client.profile) |
2723 | 2775 |
2724 await session_manager.update_device_list( | 2776 await session_manager.update_device_list( |
2725 namespace, | 2777 namespace, |
2726 sender.userhost(), | 2778 sender.userhost(), |
2727 device_list | 2779 device_list |