Mercurial > libervia-backend
comparison sat/plugins/plugin_sec_aesgcm.py @ 3219:2ba602aef90e
plugin attach, aesgcm: attachments refactoring:
attachment handling has been simplified, and now use a "register" method similar as the
ones used for download or upload.
A default method (for unencrypted messages) will try a simple upload and will copy the
links to body.
AESGCM plugin has been adapted to be used for encrypted files. If more than one file is
sent with AESGCM plugin, they will be split in several messages as current de-facto
standard (OMEMO media sharing) doesn't support several files per message.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 18 Mar 2020 20:25:02 +0100 |
parents | 2c0628f3927e |
children | 653fa213d2f8 |
comparison
equal
deleted
inserted
replaced
3218:806a7936a591 | 3219:2ba602aef90e |
---|---|
40 PLUGIN_INFO = { | 40 PLUGIN_INFO = { |
41 C.PI_NAME: "AES-GCM", | 41 C.PI_NAME: "AES-GCM", |
42 C.PI_IMPORT_NAME: "AES-GCM", | 42 C.PI_IMPORT_NAME: "AES-GCM", |
43 C.PI_TYPE: "SEC", | 43 C.PI_TYPE: "SEC", |
44 C.PI_PROTOCOLS: ["OMEMO Media sharing"], | 44 C.PI_PROTOCOLS: ["OMEMO Media sharing"], |
45 C.PI_DEPENDENCIES: ["XEP-0363", "XEP-0384", "DOWNLOAD"], | 45 C.PI_DEPENDENCIES: ["XEP-0363", "XEP-0384", "DOWNLOAD", "ATTACH"], |
46 C.PI_MAIN: "AESGCM", | 46 C.PI_MAIN: "AESGCM", |
47 C.PI_HANDLER: "no", | 47 C.PI_HANDLER: "no", |
48 C.PI_DESCRIPTION: dedent(_("""\ | 48 C.PI_DESCRIPTION: dedent(_("""\ |
49 Implementation of AES-GCM scheme, a way to encrypt files (not official XMPP standard). | 49 Implementation of AES-GCM scheme, a way to encrypt files (not official XMPP standard). |
50 See https://xmpp.org/extensions/inbox/omemo-media-sharing.html for details | 50 See https://xmpp.org/extensions/inbox/omemo-media-sharing.html for details |
59 class AESGCM(object): | 59 class AESGCM(object): |
60 | 60 |
61 def __init__(self, host): | 61 def __init__(self, host): |
62 self.host = host | 62 self.host = host |
63 log.info(_("AESGCM plugin initialization")) | 63 log.info(_("AESGCM plugin initialization")) |
64 self._http_upload = host.plugins['XEP-0363'] | |
65 self._attach = host.plugins["ATTACH"] | |
64 host.plugins["DOWNLOAD"].registerScheme( | 66 host.plugins["DOWNLOAD"].registerScheme( |
65 "aesgcm", self.download | 67 "aesgcm", self.download |
66 ) | 68 ) |
69 self._attach.register( | |
70 self.canHandleAttachment, self.attach, encrypted=True) | |
67 host.trigger.add("XEP-0363_upload_size", self._uploadSizeTrigger) | 71 host.trigger.add("XEP-0363_upload_size", self._uploadSizeTrigger) |
68 host.trigger.add("XEP-0363_upload", self._uploadTrigger) | 72 host.trigger.add("XEP-0363_upload", self._uploadTrigger) |
69 host.trigger.add("messageReceived", self._messageReceivedTrigger) | 73 host.trigger.add("messageReceived", self._messageReceivedTrigger) |
70 | 74 |
71 async def download(self, client, uri_parsed, dest_path, options): | 75 async def download(self, client, uri_parsed, dest_path, options): |
125 decryptor=decryptor)) | 129 decryptor=decryptor)) |
126 else: | 130 else: |
127 d = defer.Deferred() | 131 d = defer.Deferred() |
128 self.host.plugins["DOWNLOAD"].errbackDownload(file_obj, d, resp) | 132 self.host.plugins["DOWNLOAD"].errbackDownload(file_obj, d, resp) |
129 return progress_id, d | 133 return progress_id, d |
134 | |
135 async def canHandleAttachment(self, client, data): | |
136 try: | |
137 await self._http_upload.getHTTPUploadEntity(client) | |
138 except exceptions.NotFound: | |
139 return False | |
140 else: | |
141 return True | |
142 | |
143 async def _uploadCb(self, client, filepath, filename, options): | |
144 options['encryption'] = C.ENC_AES_GCM | |
145 return await self._http_upload.fileHTTPUpload( | |
146 client=client, | |
147 filepath=filepath, | |
148 filename=filename, | |
149 options=options | |
150 ) | |
151 | |
152 async def attach(self, client, data): | |
153 # XXX: the attachment removal/resend code below is due to the one file per | |
154 # message limitation of OMEMO media sharing unofficial XEP. We have to remove | |
155 # attachments from original message, and send them one by one. | |
156 # TODO: this is to be removed when a better mechanism is available with OMEMO (now | |
157 # possible with the 0.4 version of OMEMO, it's possible to encrypt other stanza | |
158 # elements than body). | |
159 attachments = data["extra"][C.MESS_KEY_ATTACHMENTS] | |
160 if not data['message'] or data['message'] == {'': ''}: | |
161 extra_attachments = attachments[1:] | |
162 del attachments[1:] | |
163 await self._attach.uploadFiles(client, data, upload_cb=self._uploadCb) | |
164 else: | |
165 # we have a message, we must send first attachment separately | |
166 extra_attachments = attachments[:] | |
167 attachments.clear() | |
168 del data["extra"][C.MESS_KEY_ATTACHMENTS] | |
169 | |
170 body_elt = next(data["xml"].elements((C.NS_CLIENT, "body"))) | |
171 | |
172 for attachment in attachments: | |
173 body_elt.addContent(attachment["url"]) | |
174 | |
175 for attachment in extra_attachments: | |
176 # we send all remaining attachment in a separate message | |
177 client.sendMessage( | |
178 to_jid=data['to'], | |
179 message={'': ''}, | |
180 subject=data['subject'], | |
181 mess_type=data['type'], | |
182 extra={C.MESS_KEY_ATTACHMENTS: [attachment]}, | |
183 ) | |
184 | |
185 if ((not data['extra'] | |
186 and (not data['message'] or data['message'] == {'': ''}) | |
187 and not data['subject'])): | |
188 # nothing left to send, we can cancel the message | |
189 raise exceptions.CancelError("Cancelled by AESGCM attachment handling") | |
130 | 190 |
131 def onDataDownload(self, data, client, file_obj, decryptor): | 191 def onDataDownload(self, data, client, file_obj, decryptor): |
132 if file_obj.tell() + len(data) > file_obj.size: | 192 if file_obj.tell() + len(data) > file_obj.size: |
133 # we're reaching end of file with this bunch of data | 193 # we're reaching end of file with this bunch of data |
134 # we may still have a last bunch if the tag is incomplete | 194 # we may still have a last bunch if the tag is incomplete |