annotate sat_pubsub/bookmark_compat.py @ 491:4e8e8788bc86

Bookmark compatibility layer: The new `bookmark_compat` module add a compatibility layer between XEP-0048 (with XEP-0049 private XML storage) and XEP-0402, i.e. it implements the `urn:xmpp:bookmarks:1#compat` feature.
author Goffi <goffi@goffi.org>
date Thu, 21 Nov 2024 11:03:51 +0100
parents
children 468b7cd6c344
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
491
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
1 #!/usr/bin/env python3
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
2 #
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
3 # Copyright (c) 2015-2024 Jérôme Poisson
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
4
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
5
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
6 # This program is free software: you can redistribute it and/or modify
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # it under the terms of the GNU Affero General Public License as published by
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # the Free Software Foundation, either version 3 of the License, or
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # (at your option) any later version.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
10
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
11 # This program is distributed in the hope that it will be useful,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # GNU Affero General Public License for more details.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
15
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
16 # You should have received a copy of the GNU Affero General Public License
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
18
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
19 "This module implements a compatibility layer for XEP-0048."
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
20
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
21
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
22 from twisted.internet import defer
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
23 from twisted.python import log
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
24 from twisted.words.protocols.jabber import error as jabber_error, jid, xmlstream
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
25 from twisted.words.xish import domish
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
26 from wokkel import disco, iwokkel, pubsub
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
27 from wokkel.iwokkel import IPubSubService
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
28 from zope.interface import implementer
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
29
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
30 from sat_pubsub import const
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
31
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
32 from . import error
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
33
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
34 NS_IQ_PRIVATE = "jabber:iq:private"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
35 NS_STORAGE_BOOKMARKS = "storage:bookmarks"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
36 NS_BOOKMARKS2 = "urn:xmpp:bookmarks:1"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 NS_BOOKMARKS_COMPAT = f"{NS_BOOKMARKS2}#compat"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
38 IQ_PRIVATE_GET = f'/iq[@type="get"]/query[@xmlns="{NS_IQ_PRIVATE}"]'
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
39 IQ_PRIVATE_SET = f'/iq[@type="set"]/query[@xmlns="{NS_IQ_PRIVATE}"]'
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
40
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
41
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
42 @implementer(iwokkel.IDisco)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 class BookmarkCompatHandler(disco.DiscoClientProtocol):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
44
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
45 def __init__(self, service_jid):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
46 super().__init__()
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 self.backend = None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
48
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
49 def connectionInitialized(self):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
50 for handler in self.parent.handlers:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 if IPubSubService.providedBy(handler):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
52 self._pubsub_service = handler
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 break
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 self.backend = self.parent.parent.getServiceNamed("backend")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 self.xmlstream.addObserver(IQ_PRIVATE_GET, self._on_get)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 self.xmlstream.addObserver(IQ_PRIVATE_SET, self._on_set)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
57
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 def _on_get(self, iq_elt: domish.Element) -> None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
59 """Handle incoming legacy IQ GET requests for bookmarks.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
60
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
61 This method processes legacy XEP-0048 IQ GET requests. It does some checks and
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
62 then proceeds to return the bookmarks.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
63
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
64 @param iq_elt: The incoming IQ element.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
65 """
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
66 if not iq_elt.delegated:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
67 return
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
68 assert self.xmlstream is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
69 iq_elt.handled = True
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
70 from_jid = jid.JID(iq_elt["from"])
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
71 to_jid = jid.JID(iq_elt["to"])
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 if from_jid.userhostJID() != to_jid:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
73 msg = (
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 f"{from_jid.userhost()} is not allowed to access private storage of "
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
75 f"{to_jid.userhost()}!"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
76 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
77 log.msg(f"Hack attempt? {msg}")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
78 error_elt = jabber_error.StanzaError("forbidden", text=msg).toResponse(iq_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
79 self.xmlstream.send(error_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
80 return
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
81
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
82 query_elt = iq_elt.query
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 assert query_elt is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
84
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
85 storage_elt = query_elt.firstChildElement()
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 if (
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
87 storage_elt is None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 or storage_elt.name != "storage"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
89 or storage_elt.uri != NS_STORAGE_BOOKMARKS
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 ):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
91 error_elt = jabber_error.StanzaError(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
92 "not-allowed",
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 text=(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
94 f'"{NS_STORAGE_BOOKMARKS}" is the only private XML storage allowed '
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
95 "on this server"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 ),
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
97 ).toResponse(iq_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
98 self.xmlstream.send(error_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 return
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
100
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 defer.ensureDeferred(self.return_bookmarks(iq_elt, to_jid))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
102
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 async def return_bookmarks(self, iq_elt: domish.Element, requestor: jid.JID) -> None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 """Send IQ result for bookmark request on private XML.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
105
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
106 Retrieve bookmark from Bookmarks2 PEP node, convert them to private XML
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
107 XEP-0048 format, and send the IQ result.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 @param iq_elt: The incoming IQ element.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
109 @param requestor: The JID of the entity requesting the bookmarks.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 """
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
111 assert self.backend is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
112 assert self.xmlstream is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
113 items, __ = await self.backend.getItems(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
114 NS_BOOKMARKS2, requestor, requestor, ext_data={"pep": True}
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
115 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
116 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
117
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
118 query_elt = iq_result_elt.addElement((NS_IQ_PRIVATE, "query"))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
119 storage_elt = query_elt.addElement((NS_STORAGE_BOOKMARKS, "storage"))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
120
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
121 # For simply add all bookmarks to get XEP-0048 private XML elements.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
122 for item_elt in items:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
123 conference_elt = next(item_elt.elements(NS_BOOKMARKS2, "conference"), None)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
124 if conference_elt is not None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
125 # The namespace is not the same for XEP-0048
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
126 conference_elt.uri = NS_STORAGE_BOOKMARKS
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
127 for elt in conference_elt.children:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
128 elt.uri = NS_STORAGE_BOOKMARKS
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
129 conference_elt["jid"] = item_elt["id"]
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
130 storage_elt.addChild(conference_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
131 else:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
132 log.msg(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
133 "Warning: Unexpectedly missing conference element: "
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
134 f"{item_elt.toXml()}"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
135 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
136
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
137 self.xmlstream.send(iq_result_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
138
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 def _on_set(self, iq_elt: domish.Element) -> None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
140 if not iq_elt.delegated:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
141 return
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
142 assert self.xmlstream is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
143 iq_elt.handled = True
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
144 from_jid = jid.JID(iq_elt["from"])
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
145 to_jid = jid.JID(iq_elt["to"])
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
146 if from_jid.userhostJID() != to_jid:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
147 msg = (
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
148 f"{from_jid.userhost()} is not allowed to access private storage of "
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
149 f"{to_jid.userhost()}!"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
150 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
151 log.msg(f"Hack attempt? {msg}")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
152 error_elt = jabber_error.StanzaError("forbidden", text=msg).toResponse(iq_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
153 self.xmlstream.send(error_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
154 return
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
155 query_elt = iq_elt.query
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
156 assert query_elt is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
157 storage_elt = query_elt.firstChildElement()
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
158 if (
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
159 storage_elt is None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
160 or storage_elt.name != "storage"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
161 or storage_elt.uri != NS_STORAGE_BOOKMARKS
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
162 ):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
163 error_elt = jabber_error.StanzaError(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
164 "not-allowed",
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
165 text=(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
166 f'"{NS_STORAGE_BOOKMARKS}" is the only private XML storage allowed '
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
167 "on this server"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
168 ),
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
169 ).toResponse(iq_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
170 self.xmlstream.send(error_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
171 return
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
172 defer.ensureDeferred(self.on_set(iq_elt, from_jid))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
173
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
174 async def publish_bookmarks(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
175 self, iq_elt: domish.Element, items: list[domish.Element], requestor: jid.JID
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
176 ) -> None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
177 """Publish bookmarks on Bookmarks2 PEP node"""
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
178 assert self.backend is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
179 assert self.xmlstream is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
180 try:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
181 await self.backend.publish(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
182 NS_BOOKMARKS2,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
183 items,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
184 requestor,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
185 options={const.OPT_ACCESS_MODEL: const.VAL_AMODEL_WHITELIST},
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
186 pep=True,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
187 recipient=requestor,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
188 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
189 except error.NodeNotFound:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
190 # The node doesn't exist, we create it
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
191 await self.backend.createNode(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
192 NS_BOOKMARKS2,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
193 requestor,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
194 options={const.OPT_ACCESS_MODEL: const.VAL_AMODEL_WHITELIST},
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
195 pep=True,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
196 recipient=requestor,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
197 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
198 await self.publish_bookmarks(iq_elt, items, requestor)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
199 except Exception as e:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
200 log.err(f"Error while publishing converted bookmarks: {e}")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
201 error_elt = jabber_error.StanzaError(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
202 "internal-server-error",
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
203 text=(f"Something went wrong while publishing the bookmark items: {e}"),
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
204 ).toResponse(iq_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
205 self.xmlstream.send(error_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
206 raise e
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
207
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
208 async def on_set(self, iq_elt: domish.Element, requestor: jid.JID) -> None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
209 """Handle IQ set request for bookmarks on private XML.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
210
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
211 This method processes an IQ set request to update bookmarks stored in private XML.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
212 It extracts conference elements from the request, transforms them into XEP-0402
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
213 format, and publishes them to XEP-0402 PEP node.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
214
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
215 @param iq_elt: The incoming IQ element containing the set request.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
216 @param requestor: The JID of the entity making the request.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
217 """
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
218 # TODO: We should check if items already exist in Bookmarks 2 and avoid updating
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
219 # them if there is no change. However, considering that XEP-0048 is deprecated and
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
220 # active implementations without XEP-0402 are rare, it might not be worth the
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
221 # trouble.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
222 assert self.backend is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
223 assert self.xmlstream is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
224 query_elt = iq_elt.query
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
225 assert query_elt is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
226 # <storage> presence has been checked in ``_on_set``, we know that we have it
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
227 # here.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
228 storage_elt = next(query_elt.elements(NS_STORAGE_BOOKMARKS, "storage"))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
229
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
230 items = []
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
231 for conference_elt in storage_elt.elements(NS_STORAGE_BOOKMARKS, "conference"):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
232 item_elt = domish.Element((pubsub.NS_PUBSUB, "item"))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
233 try:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
234 item_elt["id"] = conference_elt["jid"]
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
235 except AttributeError:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
236 log.msg(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
237 "Warning: ignoring <conference> with missing jid: "
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
238 f"conference_elt.toXml()"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
239 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
240 continue
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
241 new_conference_elt = item_elt.addElement((NS_BOOKMARKS2, "conference"))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
242 for attr, value in conference_elt.attributes.items():
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
243 if attr == "jid":
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
244 continue
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
245 new_conference_elt[attr] = value
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
246 for child in conference_elt.children:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
247 new_child = domish.Element((NS_BOOKMARKS2, child.name))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
248 new_child.addContent(str(child))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
249 new_conference_elt.addChild(new_child)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
250 items.append(item_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
251
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
252 await self.publish_bookmarks(iq_elt, items, requestor)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
253
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
254 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
255 self.xmlstream.send(iq_result_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
256
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
257 def getDiscoInfo(self, requestor, service, nodeIdentifier=""):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
258 return [
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
259 disco.DiscoFeature(NS_IQ_PRIVATE),
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
260 disco.DiscoFeature(NS_BOOKMARKS_COMPAT),
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
261 ]
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
262
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
263 def getDiscoItems(self, requestor, service, nodeIdentifier=""):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
264 return []