comparison sat/plugins/plugin_xep_0420.py @ 3933:cecf45416403

plugin XEP-0373 and XEP-0374: Implementation of OX and OXIM: GPGME is used as the GPG provider. rel 374
author Syndace <me@syndace.dev>
date Tue, 20 Sep 2022 16:22:18 +0200
parents 626629781a53
children
comparison
equal deleted inserted replaced
3932:7af29260ecb8 3933:cecf45416403
20 from datetime import datetime 20 from datetime import datetime
21 import enum 21 import enum
22 import secrets 22 import secrets
23 import string 23 import string
24 from typing import Dict, NamedTuple, Optional, Set, Tuple, cast 24 from typing import Dict, NamedTuple, Optional, Set, Tuple, cast
25 from typing_extensions import Final
25 26
26 from lxml import etree 27 from lxml import etree
28 from sat.core import exceptions
27 29
28 from sat.core.constants import Const as C 30 from sat.core.constants import Const as C
29 from sat.core.i18n import D_ 31 from sat.core.i18n import D_
30 from sat.core.log import Logger, getLogger 32 from sat.core.log import Logger, getLogger
31 from sat.core.sat_main import SAT 33 from sat.core.sat_main import SAT
66 C.PI_HANDLER: "no", 68 C.PI_HANDLER: "no",
67 C.PI_DESCRIPTION: D_("Implementation of Stanza Content Encryption"), 69 C.PI_DESCRIPTION: D_("Implementation of Stanza Content Encryption"),
68 } 70 }
69 71
70 72
71 NS_SCE = "urn:xmpp:sce:1" 73 NS_SCE: Final = "urn:xmpp:sce:1"
72 74
73 75
74 class ProfileRequirementsNotMet(Exception): 76 class ProfileRequirementsNotMet(Exception):
75 """ 77 """
76 Raised by :meth:`XEP_0420.unpack_stanza` in case the requirements formulated by the 78 Raised by :meth:`XEP_0420.unpack_stanza` in case the requirements formulated by the
112 :meth:`XEP_0420.pack_stanza`, i.e. all encryptable children have been removed 114 :meth:`XEP_0420.pack_stanza`, i.e. all encryptable children have been removed
113 and only the root ``<message/>`` or ``<iq/>`` and unencryptable children 115 and only the root ``<message/>`` or ``<iq/>`` and unencryptable children
114 remain. Do not modify. 116 remain. Do not modify.
115 @return: An affix element to include in the envelope. The element must have the 117 @return: An affix element to include in the envelope. The element must have the
116 name :attr:`element_name` and must validate using :attr:`element_schema`. 118 name :attr:`element_name` and must validate using :attr:`element_schema`.
117 @raise ValueError: if the affix couldn't be built. 119 @raise ValueError: if the affix couldn't be built due to missing information on
120 the stanza.
118 """ 121 """
119 122
120 @abstractmethod 123 @abstractmethod
121 def verify(self, stanza: domish.Element, element: domish.Element) -> None: 124 def verify(self, stanza: domish.Element, element: domish.Element) -> None:
122 """ 125 """
382 @param stanza: The stanza to process. Will be modified by the call. 385 @param stanza: The stanza to process. Will be modified by the call.
383 @param envelope_serialized: The serialized envelope, i.e. the plaintext produced 386 @param envelope_serialized: The serialized envelope, i.e. the plaintext produced
384 by the decryption scheme utilizing SCE. 387 by the decryption scheme utilizing SCE.
385 @return: The parsed and processed values of all affixes that were present on the 388 @return: The parsed and processed values of all affixes that were present on the
386 envelope, notably including the timestamp. 389 envelope, notably including the timestamp.
387 @raise ValueError: if the serialized envelope element is malformed. 390 @raise exceptions.ParsingError: if the serialized envelope element is malformed.
388 @raise ProfileRequirementsNotMet: if one or more affixes required by the profile 391 @raise ProfileRequirementsNotMet: if one or more affixes required by the profile
389 are missing from the envelope. 392 are missing from the envelope.
390 @raise AffixVerificationFailed: if an affix included in the envelope fails to 393 @raise AffixVerificationFailed: if an affix included in the envelope fails to
391 validate. It doesn't matter whether the affix is required by the profile or 394 validate. It doesn't matter whether the affix is required by the profile or
392 not, all affixes included in the envelope are validated and cause this 395 not, all affixes included in the envelope are validated and cause this
397 """ 400 """
398 401
399 try: 402 try:
400 envelope_serialized_string = envelope_serialized.decode("utf-8") 403 envelope_serialized_string = envelope_serialized.decode("utf-8")
401 except UnicodeError as e: 404 except UnicodeError as e:
402 raise ValueError("Serialized envelope can't bare parsed as utf-8.") from e 405 raise exceptions.ParsingError(
406 "Serialized envelope can't bare parsed as utf-8."
407 ) from e
403 408
404 custom_affixes = set(profile.custom_policies.keys()) 409 custom_affixes = set(profile.custom_policies.keys())
405 410
406 # Make sure the envelope adheres to the schema 411 # Make sure the envelope adheres to the schema
407 parser = etree.XMLParser(schema=etree.XMLSchema(etree.XML(ENVELOPE_SCHEMA.format( 412 parser = etree.XMLParser(schema=etree.XMLSchema(etree.XML(ENVELOPE_SCHEMA.format(
418 ).encode("utf-8")))) 423 ).encode("utf-8"))))
419 424
420 try: 425 try:
421 etree.fromstring(envelope_serialized_string, parser) 426 etree.fromstring(envelope_serialized_string, parser)
422 except etree.XMLSyntaxError as e: 427 except etree.XMLSyntaxError as e:
423 raise ValueError("Serialized envelope doesn't pass schema validation.") from e 428 raise exceptions.ParsingError(
429 "Serialized envelope doesn't pass schema validation."
430 ) from e
424 431
425 # Prepare the envelope and content elements 432 # Prepare the envelope and content elements
426 envelope = cast(domish.Element, ElementParser()(envelope_serialized_string)) 433 envelope = cast(domish.Element, ElementParser()(envelope_serialized_string))
427 content = next(envelope.elements(NS_SCE, "content")) 434 content = next(envelope.elements(NS_SCE, "content"))
428 435
450 # The time affix isn't verified other than that the timestamp is parseable. 457 # The time affix isn't verified other than that the timestamp is parseable.
451 try: 458 try:
452 timestamp_value = None if time_element is None else \ 459 timestamp_value = None if time_element is None else \
453 XEP_0082.parse_datetime(time_element["stamp"]) 460 XEP_0082.parse_datetime(time_element["stamp"])
454 except ValueError as e: 461 except ValueError as e:
455 raise AffixVerificationFailed("Malformed time affix") from e 462 raise AffixVerificationFailed("Malformed time affix.") from e
456 463
457 # The to affix is verified by comparing the to attribute of the stanza with the 464 # The to affix is verified by comparing the to attribute of the stanza with the
458 # JID referenced by the affix. Note that only bare JIDs are compared as per the 465 # JID referenced by the affix. Note that only bare JIDs are compared as per the
459 # specification. 466 # specification.
460 recipient_value: Optional[jid.JID] = None 467 recipient_value: Optional[jid.JID] = None