Mercurial > libervia-backend
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 |