Mercurial > libervia-backend
annotate src/plugins/plugin_sec_otr.py @ 1137:768f1f1ef12c
plugin otr: priv_key is better than getPrivKey here, as it should not be None + fixed private key encryption/decryption
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 25 Aug 2014 21:32:29 +0200 |
parents | ea2bbdf5b541 |
children | 7fcafc3206b1 |
rev | line source |
---|---|
1055 | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # SAT plugin for OTR encryption | |
5 # Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Jérôme Poisson (goffi@goffi.org) | |
6 | |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Affero General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Affero General Public License for more details. | |
16 | |
17 # You should have received a copy of the GNU Affero General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 # XXX: thanks to Darrik L Mazey for his documentation (https://blog.darmasoft.net/2013/06/30/using-pure-python-otr.html) | |
21 # this implentation is based on it | |
22 | |
1136
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
23 from sat.core.i18n import _, D_ |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
24 from sat.core.constants import Const as C |
1055 | 25 from sat.core.log import getLogger |
26 from sat.core import exceptions | |
27 log = getLogger(__name__) | |
28 from twisted.words.protocols.jabber import jid | |
29 from twisted.python import failure | |
1095 | 30 from twisted.internet import defer |
1055 | 31 import potr |
1095 | 32 from sat.memory import persistent |
33 | |
34 NS_OTR = "otr_plugin" | |
35 PRIVATE_KEY = "PRIVATE KEY" | |
1136
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
36 MAIN_MENU = D_('OTR') |
1055 | 37 |
38 DEFAULT_POLICY_FLAGS = { | |
39 'ALLOW_V1':False, | |
40 'ALLOW_V2':True, | |
41 'REQUIRE_ENCRYPTION':True, | |
42 } | |
43 | |
44 PLUGIN_INFO = { | |
45 "name": "OTR", | |
46 "import_name": "OTR", | |
47 "type": "SEC", | |
48 "protocols": [], | |
49 "dependencies": [], | |
50 "main": "OTR", | |
51 "handler": "no", | |
52 "description": _("""Implementation of OTR""") | |
53 } | |
54 | |
55 | |
56 class Context(potr.context.Context): | |
57 | |
1095 | 58 def __init__(self, host, account, other_jid): |
59 super(Context, self).__init__(account, other_jid) | |
1055 | 60 self.host = host |
61 | |
62 def getPolicy(self, key): | |
63 if key in DEFAULT_POLICY_FLAGS: | |
64 return DEFAULT_POLICY_FLAGS[key] | |
65 else: | |
66 return False | |
67 | |
1095 | 68 def inject(self, msg_str, appdata=None): |
69 assert isinstance(self.peer, jid.JID) | |
70 msg = msg_str.decode('utf-8') | |
71 client = self.user.client | |
72 log.debug(u'inject(%s, appdata=%s, to=%s)' % (msg, appdata, self.peer)) | |
1055 | 73 mess_data = {'message': msg, |
74 'type': 'chat', | |
75 'from': client.jid, | |
1095 | 76 'to': self.peer, |
1055 | 77 'subject': None, |
78 } | |
79 self.host.generateMessageXML(mess_data) | |
80 client.xmlstream.send(mess_data['xml']) | |
81 | |
82 def setState(self, state): | |
1095 | 83 old_state = self.state |
1055 | 84 super(Context, self).setState(state) |
1135
3158f9e08760
plugin OTR: a warning is logged when Account is instancied with a bare jid.
Goffi <goffi@goffi.org>
parents:
1134
diff
changeset
|
85 log.debug(u"setState: %s (old_state=%s)" % (state, old_state)) |
1095 | 86 |
87 if state == potr.context.STATE_PLAINTEXT: | |
88 feedback = _(u"/!\\ conversation with %(other_jid)s is now UNENCRYPTED") % {'other_jid': self.peer.full()} | |
89 elif state == potr.context.STATE_ENCRYPTED: | |
90 try: | |
91 fingerprint, trusted = self.getCurrentTrust() | |
92 except TypeError: | |
93 trusted = False | |
94 trusted_str = _(u"trusted") if trusted else _(u"untrusted") | |
95 | |
96 if old_state == potr.context.STATE_ENCRYPTED: | |
97 feedback = _(u"%(trusted)s OTR conversation with %(other_jid)s REFRESHED") % {'trusted': trusted_str, 'other_jid': self.peer.full()} | |
98 else: | |
99 feedback = _(u"%(trusted)s Encrypted OTR conversation started with %(other_jid)s") % {'trusted': trusted_str, 'other_jid': self.peer.full()} | |
100 elif state == potr.context.STATE_FINISHED: | |
101 feedback = _(u"OTR conversation with %(other_jid)s is FINISHED") % {'other_jid': self.peer.full()} | |
102 else: | |
103 log.error(_(u"Unknown OTR state")) | |
104 return | |
105 | |
106 client = self.user.client | |
107 # FIXME: newMessage should manage system message, so they don't appear as coming from the contact | |
108 self.host.bridge.newMessage(client.jid.full(), | |
109 feedback, | |
110 mess_type="headline", | |
111 to_jid=self.peer.full(), | |
112 extra={}, | |
113 profile=client.profile) | |
114 # TODO: send signal to frontends | |
1055 | 115 |
116 | |
117 class Account(potr.context.Account): | |
118 | |
1095 | 119 def __init__(self, host, client): |
120 log.debug(u"new account: %s" % client.jid) | |
1135
3158f9e08760
plugin OTR: a warning is logged when Account is instancied with a bare jid.
Goffi <goffi@goffi.org>
parents:
1134
diff
changeset
|
121 if not client.jid.resource: |
3158f9e08760
plugin OTR: a warning is logged when Account is instancied with a bare jid.
Goffi <goffi@goffi.org>
parents:
1134
diff
changeset
|
122 log.warning("Account created without resource") |
3158f9e08760
plugin OTR: a warning is logged when Account is instancied with a bare jid.
Goffi <goffi@goffi.org>
parents:
1134
diff
changeset
|
123 super(Account, self).__init__(unicode(client.jid), "xmpp", 1024) |
1095 | 124 self.host = host |
125 self.client = client | |
1055 | 126 |
127 def loadPrivkey(self): | |
1095 | 128 log.debug(u"loadPrivkey") |
129 return self.client.otr_priv_key | |
1055 | 130 |
131 def savePrivkey(self): | |
1095 | 132 log.debug(u"savePrivkey") |
1137
768f1f1ef12c
plugin otr: priv_key is better than getPrivKey here, as it should not be None + fixed private key encryption/decryption
Goffi <goffi@goffi.org>
parents:
1136
diff
changeset
|
133 if self.privkey is None: |
768f1f1ef12c
plugin otr: priv_key is better than getPrivKey here, as it should not be None + fixed private key encryption/decryption
Goffi <goffi@goffi.org>
parents:
1136
diff
changeset
|
134 raise exceptions.InternalError(_("Save is called but privkey is None !")) |
768f1f1ef12c
plugin otr: priv_key is better than getPrivKey here, as it should not be None + fixed private key encryption/decryption
Goffi <goffi@goffi.org>
parents:
1136
diff
changeset
|
135 priv_key = self.privkey.serializePrivateKey().encode('hex') |
1095 | 136 d = self.host.memory.encryptValue(priv_key, self.client.profile) |
137 def save_encrypted_key(encrypted_priv_key): | |
138 self.client.otr_data[PRIVATE_KEY] = encrypted_priv_key | |
139 d.addCallback(save_encrypted_key) | |
1055 | 140 |
141 | |
142 class ContextManager(object): | |
143 | |
144 def __init__(self, host, client): | |
145 self.host = host | |
1095 | 146 self.account = Account(host, client) |
1055 | 147 self.contexts = {} |
148 | |
1095 | 149 def startContext(self, other_jid): |
150 assert isinstance(other_jid, jid.JID) | |
151 context = self.contexts.setdefault(other_jid, Context(self.host, self.account, other_jid)) | |
152 return context | |
1055 | 153 |
154 def getContextForUser(self, other): | |
1095 | 155 log.debug(u"getContextForUser [%s]" % other) |
1135
3158f9e08760
plugin OTR: a warning is logged when Account is instancied with a bare jid.
Goffi <goffi@goffi.org>
parents:
1134
diff
changeset
|
156 if not other.resource: |
3158f9e08760
plugin OTR: a warning is logged when Account is instancied with a bare jid.
Goffi <goffi@goffi.org>
parents:
1134
diff
changeset
|
157 log.warning("getContextForUser called with a bare jid") |
1055 | 158 return self.startContext(other) |
159 | |
160 | |
161 class OTR(object): | |
162 | |
163 def __init__(self, host): | |
1095 | 164 log.info(_(u"OTR plugin initialization")) |
1134
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
165 self._fixPotr() # FIXME: to be removed when potr will be fixed |
1055 | 166 self.host = host |
167 self.context_managers = {} | |
168 host.trigger.add("MessageReceived", self.MessageReceivedTrigger, priority=100000) | |
169 host.trigger.add("sendMessage", self.sendMessageTrigger, priority=100000) | |
1136
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
170 host.importMenu((MAIN_MENU, D_("Start/Refresh")), self._startRefresh, security_limit=0, help_string=D_("Start or refresh an OTR session"), type_=C.MENU_SINGLE) |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
171 host.importMenu((MAIN_MENU, D_("End session")), self._endSession, security_limit=0, help_string=D_("Finish an OTR session"), type_=C.MENU_SINGLE) |
1055 | 172 |
1134
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
173 def _fixPotr(self): |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
174 # FIXME: potr fix for bad unicode handling |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
175 # this method monkeypatch it, must be removed when potr |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
176 # is fixed |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
177 |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
178 def getDefaultQueryMessage(self, policy): |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
179 defaultQuery = '?OTRv{versions}?\nI would like to start ' \ |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
180 'an Off-the-Record private conversation. However, you ' \ |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
181 'do not have a plugin to support that.\nSee '\ |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
182 'https://otr.cypherpunks.ca/ for more information.' |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
183 v = '2' if policy('ALLOW_V2') else '' |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
184 msg = defaultQuery.format(versions=v) |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
185 return msg.encode('ascii') |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
186 |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
187 potr.context.Account.getDefaultQueryMessage = getDefaultQueryMessage |
8def4a3f55c2
plugin OTR: temporary potr monkey patch to work around a unicode bug, to be removed as soon as a potr fixed version is released (potr maintainer should do it soon)
Goffi <goffi@goffi.org>
parents:
1095
diff
changeset
|
188 |
1095 | 189 @defer.inlineCallbacks |
1055 | 190 def profileConnected(self, profile): |
191 client = self.host.getClient(profile) | |
192 self.context_managers[profile] = ContextManager(self.host, client) | |
1095 | 193 client.otr_data = persistent.PersistentBinaryDict(NS_OTR, profile) |
194 yield client.otr_data.load() | |
195 encrypted_priv_key = client.otr_data.get(PRIVATE_KEY, None) | |
196 if encrypted_priv_key is not None: | |
197 priv_key = yield self.host.memory.decryptValue(encrypted_priv_key, profile) | |
1137
768f1f1ef12c
plugin otr: priv_key is better than getPrivKey here, as it should not be None + fixed private key encryption/decryption
Goffi <goffi@goffi.org>
parents:
1136
diff
changeset
|
198 client.otr_priv_key = potr.crypt.PK.parsePrivateKey(priv_key.decode('hex'))[0] |
1095 | 199 else: |
200 client.otr_priv_key = None | |
1055 | 201 |
1136
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
202 def _startRefresh(self, menu_data, profile): |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
203 """Start or refresh an OTR session |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
204 |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
205 @param menu_data: %(menu_data)s |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
206 @param profile: %(doc_profile)s |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
207 """ |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
208 try: |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
209 to_jid = jid.JID(menu_data['jid']) |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
210 if not to_jid.resource: |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
211 to_jid.resource = self.host.memory.getLastResource(to_jid, profile) # FIXME: temporary and unsecure, must be changed when frontends are refactored |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
212 except KeyError: |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
213 log.error(_("jid key is not present !")) |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
214 return defer.fail(exceptions.DataError) |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
215 otrctx = self.context_managers[profile].getContextForUser(to_jid) |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
216 query = otrctx.sendMessage(0, '?OTRv?') |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
217 otrctx.inject(query) |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
218 return {} |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
219 |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
220 def _endSession(self, menu_data, profile): |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
221 """End an OTR session |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
222 |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
223 @param menu_data: %(menu_data)s |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
224 @param profile: %(doc_profile)s |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
225 """ |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
226 try: |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
227 to_jid = jid.JID(menu_data['jid']) |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
228 if not to_jid.resource: |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
229 to_jid.resource = self.host.memory.getLastResource(to_jid, profile) # FIXME: temporary and unsecure, must be changed when frontends are refactored |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
230 except KeyError: |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
231 log.error(_("jid key is not present !")) |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
232 return defer.fail(exceptions.DataError) |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
233 otrctx = self.context_managers[profile].getContextForUser(to_jid) |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
234 otrctx.disconnect() |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
235 return {} |
ea2bbdf5b541
plugin OTR: added start/refresh and end session menus
Goffi <goffi@goffi.org>
parents:
1135
diff
changeset
|
236 |
1055 | 237 def _receivedTreatment(self, data, profile): |
238 from_jid = jid.JID(data['from']) | |
1095 | 239 log.debug(u"_receivedTreatment [from_jid = %s]" % from_jid) |
1055 | 240 otrctx = self.context_managers[profile].getContextForUser(from_jid) |
1095 | 241 encrypted = True |
1055 | 242 |
243 try: | |
1095 | 244 res = otrctx.receiveMessage(data['body'].encode('utf-8')) |
1055 | 245 except potr.context.UnencryptedMessage: |
1095 | 246 if otrctx.state == potr.context.STATE_ENCRYPTED: |
247 log.warning(u"Received unencrypted message in an encrypted context (from %(jid)s)" % {'jid': from_jid.full()}) | |
248 client = self.host.getClient(profile) | |
249 self.host.bridge.newMessage(from_jid.full(), | |
250 _(u"WARNING: received unencrypted data in a supposedly encrypted context"), | |
251 mess_type="headline", # FIXME: add message type for internal informations | |
252 to_jid=client.jid.full(), | |
253 extra={}, | |
254 profile=client.profile) | |
1055 | 255 encrypted = False |
256 | |
1095 | 257 if not encrypted: |
1055 | 258 return data |
259 else: | |
260 if res[0] != None: | |
261 # decrypted messages handling. | |
262 # receiveMessage() will return a tuple, the first part of which will be the decrypted message | |
263 data['body'] = res[0].decode('utf-8') | |
264 raise failure.Failure(exceptions.SkipHistory()) # we send the decrypted message to frontends, but we don't want it in history | |
265 else: | |
266 raise failure.Failure(exceptions.CancelError()) # no message at all (no history, no signal) | |
267 | |
268 def MessageReceivedTrigger(self, message, post_treat, profile): | |
269 post_treat.addCallback(self._receivedTreatment, profile) | |
270 return True | |
271 | |
272 def sendMessageTrigger(self, mess_data, pre_xml_treatments, post_xml_treatments, profile): | |
273 to_jid = mess_data['to'] | |
274 if mess_data['type'] != 'groupchat' and not to_jid.resource: | |
275 to_jid.resource = self.host.memory.getLastResource(to_jid, profile) # FIXME: it's dirty, but frontends don't manage resources correctly now, refactoring is planed | |
276 otrctx = self.context_managers[profile].getContextForUser(to_jid) | |
277 if mess_data['type'] != 'groupchat' and otrctx.state == potr.context.STATE_ENCRYPTED: | |
1095 | 278 log.debug(u"encrypting message") |
279 otrctx.sendMessage(0, mess_data['message'].encode('utf-8')) | |
1055 | 280 client = self.host.getClient(profile) |
281 self.host.sendMessageToBridge(mess_data, client) | |
282 return False | |
283 else: | |
1095 | 284 log.debug(u"sending message unencrypted") |
1055 | 285 return True |
286 |