Mercurial > libervia-backend
comparison libervia/backend/plugins/plugin_xep_0308.py @ 4198:b1207332cea2
plugin XEP-0308: fix ID used, recipients and author check.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 13 Dec 2023 22:00:25 +0100 |
parents | a1f7040b5a15 |
children | 0d7bb4df2343 |
comparison
equal
deleted
inserted
replaced
4197:9cda0347e0ac | 4198:b1207332cea2 |
---|---|
14 | 14 |
15 # You should have received a copy of the GNU Affero General Public License | 15 # You should have received a copy of the GNU Affero General Public License |
16 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 17 |
18 import time | 18 import time |
19 import uuid | |
19 | 20 |
20 from sqlalchemy.orm.attributes import flag_modified | 21 from sqlalchemy.orm.attributes import flag_modified |
21 from twisted.internet import defer | 22 from twisted.internet import defer |
22 from twisted.words.protocols.jabber import xmlstream | 23 from twisted.words.protocols.jabber import xmlstream |
23 from twisted.words.protocols.jabber import jid | 24 from twisted.words.protocols.jabber import jid |
81 stmt = ( | 82 stmt = ( |
82 select(History) | 83 select(History) |
83 .where( | 84 .where( |
84 History.profile_id == profile_id, | 85 History.profile_id == profile_id, |
85 History.source == from_jid.userhost(), | 86 History.source == from_jid.userhost(), |
87 History.dest == client.jid.userhost(), | |
86 History.type == message_type, | 88 History.type == message_type, |
87 ) | 89 ) |
88 .options(joinedload(History.messages)) | 90 .options(joinedload(History.messages)) |
89 .options(joinedload(History.subjects)) | 91 .options(joinedload(History.subjects)) |
90 .options(joinedload(History.thread)) | 92 .options(joinedload(History.thread)) |
152 self, | 154 self, |
153 client: SatXMPPEntity, | 155 client: SatXMPPEntity, |
154 message_elt: domish.Element, | 156 message_elt: domish.Element, |
155 post_treat: defer.Deferred, | 157 post_treat: defer.Deferred, |
156 ) -> bool: | 158 ) -> bool: |
159 from_jid = jid.JID(message_elt["from"]) | |
157 replace_elt = next(message_elt.elements(NS_MESSAGE_CORRECT, "replace"), None) | 160 replace_elt = next(message_elt.elements(NS_MESSAGE_CORRECT, "replace"), None) |
158 if not replace_elt: | 161 if not replace_elt: |
159 return True | 162 return True |
160 try: | 163 try: |
161 replace_id = replace_elt["id"].strip() | 164 replace_id = replace_elt["id"].strip() |
165 log.warning(f"Invalid message correction: {message_elt.toXml()}") | 168 log.warning(f"Invalid message correction: {message_elt.toXml()}") |
166 else: | 169 else: |
167 edited_history = await self.get_last_history(client, message_elt) | 170 edited_history = await self.get_last_history(client, message_elt) |
168 if edited_history is None: | 171 if edited_history is None: |
169 log.warning( | 172 log.warning( |
170 f"No message found from {message_elt['from']}, can't correct " | 173 f"No message found from {from_jid.full()}, can't correct " |
171 f"anything: {message_elt.toXml()}" | 174 f"anything: {message_elt.toXml()}" |
172 ) | 175 ) |
173 return False | 176 return True |
174 if edited_history.extra.get("message_id") != replace_id: | 177 check_id = edited_history.origin_id or edited_history.extra.get("message_id") |
178 if check_id != replace_id: | |
175 log.warning( | 179 log.warning( |
176 "Can't apply correction: it doesn't reference the last one: " | 180 "Can't apply correction: it doesn't reference the last one:\n" |
177 f"{message_elt.toXml}" | 181 f"{message_elt.toXml()}" |
178 ) | 182 ) |
179 return False | 183 return True |
184 # TODO: this only accept same full JID, if we do more than last message | |
185 # correction, we may want to accept different resource for non groupchat | |
186 # messages (in case of reconnection with resource change for instance). | |
187 if edited_history.source_jid != from_jid: | |
188 log.warning( | |
189 "Can't apply correction: correction doesn't come from same author " | |
190 f"{edited_history.source_jid.full()}:\n{message_elt.toXml()}" | |
191 ) | |
192 return True | |
193 | |
180 previous_message_data = edited_history.serialise() | 194 previous_message_data = edited_history.serialise() |
181 message_data = client.messageProt.parse_message(message_elt) | 195 message_data = client.messageProt.parse_message(message_elt) |
182 if not message_data["message"] and not message_data["subject"]: | 196 if not message_data["message"] and not message_data["subject"]: |
183 log.warning( | 197 log.warning( |
184 "Message correction doesn't have body not subject, we can't edit " | 198 "Message correction doesn't have body nor subject, we can't edit " |
185 "anything" | 199 "anything" |
186 ) | 200 ) |
187 return False | 201 return False |
188 | 202 |
189 await self.update_history( | 203 await self.update_history( |
225 raise exceptions.NotFound( | 239 raise exceptions.NotFound( |
226 f"message to edit not found in database ({message_id})" | 240 f"message to edit not found in database ({message_id})" |
227 ) | 241 ) |
228 if edited_history.type == C.MESS_TYPE_GROUPCHAT: | 242 if edited_history.type == C.MESS_TYPE_GROUPCHAT: |
229 is_group_chat = True | 243 is_group_chat = True |
230 peer_jid = edited_history.dest_jid | 244 # In the case of group chat, our message is sent by ourself with our room JID. |
245 peer_jid = edited_history.source_jid | |
231 else: | 246 else: |
232 is_group_chat = False | 247 is_group_chat = False |
233 peer_jid = jid.JID(edited_history.dest) | 248 peer_jid = jid.JID(edited_history.dest) |
234 history_data = await self.host.memory.history_get( | 249 history_data = await self.host.memory.history_get( |
235 client.jid, peer_jid, limit=1, profile=client.profile | 250 client.jid, peer_jid, limit=1, profile=client.profile |
236 ) | 251 ) |
237 if not history_data: | 252 if not history_data: |
238 raise exceptions.NotFound( | 253 raise exceptions.NotFound( |
239 "No message found in conversation with {peer_jid.full()}" | 254 "No message found in conversation with {peer_jid.userhost()}" |
240 ) | 255 ) |
241 last_mess = history_data[0] | 256 last_mess = history_data[0] |
242 if last_mess[0] != message_id: | 257 if last_mess[0] != message_id: |
243 raise ValueError( | 258 raise ValueError( |
244 f"{message_id} is not the last message of the discussion, we can't edit " | 259 f"{message_id} is not the last message of the discussion, we can't edit " |
258 # message will be updated and signal sent on reception in group chat | 273 # message will be updated and signal sent on reception in group chat |
259 store = not is_group_chat | 274 store = not is_group_chat |
260 ) | 275 ) |
261 | 276 |
262 serialised = edited_history.serialise() | 277 serialised = edited_history.serialise() |
263 serialised["from"] = jid.JID(serialised["from"]) | 278 serialised["uid"] = str(uuid.uuid4()) |
264 serialised["to"] = jid.JID(serialised["to"]) | 279 serialised["from"] = client.jid |
280 # for group chat, we want to send the correction to the room | |
281 serialised["to"] = peer_jid.userhostJID() if is_group_chat else peer_jid | |
265 | 282 |
266 message_elt = client.generate_message_xml(serialised)["xml"] | 283 message_elt = client.generate_message_xml(serialised)["xml"] |
267 replace_elt = message_elt.addElement((NS_MESSAGE_CORRECT, "replace")) | 284 replace_elt = message_elt.addElement((NS_MESSAGE_CORRECT, "replace")) |
268 replace_elt["id"] = message_id | 285 replace_elt["id"] = edited_history.origin_id |
269 self._h.add_hint_elements(message_elt, [self._h.HINT_STORE]) | 286 self._h.add_hint_elements(message_elt, [self._h.HINT_STORE]) |
270 client.send(message_elt) | 287 client.send(message_elt) |
271 | 288 |
272 def _message_edit(self, message_id: str, edit_data_s: str, profile: str) -> None: | 289 def _message_edit(self, message_id: str, edit_data_s: str, profile: str) -> None: |
273 client = self.host.get_client(profile) | 290 client = self.host.get_client(profile) |