Mercurial > libervia-backend
comparison libervia/backend/plugins/plugin_xep_0391.py @ 4270:0d7bb4df2343
Reformatted code base using black.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 19 Jun 2024 18:44:57 +0200 |
parents | e11b13418ba6 |
children |
comparison
equal
deleted
inserted
replaced
4269:64a85ce8be70 | 4270:0d7bb4df2343 |
---|---|
75 log.info(_("XEP-0391 (Pubsub Attachments) plugin initialization")) | 75 log.info(_("XEP-0391 (Pubsub Attachments) plugin initialization")) |
76 host.register_namespace("jet", NS_JET) | 76 host.register_namespace("jet", NS_JET) |
77 self.host = host | 77 self.host = host |
78 self._o = host.plugins["XEP-0384"] | 78 self._o = host.plugins["XEP-0384"] |
79 self._j = host.plugins["XEP-0166"] | 79 self._j = host.plugins["XEP-0166"] |
80 host.trigger.add("XEP-0166_initiate_elt_built", self._on_initiate_elt_build) | |
81 host.trigger.add("XEP-0166_on_session_initiate", self._on_session_initiate) | |
82 host.trigger.add("XEP-0234_jingle_handler", self._add_encryption_filter) | |
80 host.trigger.add( | 83 host.trigger.add( |
81 "XEP-0166_initiate_elt_built", | 84 "XEP-0234_file_receiving_request_conf", self._add_encryption_filter |
82 self._on_initiate_elt_build | |
83 ) | |
84 host.trigger.add( | |
85 "XEP-0166_on_session_initiate", | |
86 self._on_session_initiate | |
87 ) | |
88 host.trigger.add( | |
89 "XEP-0234_jingle_handler", | |
90 self._add_encryption_filter | |
91 ) | |
92 host.trigger.add( | |
93 "XEP-0234_file_receiving_request_conf", | |
94 self._add_encryption_filter | |
95 ) | 85 ) |
96 | 86 |
97 def get_handler(self, client): | 87 def get_handler(self, client): |
98 return JET_Handler() | 88 return JET_Handler() |
99 | 89 |
100 async def _on_initiate_elt_build( | 90 async def _on_initiate_elt_build( |
101 self, | 91 self, |
102 client: SatXMPPEntity, | 92 client: SatXMPPEntity, |
103 session: Dict[str, Any], | 93 session: Dict[str, Any], |
104 iq_elt: domish.Element, | 94 iq_elt: domish.Element, |
105 jingle_elt: domish.Element | 95 jingle_elt: domish.Element, |
106 ) -> bool: | 96 ) -> bool: |
107 if client.encryption.get_namespace( | 97 if ( |
108 session["peer_jid"].userhostJID() | 98 client.encryption.get_namespace(session["peer_jid"].userhostJID()) |
109 ) != self._o.NS_OLDMEMO: | 99 != self._o.NS_OLDMEMO |
100 ): | |
110 return True | 101 return True |
111 for content_elt in jingle_elt.elements(self._j.namespace, "content"): | 102 for content_elt in jingle_elt.elements(self._j.namespace, "content"): |
112 content_data = session["contents"][content_elt["name"]] | 103 content_data = session["contents"][content_elt["name"]] |
113 transport_data = content_data["transport_data"] | 104 transport_data = content_data["transport_data"] |
114 if transport_data.get("webrtc"): | 105 if transport_data.get("webrtc"): |
124 enc_type = "eu.siacs.conversations.axolotl" | 115 enc_type = "eu.siacs.conversations.axolotl" |
125 security_elt["cipher"] = cipher | 116 security_elt["cipher"] = cipher |
126 security_elt["type"] = enc_type | 117 security_elt["type"] = enc_type |
127 encryption_data = content_data["encryption"] = { | 118 encryption_data = content_data["encryption"] = { |
128 "cipher": cipher, | 119 "cipher": cipher, |
129 "type": enc_type | 120 "type": enc_type, |
130 } | 121 } |
131 session_manager = await self._o.get_session_manager(client.profile) | 122 session_manager = await self._o.get_session_manager(client.profile) |
132 await self._o.download_missing_device_lists( | 123 await self._o.download_missing_device_lists( |
133 client, self._o.NS_OLDMEMO, {session["peer_jid"]}, session_manager | 124 client, self._o.NS_OLDMEMO, {session["peer_jid"]}, session_manager |
134 ) | 125 ) |
135 try: | 126 try: |
136 messages, encryption_errors = await session_manager.encrypt( | 127 messages, encryption_errors = await session_manager.encrypt( |
137 frozenset({session["peer_jid"].userhost()}), | 128 frozenset({session["peer_jid"].userhost()}), |
138 # the value seems to be the commonly used value | 129 # the value seems to be the commonly used value |
139 { self._o.NS_OLDMEMO: b" " }, | 130 {self._o.NS_OLDMEMO: b" "}, |
140 backend_priority_order=[ self._o.NS_OLDMEMO ], | 131 backend_priority_order=[self._o.NS_OLDMEMO], |
141 identifier = client.jid.userhost() | 132 identifier=client.jid.userhost(), |
142 ) | 133 ) |
143 except Exception as e: | 134 except Exception as e: |
144 log.exception("Can't generate IV and keys") | 135 log.exception("Can't generate IV and keys") |
145 raise e | 136 raise e |
146 message, plain_key_material = next(iter(messages.items())) | 137 message, plain_key_material = next(iter(messages.items())) |
147 iv, key = message.content.initialization_vector, plain_key_material.key | 138 iv, key = message.content.initialization_vector, plain_key_material.key |
148 content_data["encryption"].update({ | 139 content_data["encryption"].update({"iv": iv, "key": key}) |
149 "iv": iv, | |
150 "key": key | |
151 }) | |
152 encrypted_elt = xml_tools.et_elt_2_domish_elt( | 140 encrypted_elt = xml_tools.et_elt_2_domish_elt( |
153 oldmemo.etree.serialize_message(message) | 141 oldmemo.etree.serialize_message(message) |
154 ) | 142 ) |
155 security_elt.addChild(encrypted_elt) | 143 security_elt.addChild(encrypted_elt) |
156 return True | 144 return True |
158 async def _on_session_initiate( | 146 async def _on_session_initiate( |
159 self, | 147 self, |
160 client: SatXMPPEntity, | 148 client: SatXMPPEntity, |
161 session: Dict[str, Any], | 149 session: Dict[str, Any], |
162 iq_elt: domish.Element, | 150 iq_elt: domish.Element, |
163 jingle_elt: domish.Element | 151 jingle_elt: domish.Element, |
164 ) -> bool: | 152 ) -> bool: |
165 for content_elt in jingle_elt.elements(self._j.namespace, "content"): | 153 for content_elt in jingle_elt.elements(self._j.namespace, "content"): |
166 content_data = session["contents"][content_elt["name"]] | 154 content_data = session["contents"][content_elt["name"]] |
167 security_elt = next(content_elt.elements(NS_JET, "security"), None) | 155 security_elt = next(content_elt.elements(NS_JET, "security"), None) |
168 if security_elt is None: | 156 if security_elt is None: |
179 try: | 167 try: |
180 message = await oldmemo.etree.parse_message( | 168 message = await oldmemo.etree.parse_message( |
181 xml_tools.domish_elt_2_et_elt(encrypted_elt, False), | 169 xml_tools.domish_elt_2_et_elt(encrypted_elt, False), |
182 session["peer_jid"].userhost(), | 170 session["peer_jid"].userhost(), |
183 client.jid.userhost(), | 171 client.jid.userhost(), |
184 session_manager | 172 session_manager, |
185 ) | 173 ) |
186 __, __, plain_key_material = await session_manager.decrypt(message) | 174 __, __, plain_key_material = await session_manager.decrypt(message) |
187 except Exception as e: | 175 except Exception as e: |
188 log.warning(f"Can't get IV and key: {e}\n{security_elt.toXml()}") | 176 log.warning(f"Can't get IV and key: {e}\n{security_elt.toXml()}") |
189 continue | 177 continue |
190 try: | 178 try: |
191 content_data["encryption"] = { | 179 content_data["encryption"] = { |
192 "cipher": security_elt["cipher"], | 180 "cipher": security_elt["cipher"], |
193 "type": security_elt["type"], | 181 "type": security_elt["type"], |
194 "iv": message.content.initialization_vector, | 182 "iv": message.content.initialization_vector, |
195 "key": plain_key_material.key | 183 "key": plain_key_material.key, |
196 } | 184 } |
197 except KeyError as e: | 185 except KeyError as e: |
198 log.warning(f"missing data, can't decrypt: {e}") | 186 log.warning(f"missing data, can't decrypt: {e}") |
199 continue | 187 continue |
200 | 188 |
201 return True | 189 return True |
202 | 190 |
203 def __encrypt( | 191 def __encrypt( |
204 self, | 192 self, data: bytes, encryptor: CipherContext, data_cb: Callable |
205 data: bytes, | |
206 encryptor: CipherContext, | |
207 data_cb: Callable | |
208 ) -> bytes: | 193 ) -> bytes: |
209 data_cb(data) | 194 data_cb(data) |
210 if data: | 195 if data: |
211 return encryptor.update(data) | 196 return encryptor.update(data) |
212 else: | 197 else: |
213 try: | 198 try: |
214 return encryptor.finalize() + encryptor.tag | 199 return encryptor.finalize() + encryptor.tag |
215 except AlreadyFinalized: | 200 except AlreadyFinalized: |
216 return b'' | 201 return b"" |
217 | 202 |
218 def __decrypt( | 203 def __decrypt( |
219 self, | 204 self, |
220 data: bytes, | 205 data: bytes, |
221 buffer: list[bytes], | 206 buffer: list[bytes], |
222 decryptor: CipherContext, | 207 decryptor: CipherContext, |
223 data_cb: Callable | 208 data_cb: Callable, |
224 ) -> bytes: | 209 ) -> bytes: |
225 buffer.append(data) | 210 buffer.append(data) |
226 data = b''.join(buffer) | 211 data = b"".join(buffer) |
227 buffer.clear() | 212 buffer.clear() |
228 if len(data) > 16: | 213 if len(data) > 16: |
229 decrypted = decryptor.update(data[:-16]) | 214 decrypted = decryptor.update(data[:-16]) |
230 data_cb(decrypted) | 215 data_cb(decrypted) |
231 else: | 216 else: |
232 decrypted = b'' | 217 decrypted = b"" |
233 buffer.append(data[-16:]) | 218 buffer.append(data[-16:]) |
234 return decrypted | 219 return decrypted |
235 | 220 |
236 def __decrypt_finalize( | 221 def __decrypt_finalize( |
237 self, | 222 self, |
238 file_obj: io.BytesIO, | 223 file_obj: io.BytesIO, |
239 buffer: list[bytes], | 224 buffer: list[bytes], |
240 decryptor: CipherContext, | 225 decryptor: CipherContext, |
241 ) -> None: | 226 ) -> None: |
242 tag = b''.join(buffer) | 227 tag = b"".join(buffer) |
243 file_obj.write(decryptor.finalize_with_tag(tag)) | 228 file_obj.write(decryptor.finalize_with_tag(tag)) |
244 | 229 |
245 async def _add_encryption_filter( | 230 async def _add_encryption_filter( |
246 self, | 231 self, |
247 client: SatXMPPEntity, | 232 client: SatXMPPEntity, |
248 session: Dict[str, Any], | 233 session: Dict[str, Any], |
249 content_data: Dict[str, Any], | 234 content_data: Dict[str, Any], |
250 elt: domish.Element | 235 elt: domish.Element, |
251 ) -> bool: | 236 ) -> bool: |
252 try: | 237 try: |
253 file_obj = content_data["stream_object"].file_obj | 238 file_obj = content_data["stream_object"].file_obj |
254 except KeyError: | 239 except KeyError: |
255 transport_data = content_data["transport_data"] | 240 transport_data = content_data["transport_data"] |
256 if transport_data.get("webrtc"): | 241 if transport_data.get("webrtc"): |
257 # we skip JET to avoid double encryption | 242 # we skip JET to avoid double encryption |
258 log.debug("JET skipped due to webrtc transport.") | 243 log.debug("JET skipped due to webrtc transport.") |
259 return True | 244 return True |
260 try: | 245 try: |
261 encryption_data=content_data["encryption"] | 246 encryption_data = content_data["encryption"] |
262 except KeyError: | 247 except KeyError: |
263 return True | 248 return True |
264 cipher = ciphers.Cipher( | 249 cipher = ciphers.Cipher( |
265 ciphers.algorithms.AES(encryption_data["key"]), | 250 ciphers.algorithms.AES(encryption_data["key"]), |
266 modes.GCM(encryption_data["iv"]), | 251 modes.GCM(encryption_data["iv"]), |
272 decryptor = cipher.decryptor() | 257 decryptor = cipher.decryptor() |
273 file_obj.pre_close_cb = partial( | 258 file_obj.pre_close_cb = partial( |
274 self.__decrypt_finalize, | 259 self.__decrypt_finalize, |
275 file_obj=file_obj, | 260 file_obj=file_obj, |
276 buffer=buffer, | 261 buffer=buffer, |
277 decryptor=decryptor | 262 decryptor=decryptor, |
278 ) | 263 ) |
279 file_obj.data_cb = partial( | 264 file_obj.data_cb = partial( |
280 self.__decrypt, | 265 self.__decrypt, |
281 buffer=buffer, | 266 buffer=buffer, |
282 decryptor=decryptor, | 267 decryptor=decryptor, |
283 data_cb=file_obj.data_cb | 268 data_cb=file_obj.data_cb, |
284 ) | 269 ) |
285 else: | 270 else: |
286 # we are sending a file | 271 # we are sending a file |
287 file_obj.data_cb = partial( | 272 file_obj.data_cb = partial( |
288 self.__encrypt, | 273 self.__encrypt, encryptor=cipher.encryptor(), data_cb=file_obj.data_cb |
289 encryptor=cipher.encryptor(), | |
290 data_cb=file_obj.data_cb | |
291 ) | 274 ) |
292 | 275 |
293 return True | 276 return True |
294 | 277 |
295 | 278 |