comparison libervia/backend/plugins/plugin_comp_email_gateway/__init__.py @ 4350:6baea959dc33

component email gateway: convert `autocrypt` header: Autocrypt header must be transmitted in both directions to allow opportunistic end-to-end encryption with this protocol. Moved email validation regex to `tools/common/regex.py`, as it can be used in other locations. rel 456
author Goffi <goffi@goffi.org>
date Fri, 28 Feb 2025 09:23:35 +0100
parents 54df67d5646c
children f43cbceba2a0
comparison
equal deleted inserted replaced
4349:1bedcc6712e9 4350:6baea959dc33
55 from libervia.backend.models.core import MessageData 55 from libervia.backend.models.core import MessageData
56 from libervia.backend.plugins.plugin_comp_email_gateway.pubsub_service import ( 56 from libervia.backend.plugins.plugin_comp_email_gateway.pubsub_service import (
57 EmailGWPubsubService, 57 EmailGWPubsubService,
58 ) 58 )
59 from libervia.backend.plugins.plugin_exp_gre import GRE, GetDataHandler 59 from libervia.backend.plugins.plugin_exp_gre import GRE, GetDataHandler
60 from libervia.backend.plugins.plugin_sec_gre_encrypted_openpgp import NS_GRE_OPENPGP 60 from libervia.backend.plugins.plugin_sec_gre_encrypter_openpgp import NS_GRE_OPENPGP
61 from libervia.backend.plugins.plugin_sec_gre_formatter_mime import NS_GRE_MIME 61 from libervia.backend.plugins.plugin_sec_gre_formatter_mime import NS_GRE_MIME
62 from libervia.backend.plugins.plugin_xep_0033 import ( 62 from libervia.backend.plugins.plugin_xep_0033 import (
63 AddressType, 63 AddressType,
64 AddressesData, 64 AddressesData,
65 RECIPIENT_FIELDS, 65 RECIPIENT_FIELDS,
67 from libervia.backend.plugins.plugin_xep_0077 import XEP_0077 67 from libervia.backend.plugins.plugin_xep_0077 import XEP_0077
68 from libervia.backend.plugins.plugin_xep_0106 import XEP_0106 68 from libervia.backend.plugins.plugin_xep_0106 import XEP_0106
69 from libervia.backend.plugins.plugin_xep_0131 import HeadersData, Urgency, XEP_0131 69 from libervia.backend.plugins.plugin_xep_0131 import HeadersData, Urgency, XEP_0131
70 from libervia.backend.plugins.plugin_xep_0373 import binary_to_ascii_armor 70 from libervia.backend.plugins.plugin_xep_0373 import binary_to_ascii_armor
71 from libervia.backend.plugins.plugin_xep_0498 import XEP_0498 71 from libervia.backend.plugins.plugin_xep_0498 import XEP_0498
72 from libervia.backend.tools.common import regex
72 from libervia.backend.tools.utils import aio 73 from libervia.backend.tools.utils import aio
73 74
74 from .imap import IMAPClientFactory 75 from .imap import IMAPClientFactory
75 from .models import Credentials, UserData 76 from .models import Credentials, UserData
76 77
102 } 103 }
103 104
104 CONF_SECTION = f"component {IMPORT_NAME}" 105 CONF_SECTION = f"component {IMPORT_NAME}"
105 PREFIX_KEY_CREDENTIALS = "CREDENTIALS_" 106 PREFIX_KEY_CREDENTIALS = "CREDENTIALS_"
106 KEY_CREDENTIALS = f"{PREFIX_KEY_CREDENTIALS}{{from_jid}}" 107 KEY_CREDENTIALS = f"{PREFIX_KEY_CREDENTIALS}{{from_jid}}"
107
108 email_pattern = re.compile(r"[^@]+@[^@]+\.[^@]+")
109 108
110 109
111 class FileMetadata(NamedTuple): 110 class FileMetadata(NamedTuple):
112 path: Path 111 path: Path
113 hash: str 112 hash: str
533 if urgency == Urgency.medium: 532 if urgency == Urgency.medium:
534 importance = "normal" 533 importance = "normal"
535 else: 534 else:
536 importance = urgency 535 importance = urgency
537 msg["Importance"] = importance 536 msg["Importance"] = importance
537 if getattr(extra.headers, "autocrypt", None):
538 msg["Autocrypt"] = extra.headers.autocrypt
538 539
539 await smtp.sendmail( 540 await smtp.sendmail(
540 credentials["smtp_host"].encode(), 541 credentials["smtp_host"].encode(),
541 credentials["user_email"].encode(), 542 credentials["user_email"].encode(),
542 [to_email.encode()], 543 [to_email.encode()],
720 721
721 # Basic email validation for user_email field 722 # Basic email validation for user_email field
722 if key == "user_email": 723 if key == "user_email":
723 # XXX: This is a minimal check. A complete email validation is notoriously 724 # XXX: This is a minimal check. A complete email validation is notoriously
724 # difficult. 725 # difficult.
725 if not email_pattern.match(value): 726 if not regex.RE_EMAIL.match(value):
726 raise StanzaError( 727 raise StanzaError(
727 "bad-request", text=f"Invalid email address: {value}" 728 "bad-request", text=f"Invalid email address: {value}"
728 ) 729 )
729 730
730 def validate_imap_smtp_form(self, submit_form: data_form.Form) -> None: 731 def validate_imap_smtp_form(self, submit_form: data_form.Form) -> None:
904 headers["urgency"] = importance 905 headers["urgency"] = importance
905 elif importance == "normal": 906 elif importance == "normal":
906 headers["urgency"] = "medium" 907 headers["urgency"] = "medium"
907 else: 908 else:
908 log.warning("Ignoring invalid importance header: {importance!r}") 909 log.warning("Ignoring invalid importance header: {importance!r}")
910
911 autocrypt = email["autocrypt"]
912 if autocrypt:
913 headers["autocrypt"] = autocrypt
909 914
910 if headers: 915 if headers:
911 extra["headers"] = HeadersData(**headers).model_dump( 916 extra["headers"] = HeadersData(**headers).model_dump(
912 mode="json", exclude_none=True 917 mode="json", exclude_none=True
913 ) 918 )