comparison sat/core/xmpp.py @ 3911:8289ac1b34f4

plugin XEP-0384: Fully reworked to adjust to the reworked python-omemo: - support for both (modern) OMEMO under the `urn:xmpp:omemo:2` namespace and (legacy) OMEMO under the `eu.siacs.conversations.axolotl` namespace - maintains one identity across both versions of OMEMO - migrates data from the old plugin - includes more features for protocol stability - uses SCE for modern OMEMO - fully type-checked, linted and format-checked - added type hints to various pieces of backend code used by the plugin - added stubs for some Twisted APIs used by the plugin under stubs/ (use `export MYPYPATH=stubs/` before running mypy) - core (xmpp): enabled `send` trigger and made it an asyncPoint fix 375
author Syndace <me@syndace.dev>
date Tue, 23 Aug 2022 21:06:24 +0200
parents 967a8e109cda
children 944f51f9c2b4
comparison
equal deleted inserted replaced
3910:199598223f82 3911:8289ac1b34f4
548 iq_error_elt = error.StanzaError( 548 iq_error_elt = error.StanzaError(
549 condition, text=text, appCondition=appCondition 549 condition, text=text, appCondition=appCondition
550 ).toResponse(iq_elt) 550 ).toResponse(iq_elt)
551 self.xmlstream.send(iq_error_elt) 551 self.xmlstream.send(iq_error_elt)
552 552
553 def generateMessageXML(self, data, post_xml_treatments=None): 553 def generateMessageXML(
554 self,
555 data: core_types.MessageData,
556 post_xml_treatments: Optional[defer.Deferred] = None
557 ) -> core_types.MessageData:
554 """Generate <message/> stanza from message data 558 """Generate <message/> stanza from message data
555 559
556 @param data(dict): message data 560 @param data: message data
557 domish element will be put in data['xml'] 561 domish element will be put in data['xml']
558 following keys are needed: 562 following keys are needed:
559 - from 563 - from
560 - to 564 - to
561 - uid: can be set to '' if uid attribute is not wanted 565 - uid: can be set to '' if uid attribute is not wanted
562 - message 566 - message
563 - type 567 - type
564 - subject 568 - subject
565 - extra 569 - extra
566 @param post_xml_treatments(Deferred): a Deferred which will be called with data 570 @param post_xml_treatments: a Deferred which will be called with data once XML is
567 once XML is generated 571 generated
568 @return (dict) message data 572 @return: message data
569 """ 573 """
570 data["xml"] = message_elt = domish.Element((None, "message")) 574 data["xml"] = message_elt = domish.Element((None, "message"))
571 message_elt["to"] = data["to"].full() 575 message_elt["to"] = data["to"].full()
572 message_elt["from"] = data["from"].full() 576 message_elt["from"] = data["from"].full()
573 message_elt["type"] = data["type"] 577 message_elt["type"] = data["type"]
610 614
611 @param post_xml_treatments(D): the same Deferred as in sendMessage trigger 615 @param post_xml_treatments(D): the same Deferred as in sendMessage trigger
612 """ 616 """
613 raise NotImplementedError 617 raise NotImplementedError
614 618
615 def send(self, obj): 619 async def send(self, obj):
616 # original send method accept string 620 # original send method accept string
617 # but we restrict to domish.Element to make trigger treatments easier 621 # but we restrict to domish.Element to make trigger treatments easier
618 assert isinstance(obj, domish.Element) 622 assert isinstance(obj, domish.Element)
619 # XXX: this trigger is the last one before sending stanza on wire 623 # XXX: this trigger is the last one before sending stanza on wire
620 # it is intended for things like end 2 end encryption. 624 # it is intended for things like end 2 end encryption.
621 # *DO NOT* cancel (i.e. return False) without very good reason 625 # *DO NOT* cancel (i.e. return False) without very good reason
622 # (out of band transmission for instance). 626 # (out of band transmission for instance).
623 # e2e should have a priority of 0 here, and out of band transmission 627 # e2e should have a priority of 0 here, and out of band transmission
624 # a lower priority 628 # a lower priority
625 #  FIXME: trigger not used yet, can be uncommented when e2e full stanza 629 if not (await self.host_app.trigger.asyncPoint("send", self, obj)):
626 # encryption is implemented 630 return
627 #  if not self.host_app.trigger.point("send", self, obj):
628 #   return
629 super().send(obj) 631 super().send(obj)
630 632
631 @defer.inlineCallbacks 633 async def sendMessageData(self, mess_data):
632 def sendMessageData(self, mess_data):
633 """Convenient method to send message data to stream 634 """Convenient method to send message data to stream
634 635
635 This method will send mess_data[u'xml'] to stream, but a trigger is there 636 This method will send mess_data[u'xml'] to stream, but a trigger is there
636 The trigger can't be cancelled, it's a good place for e2e encryption which 637 The trigger can't be cancelled, it's a good place for e2e encryption which
637 don't handle full stanza encryption 638 don't handle full stanza encryption
642 # XXX: This is the last trigger before u"send" (last but one globally) 643 # XXX: This is the last trigger before u"send" (last but one globally)
643 # for sending message. 644 # for sending message.
644 # This is intented for e2e encryption which doesn't do full stanza 645 # This is intented for e2e encryption which doesn't do full stanza
645 # encryption (e.g. OTR) 646 # encryption (e.g. OTR)
646 # This trigger point can't cancel the method 647 # This trigger point can't cancel the method
647 yield self.host_app.trigger.asyncPoint("sendMessageData", self, mess_data, 648 await self.host_app.trigger.asyncPoint("sendMessageData", self, mess_data,
648 triggers_no_cancel=True) 649 triggers_no_cancel=True)
649 self.send(mess_data["xml"]) 650 await self.send(mess_data["xml"])
650 defer.returnValue(mess_data) 651 return mess_data
651 652
652 def sendMessage( 653 def sendMessage(
653 self, to_jid, message, subject=None, mess_type="auto", extra=None, uid=None, 654 self, to_jid, message, subject=None, mess_type="auto", extra=None, uid=None,
654 no_trigger=False): 655 no_trigger=False):
655 r"""Send a message to an entity 656 r"""Send a message to an entity
820 @return (object): requested plugin wrapper, or default value 821 @return (object): requested plugin wrapper, or default value
821 The plugin wrapper will return the method with client set as first 822 The plugin wrapper will return the method with client set as first
822 positional argument 823 positional argument
823 """ 824 """
824 return ClientPluginWrapper(self, plugin_name, missing) 825 return ClientPluginWrapper(self, plugin_name, missing)
826
827
828 ExtraDict = dict # TODO
825 829
826 830
827 @implementer(iwokkel.IDisco) 831 @implementer(iwokkel.IDisco)
828 class SatXMPPClient(SatXMPPEntity, wokkel_client.XMPPClient): 832 class SatXMPPClient(SatXMPPEntity, wokkel_client.XMPPClient):
829 trigger_suffix = "" 833 trigger_suffix = ""
928 post_xml_treatments.addCallback( 932 post_xml_treatments.addCallback(
929 lambda ret: defer.ensureDeferred(self.messageAddToHistory(ret)) 933 lambda ret: defer.ensureDeferred(self.messageAddToHistory(ret))
930 ) 934 )
931 post_xml_treatments.addCallback(self.messageSendToBridge) 935 post_xml_treatments.addCallback(self.messageSendToBridge)
932 936
933 def feedback(self, to_jid, message, extra=None): 937 def feedback(
938 self,
939 to_jid: jid.JID,
940 message: str,
941 extra: Optional[ExtraDict] = None
942 ) -> None:
934 """Send message to frontends 943 """Send message to frontends
935 944
936 This message will be an info message, not recorded in history. 945 This message will be an info message, not recorded in history.
937 It can be used to give feedback of a command 946 It can be used to give feedback of a command
938 @param to_jid(jid.JID): destinee jid 947 @param to_jid: destinee jid
939 @param message(unicode): message to send to frontends 948 @param message: message to send to frontends
940 @param extra(None, dict): extra data to use 949 @param extra: extra data to use in particular, info subtype can be specified with
941 in particular, info subtype can be specified with MESS_EXTRA_INFO 950 MESS_EXTRA_INFO
942 """ 951 """
943 if extra is None: 952 if extra is None:
944 extra = {} 953 extra = {}
945 self.host_app.bridge.messageNew( 954 self.host_app.bridge.messageNew(
946 uid=str(uuid.uuid4()), 955 uid=str(uuid.uuid4()),