comparison sat/plugins/plugin_xep_0384.py @ 3715:b9718216a1c0 0.9

merge bookmark 0.9
author Goffi <goffi@goffi.org>
date Wed, 01 Dec 2021 16:13:31 +0100
parents 09f5ac48ffe3
children 11f7ca8afd15
comparison
equal deleted inserted replaced
3714:af09b5aaa5d7 3715:b9718216a1c0
112 112
113 @param promise_(promise.Promise): promise to convert 113 @param promise_(promise.Promise): promise to convert
114 @return (defer.Deferred): deferred instance linked to the promise 114 @return (defer.Deferred): deferred instance linked to the promise
115 """ 115 """
116 d = defer.Deferred() 116 d = defer.Deferred()
117 promise_.then(d.callback, d.errback) 117 promise_.then(
118 lambda result: reactor.callFromThread(d.callback, result),
119 lambda exc: reactor.callFromThread(d.errback, exc)
120 )
118 return d 121 return d
119 122
120 123
121 class OmemoStorage(omemo.Storage): 124 class OmemoStorage(omemo.Storage):
122 125
138 This method use partial to call callback with boolean then result when 141 This method use partial to call callback with boolean then result when
139 Deferred is called 142 Deferred is called
140 """ 143 """
141 deferred.addCallback(partial(callback, True)) 144 deferred.addCallback(partial(callback, True))
142 deferred.addErrback(partial(callback, False)) 145 deferred.addErrback(partial(callback, False))
146
147 def _callMainThread(self, callback, method, *args, check_jid=None):
148 if check_jid is None:
149 d = method(*args)
150 else:
151 check_jid_d = self._checkJid(check_jid)
152 check_jid_d.addCallback(lambda __: method(*args))
153 d = check_jid_d
154
155 if callback is not None:
156 d.addCallback(partial(callback, True))
157 d.addErrback(partial(callback, False))
158
159 def _call(self, callback, method, *args, check_jid=None):
160 """Create Deferred and add Promise callback to it
161
162 This method use reactor.callLater to launch Deferred in main thread
163 @param check_jid: run self._checkJid before method
164 """
165 reactor.callFromThread(
166 self._callMainThread, callback, method, *args, check_jid=check_jid
167 )
143 168
144 def _checkJid(self, bare_jid): 169 def _checkJid(self, bare_jid):
145 """Check if jid is known, and store it if not 170 """Check if jid is known, and store it if not
146 171
147 @param bare_jid(unicode): bare jid to check 172 @param bare_jid(unicode): bare jid to check
162 if own_bare_jid != self.own_bare_jid_s or own_device_id != self.device_id: 187 if own_bare_jid != self.own_bare_jid_s or own_device_id != self.device_id:
163 raise exceptions.InternalError('bare jid or device id inconsistency!') 188 raise exceptions.InternalError('bare jid or device id inconsistency!')
164 callback(True, None) 189 callback(True, None)
165 190
166 def loadState(self, callback): 191 def loadState(self, callback):
167 d = self.data.get(KEY_STATE) 192 self._call(callback, self.data.get, KEY_STATE)
168 self.setCb(d, callback)
169 193
170 def storeState(self, callback, state): 194 def storeState(self, callback, state):
171 d = self.data.force(KEY_STATE, state) 195 self._call(callback, self.data.force, KEY_STATE, state)
172 self.setCb(d, callback)
173 196
174 def loadSession(self, callback, bare_jid, device_id): 197 def loadSession(self, callback, bare_jid, device_id):
175 key = '\n'.join([KEY_SESSION, bare_jid, str(device_id)]) 198 key = '\n'.join([KEY_SESSION, bare_jid, str(device_id)])
176 d = self.data.get(key) 199 self._call(callback, self.data.get, key)
177 self.setCb(d, callback)
178 200
179 def storeSession(self, callback, bare_jid, device_id, session): 201 def storeSession(self, callback, bare_jid, device_id, session):
180 key = '\n'.join([KEY_SESSION, bare_jid, str(device_id)]) 202 key = '\n'.join([KEY_SESSION, bare_jid, str(device_id)])
181 d = self.data.force(key, session) 203 self._call(callback, self._data.force, key, session)
182 self.setCb(d, callback)
183 204
184 def deleteSession(self, callback, bare_jid, device_id): 205 def deleteSession(self, callback, bare_jid, device_id):
185 key = '\n'.join([KEY_SESSION, bare_jid, str(device_id)]) 206 key = '\n'.join([KEY_SESSION, bare_jid, str(device_id)])
186 d = self.data.remove(key) 207 self._call(callback, self.data.remove, key)
187 self.setCb(d, callback)
188 208
189 def loadActiveDevices(self, callback, bare_jid): 209 def loadActiveDevices(self, callback, bare_jid):
190 key = '\n'.join([KEY_ACTIVE_DEVICES, bare_jid]) 210 key = '\n'.join([KEY_ACTIVE_DEVICES, bare_jid])
191 d = self.data.get(key, {}) 211 self._call(callback, self.data.get, key, {})
192 if callback is not None:
193 self.setCb(d, callback)
194 return d
195 212
196 def loadInactiveDevices(self, callback, bare_jid): 213 def loadInactiveDevices(self, callback, bare_jid):
197 key = '\n'.join([KEY_INACTIVE_DEVICES, bare_jid]) 214 key = '\n'.join([KEY_INACTIVE_DEVICES, bare_jid])
198 d = self.data.get(key, {}) 215 self._call(callback, self.data.get, key, {})
199 if callback is not None:
200 self.setCb(d, callback)
201 return d
202 216
203 def storeActiveDevices(self, callback, bare_jid, devices): 217 def storeActiveDevices(self, callback, bare_jid, devices):
204 key = '\n'.join([KEY_ACTIVE_DEVICES, bare_jid]) 218 key = '\n'.join([KEY_ACTIVE_DEVICES, bare_jid])
205 d = self._checkJid(bare_jid) 219 self._call(callback, self.data.force, key, devices, check_jid=bare_jid)
206 d.addCallback(lambda _: self.data.force(key, devices))
207 self.setCb(d, callback)
208 220
209 def storeInactiveDevices(self, callback, bare_jid, devices): 221 def storeInactiveDevices(self, callback, bare_jid, devices):
210 key = '\n'.join([KEY_INACTIVE_DEVICES, bare_jid]) 222 key = '\n'.join([KEY_INACTIVE_DEVICES, bare_jid])
211 d = self._checkJid(bare_jid) 223 self._call(callback, self.data.force, key, devices, check_jid=bare_jid)
212 d.addCallback(lambda _: self.data.force(key, devices))
213 self.setCb(d, callback)
214 224
215 def storeTrust(self, callback, bare_jid, device_id, trust): 225 def storeTrust(self, callback, bare_jid, device_id, trust):
216 key = '\n'.join([KEY_TRUST, bare_jid, str(device_id)]) 226 key = '\n'.join([KEY_TRUST, bare_jid, str(device_id)])
217 d = self.data.force(key, trust) 227 self._call(callback, self.data.force, key, trust)
218 self.setCb(d, callback)
219 228
220 def loadTrust(self, callback, bare_jid, device_id): 229 def loadTrust(self, callback, bare_jid, device_id):
221 key = '\n'.join([KEY_TRUST, bare_jid, str(device_id)]) 230 key = '\n'.join([KEY_TRUST, bare_jid, str(device_id)])
222 d = self.data.get(key) 231 self._call(callback, self.data.get, key)
232
233 def listJIDs(self, callback):
223 if callback is not None: 234 if callback is not None:
224 self.setCb(d, callback) 235 callback(True, self.all_jids)
225 return d
226
227 def listJIDs(self, callback):
228 d = defer.succeed(self.all_jids)
229 if callback is not None:
230 self.setCb(d, callback)
231 return d
232 236
233 def _deleteJID_logResults(self, results): 237 def _deleteJID_logResults(self, results):
234 failed = [success for success, __ in results if not success] 238 failed = [success for success, __ in results if not success]
235 if failed: 239 if failed:
236 log.warning( 240 log.warning(
264 d_list.append(lambda __: self.data.force(KEY_ALL_JIDS, self.all_jids)) 268 d_list.append(lambda __: self.data.force(KEY_ALL_JIDS, self.all_jids))
265 d = defer.DeferredList(d_list) 269 d = defer.DeferredList(d_list)
266 d.addCallback(self._deleteJID_logResults) 270 d.addCallback(self._deleteJID_logResults)
267 return d 271 return d
268 272
269 def deleteJID(self, callback, bare_jid): 273 def _deleteJID(self, callback, bare_jid):
270 """Retrieve all (in)actives devices of bare_jid, and delete all related keys"""
271 d_list = [] 274 d_list = []
272 275
273 key = '\n'.join([KEY_ACTIVE_DEVICES, bare_jid]) 276 key = '\n'.join([KEY_ACTIVE_DEVICES, bare_jid])
274 d_list.append(self.data.get(key, [])) 277 d_list.append(self.data.get(key, []))
275 278
282 d_list.append(d_inactive) 285 d_list.append(d_inactive)
283 d = defer.DeferredList(d_list) 286 d = defer.DeferredList(d_list)
284 d.addCallback(self._deleteJID_gotDevices, bare_jid) 287 d.addCallback(self._deleteJID_gotDevices, bare_jid)
285 if callback is not None: 288 if callback is not None:
286 self.setCb(d, callback) 289 self.setCb(d, callback)
287 return d 290
291 def deleteJID(self, callback, bare_jid):
292 """Retrieve all (in)actives devices of bare_jid, and delete all related keys"""
293 reactor.callFromThread(self._deleteJID, callback, bare_jid)
288 294
289 295
290 class SatOTPKPolicy(omemo.DefaultOTPKPolicy): 296 class SatOTPKPolicy(omemo.DefaultOTPKPolicy):
291 pass 297 pass
292 298
726 device_id = random.randint(1, 2**31-1) 732 device_id = random.randint(1, 2**31-1)
727 # we check that it's really unique 733 # we check that it's really unique
728 while device_id in devices: 734 while device_id in devices:
729 device_id = random.randint(1, 2**31-1) 735 device_id = random.randint(1, 2**31-1)
730 # and we save it 736 # and we save it
731 persistent_dict[KEY_DEVICE_ID] = device_id 737 await persistent_dict.aset(KEY_DEVICE_ID, device_id)
732 738
733 log.debug(f"our OMEMO device id is {device_id}") 739 log.debug(f"our OMEMO device id is {device_id}")
734 740
735 if device_id not in devices: 741 if device_id not in devices:
736 log.debug(f"our device id ({device_id}) is not in the list, adding it") 742 log.debug(f"our device id ({device_id}) is not in the list, adding it")
786 device_id=device_elt['id'])) 792 device_id=device_elt['id']))
787 else: 793 else:
788 devices.add(device_id) 794 devices.add(device_id)
789 return devices 795 return devices
790 796
791 @defer.inlineCallbacks 797 async def getDevices(self, client, entity_jid=None):
792 def getDevices(self, client, entity_jid=None):
793 """Retrieve list of registered OMEMO devices 798 """Retrieve list of registered OMEMO devices
794 799
795 @param entity_jid(jid.JID, None): get devices from this entity 800 @param entity_jid(jid.JID, None): get devices from this entity
796 None to get our own devices 801 None to get our own devices
797 @return (set(int)): list of devices 802 @return (set(int)): list of devices
798 """ 803 """
799 if entity_jid is not None: 804 if entity_jid is not None:
800 assert not entity_jid.resource 805 assert not entity_jid.resource
801 try: 806 try:
802 items, metadata = yield self._p.getItems(client, entity_jid, NS_OMEMO_DEVICES) 807 items, metadata = await self._p.getItems(client, entity_jid, NS_OMEMO_DEVICES)
803 except exceptions.NotFound: 808 except exceptions.NotFound:
804 log.info(_("there is no node to handle OMEMO devices")) 809 log.info(_("there is no node to handle OMEMO devices"))
805 defer.returnValue(set()) 810 return set()
806 811
807 devices = self.parseDevices(items) 812 devices = self.parseDevices(items)
808 defer.returnValue(devices) 813 return devices
809 814
810 async def setDevices(self, client, devices): 815 async def setDevices(self, client, devices):
811 log.debug(f"setting devices with {', '.join(str(d) for d in devices)}") 816 log.debug(f"setting devices with {', '.join(str(d) for d in devices)}")
812 list_elt = domish.Element((NS_OMEMO, 'list')) 817 list_elt = domish.Element((NS_OMEMO, 'list'))
813 for device in devices: 818 for device in devices:
825 except Exception as e: 830 except Exception as e:
826 log.warning(_("Can't set devices: {reason}").format(reason=e)) 831 log.warning(_("Can't set devices: {reason}").format(reason=e))
827 832
828 # bundles 833 # bundles
829 834
830 @defer.inlineCallbacks 835 async def getBundles(self, client, entity_jid, devices_ids):
831 def getBundles(self, client, entity_jid, devices_ids):
832 """Retrieve public bundles of an entity devices 836 """Retrieve public bundles of an entity devices
833 837
834 @param entity_jid(jid.JID): bare jid of entity 838 @param entity_jid(jid.JID): bare jid of entity
835 @param devices_id(iterable[int]): ids of the devices bundles to retrieve 839 @param devices_id(iterable[int]): ids of the devices bundles to retrieve
836 @return (tuple(dict[int, ExtendedPublicBundle], list(int))): 840 @return (tuple(dict[int, ExtendedPublicBundle], list(int))):
843 bundles = {} 847 bundles = {}
844 missing = set() 848 missing = set()
845 for device_id in devices_ids: 849 for device_id in devices_ids:
846 node = NS_OMEMO_BUNDLE.format(device_id=device_id) 850 node = NS_OMEMO_BUNDLE.format(device_id=device_id)
847 try: 851 try:
848 items, metadata = yield self._p.getItems(client, entity_jid, node) 852 items, metadata = await self._p.getItems(client, entity_jid, node)
849 except exceptions.NotFound: 853 except exceptions.NotFound:
850 log.warning(_("Bundle missing for device {device_id}") 854 log.warning(_("Bundle missing for device {device_id}")
851 .format(device_id=device_id)) 855 .format(device_id=device_id))
852 missing.add(device_id) 856 missing.add(device_id)
853 continue 857 continue
904 continue 908 continue
905 909
906 bundles[device_id] = ExtendedPublicBundle.parse(omemo_backend, ik, spk, 910 bundles[device_id] = ExtendedPublicBundle.parse(omemo_backend, ik, spk,
907 spkSignature, otpks) 911 spkSignature, otpks)
908 912
909 defer.returnValue((bundles, missing)) 913 return (bundles, missing)
910 914
911 async def setBundle(self, client, bundle, device_id): 915 async def setBundle(self, client, bundle, device_id):
912 """Set public bundle for this device. 916 """Set public bundle for this device.
913 917
914 @param bundle(ExtendedPublicBundle): bundle to publish 918 @param bundle(ExtendedPublicBundle): bundle to publish