Mercurial > libervia-backend
comparison sat/plugins/plugin_sec_otr.py @ 2653:7213caa5c5d0
plugin OTR: integrated in new encryption handler + fixed use of bare jid where full jid was expected
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 11 Aug 2018 18:24:55 +0200 |
parents | 189e38fb11ff |
children | 9190874a8ac5 |
comparison
equal
deleted
inserted
replaced
2652:baccc27d5c5c | 2653:7213caa5c5d0 |
---|---|
121 old_state = self.state | 121 old_state = self.state |
122 super(Context, self).setState(state) | 122 super(Context, self).setState(state) |
123 log.debug(u"setState: %s (old_state=%s)" % (state, old_state)) | 123 log.debug(u"setState: %s (old_state=%s)" % (state, old_state)) |
124 | 124 |
125 if state == potr.context.STATE_PLAINTEXT: | 125 if state == potr.context.STATE_PLAINTEXT: |
126 client.encryption.stop(self.peer, NS_OTR) | |
126 feedback = _(u"/!\\ conversation with %(other_jid)s is now UNENCRYPTED") % { | 127 feedback = _(u"/!\\ conversation with %(other_jid)s is now UNENCRYPTED") % { |
127 "other_jid": self.peer.full() | 128 "other_jid": self.peer.full() |
128 } | 129 } |
129 self.host.bridge.otrState( | 130 self.host.bridge.otrState( |
130 OTR_STATE_UNENCRYPTED, self.peer.full(), client.profile | 131 OTR_STATE_UNENCRYPTED, self.peer.full(), client.profile |
131 ) | 132 ) |
132 elif state == potr.context.STATE_ENCRYPTED: | 133 elif state == potr.context.STATE_ENCRYPTED: |
134 client.encryption.start(self.peer, NS_OTR) | |
133 try: | 135 try: |
134 trusted = self.getCurrentTrust() | 136 trusted = self.getCurrentTrust() |
135 except TypeError: | 137 except TypeError: |
136 trusted = False | 138 trusted = False |
137 trusted_str = _(u"trusted") if trusted else _(u"untrusted") | 139 trusted_str = _(u"trusted") if trusted else _(u"untrusted") |
151 ) | 153 ) |
152 self.host.bridge.otrState( | 154 self.host.bridge.otrState( |
153 OTR_STATE_ENCRYPTED, self.peer.full(), client.profile | 155 OTR_STATE_ENCRYPTED, self.peer.full(), client.profile |
154 ) | 156 ) |
155 elif state == potr.context.STATE_FINISHED: | 157 elif state == potr.context.STATE_FINISHED: |
158 client.encryption.stop(self.peer, NS_OTR) | |
156 feedback = D_(u"OTR conversation with {other_jid} is FINISHED").format( | 159 feedback = D_(u"OTR conversation with {other_jid} is FINISHED").format( |
157 other_jid=self.peer.full() | 160 other_jid=self.peer.full() |
158 ) | 161 ) |
159 self.host.bridge.otrState( | 162 self.host.bridge.otrState( |
160 OTR_STATE_UNENCRYPTED, self.peer.full(), client.profile | 163 OTR_STATE_UNENCRYPTED, self.peer.full(), client.profile |
301 self._dropPrivKey, | 304 self._dropPrivKey, |
302 security_limit=0, | 305 security_limit=0, |
303 type_=C.MENU_SINGLE, | 306 type_=C.MENU_SINGLE, |
304 ) | 307 ) |
305 host.trigger.add("presenceReceived", self._presenceReceivedTrigger) | 308 host.trigger.add("presenceReceived", self._presenceReceivedTrigger) |
309 self.host.registerEncryptionPlugin(self, u"OTR", NS_OTR) | |
306 | 310 |
307 def _skipOTR(self, profile): | 311 def _skipOTR(self, profile): |
308 """Tell the backend to not handle OTR for this profile. | 312 """Tell the backend to not handle OTR for this profile. |
309 | 313 |
310 @param profile (str): %(doc_profile)s | 314 @param profile (str): %(doc_profile)s |
359 def startRefresh(self, client, to_jid): | 363 def startRefresh(self, client, to_jid): |
360 """Start or refresh an OTR session | 364 """Start or refresh an OTR session |
361 | 365 |
362 @param to_jid(jid.JID): jid to start encrypted session with | 366 @param to_jid(jid.JID): jid to start encrypted session with |
363 """ | 367 """ |
368 encrypted_session = client.encryption.getSession(to_jid.userhostJID()) | |
369 if encrypted_session and encrypted_session[u'plugin'].namespace != NS_OTR: | |
370 raise exceptions.ConflictError(_( | |
371 u"Can't start an OTR session, there is already an encrypted session " | |
372 u"with {name}").format(name=encrypted_session[u'plugin'].name)) | |
364 if not to_jid.resource: | 373 if not to_jid.resource: |
365 to_jid.resource = self.host.memory.getMainResource( | 374 to_jid.resource = self.host.memory.getMainResource( |
366 client, to_jid | 375 client, to_jid |
367 ) # FIXME: temporary and unsecure, must be changed when frontends | 376 ) # FIXME: temporary and unsecure, must be changed when frontends |
368 # are refactored | 377 # are refactored |
577 u"WARNING: received unencrypted data in a supposedly encrypted " | 586 u"WARNING: received unencrypted data in a supposedly encrypted " |
578 u"context" | 587 u"context" |
579 ), | 588 ), |
580 ) | 589 ) |
581 client.feedback(from_jid, feedback) | 590 client.feedback(from_jid, feedback) |
591 except potr.context.NotEncryptedError: | |
592 msg = D_(u"WARNING: received OTR encrypted data in an unencrypted context") | |
593 log.warning(msg) | |
594 feedback = msg | |
595 client.feedback(from_jid, msg) | |
596 raise failure.Failure(exceptions.CancelError(msg)) | |
582 except StopIteration: | 597 except StopIteration: |
583 return data | 598 return data |
584 else: | 599 else: |
585 encrypted = True | 600 encrypted = True |
586 | 601 |
601 # TODO: add skip history as an option, but by default we don't skip it | 616 # TODO: add skip history as an option, but by default we don't skip it |
602 # data[u'history'] = C.HISTORY_SKIP # we send the decrypted message to | 617 # data[u'history'] = C.HISTORY_SKIP # we send the decrypted message to |
603 # frontends, but we don't want it in | 618 # frontends, but we don't want it in |
604 # history | 619 # history |
605 else: | 620 else: |
606 log.warning( | |
607 u"An encrypted message was expected, but got {}".format( | |
608 data["message"] | |
609 ) | |
610 ) | |
611 raise failure.Failure( | 621 raise failure.Failure( |
612 exceptions.CancelError("Cancelled by OTR") | 622 exceptions.CancelError("Cancelled by OTR") |
613 ) # no message at all (no history, no signal) | 623 ) # no message at all (no history, no signal) |
614 return data | 624 return data |
615 | 625 |
644 else: | 654 else: |
645 post_treat.addCallback(self._receivedTreatment, client) | 655 post_treat.addCallback(self._receivedTreatment, client) |
646 return True | 656 return True |
647 | 657 |
648 def _sendMessageDataTrigger(self, client, mess_data): | 658 def _sendMessageDataTrigger(self, client, mess_data): |
649 if not "OTR" in mess_data: | 659 encryption = mess_data.get(C.MESS_KEY_ENCRYPTION) |
660 if encryption is None or encryption['plugin'].namespace != NS_OTR: | |
650 return | 661 return |
651 otrctx = mess_data["OTR"] | 662 to_jid = mess_data['to'] |
663 if not to_jid.resource: | |
664 to_jid.resource = self.host.memory.getMainResource( | |
665 client, to_jid | |
666 ) # FIXME: temporary and unsecure, must be changed when frontends | |
667 otrctx = client._otr_context_manager.getContextForUser(to_jid) | |
652 message_elt = mess_data["xml"] | 668 message_elt = mess_data["xml"] |
653 to_jid = mess_data["to"] | |
654 if otrctx.state == potr.context.STATE_ENCRYPTED: | 669 if otrctx.state == potr.context.STATE_ENCRYPTED: |
655 log.debug(u"encrypting message") | 670 log.debug(u"encrypting message") |
656 body = None | 671 body = None |
657 for child in list(message_elt.children): | 672 for child in list(message_elt.children): |
658 if child.name == "body": | 673 if child.name == "body": |
666 message_elt.children.remove(child) | 681 message_elt.children.remove(child) |
667 if body is None: | 682 if body is None: |
668 log.warning(u"No message found") | 683 log.warning(u"No message found") |
669 else: | 684 else: |
670 self._p_carbons.setPrivate(message_elt) | 685 self._p_carbons.setPrivate(message_elt) |
686 self._p_hints.addHintElements(message_elt, [ | |
687 self._p_hints.HINT_NO_COPY, | |
688 self._p_hints.HINT_NO_PERMANENT_STORE]) | |
671 otrctx.sendMessage(0, unicode(body).encode("utf-8"), appdata=mess_data) | 689 otrctx.sendMessage(0, unicode(body).encode("utf-8"), appdata=mess_data) |
672 else: | 690 else: |
673 feedback = D_( | 691 feedback = D_( |
674 u"Your message was not sent because your correspondent closed the " | 692 u"Your message was not sent because your correspondent closed the " |
675 u"encrypted conversation on his/her side. " | 693 u"encrypted conversation on his/her side. " |
687 if client.profile in self.skipped_profiles: | 705 if client.profile in self.skipped_profiles: |
688 # FIXME: should not be done on a per-profile basis | 706 # FIXME: should not be done on a per-profile basis |
689 return True | 707 return True |
690 | 708 |
691 to_jid = copy.copy(mess_data["to"]) | 709 to_jid = copy.copy(mess_data["to"]) |
710 if client.encryption.getSession(to_jid.userhostJID()): | |
711 # there is already an encrypted session with this entity | |
712 return True | |
713 | |
692 if not to_jid.resource: | 714 if not to_jid.resource: |
693 to_jid.resource = self.host.memory.getMainResource( | 715 to_jid.resource = self.host.memory.getMainResource( |
694 client, to_jid | 716 client, to_jid |
695 ) # FIXME: full jid may not be known | 717 ) # FIXME: full jid may not be known |
696 | 718 |
697 otrctx = client._otr_context_manager.getContextForUser(to_jid) | 719 otrctx = client._otr_context_manager.getContextForUser(to_jid) |
698 | 720 |
699 if otrctx.state != potr.context.STATE_PLAINTEXT: | 721 if otrctx.state != potr.context.STATE_PLAINTEXT: |
700 self._p_hints.addHint(mess_data, self._p_hints.HINT_NO_COPY) | 722 client.encryption.start(to_jid, NS_OTR) |
701 self._p_hints.addHint(mess_data, self._p_hints.HINT_NO_PERMANENT_STORE) | 723 client.encryption.setEncryptionFlag(mess_data) |
702 mess_data["OTR"] = (otrctx) # this indicate that encryption is needed in | |
703 # sendMessageData trigger | |
704 if not mess_data["to"].resource: | 724 if not mess_data["to"].resource: |
705 # if not resource was given, we force it here | 725 # if not resource was given, we force it here |
706 mess_data["to"] = to_jid | 726 mess_data["to"] = to_jid |
707 return True | 727 return True |
708 | 728 |