annotate sat_pubsub/bookmark_compat.py @ 494:468b7cd6c344 default tip

bookmark compat: handle mapped errors: This convert error on request (e.g. missing node) to appropriate stanza error.
author Goffi <goffi@goffi.org>
date Fri, 13 Dec 2024 12:23:47 +0100
parents 4e8e8788bc86
children
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
494
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
30 from sat_pubsub import backend
491
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
31 from sat_pubsub import const
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
32
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
33 from . import error
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
34
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
35 NS_IQ_PRIVATE = "jabber:iq:private"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
36 NS_STORAGE_BOOKMARKS = "storage:bookmarks"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
37 NS_BOOKMARKS2 = "urn:xmpp:bookmarks:1"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
38 NS_BOOKMARKS_COMPAT = f"{NS_BOOKMARKS2}#compat"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
39 IQ_PRIVATE_GET = f'/iq[@type="get"]/query[@xmlns="{NS_IQ_PRIVATE}"]'
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
40 IQ_PRIVATE_SET = f'/iq[@type="set"]/query[@xmlns="{NS_IQ_PRIVATE}"]'
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
41
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
42
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
43 @implementer(iwokkel.IDisco)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
44 class BookmarkCompatHandler(disco.DiscoClientProtocol):
494
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
45 error_map = backend.PubSubResourceFromBackend.error_map
491
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
46
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
47 def __init__(self, service_jid):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
48 super().__init__()
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
49 self.backend = None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
50
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
51 def connectionInitialized(self):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
52 for handler in self.parent.handlers:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
53 if IPubSubService.providedBy(handler):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
54 self._pubsub_service = handler
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
55 break
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
56 self.backend = self.parent.parent.getServiceNamed("backend")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
57 self.xmlstream.addObserver(IQ_PRIVATE_GET, self._on_get)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
58 self.xmlstream.addObserver(IQ_PRIVATE_SET, self._on_set)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
59
494
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
60 def handle_mapped_error(self, e: error.Error, iq_elt: domish.Element) -> None:
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
61 condition, pubsub_condition, feature = self.error_map[e.__class__] # type: ignore
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
62 msg = e.msg
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
63 if pubsub_condition:
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
64 exc = pubsub.PubSubError(condition, pubsub_condition, feature, msg)
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
65 else:
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
66 exc = jabber_error.StanzaError(condition, text=msg)
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
67 error_elt = exc.toResponse(iq_elt)
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
68 self.xmlstream.send(error_elt)
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
69 return
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
70
491
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
71 def _on_get(self, iq_elt: domish.Element) -> None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
72 """Handle incoming legacy IQ GET requests for bookmarks.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
73
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
74 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
75 then proceeds to return the bookmarks.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
76
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
77 @param iq_elt: The incoming IQ element.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
78 """
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
79 if not iq_elt.delegated:
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 assert self.xmlstream is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
82 iq_elt.handled = True
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
83 from_jid = jid.JID(iq_elt["from"])
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
84 to_jid = jid.JID(iq_elt["to"])
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
85 if from_jid.userhostJID() != to_jid:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
86 msg = (
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
87 f"{from_jid.userhost()} is not allowed to access private storage of "
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
88 f"{to_jid.userhost()}!"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
89 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
90 log.msg(f"Hack attempt? {msg}")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
91 error_elt = jabber_error.StanzaError("forbidden", text=msg).toResponse(iq_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
92 self.xmlstream.send(error_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
93 return
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
94
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
95 query_elt = iq_elt.query
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
96 assert query_elt is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
97
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
98 storage_elt = query_elt.firstChildElement()
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
99 if (
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
100 storage_elt is None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
101 or storage_elt.name != "storage"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
102 or storage_elt.uri != NS_STORAGE_BOOKMARKS
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
103 ):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
104 error_elt = jabber_error.StanzaError(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
105 "not-allowed",
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
106 text=(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
107 f'"{NS_STORAGE_BOOKMARKS}" is the only private XML storage allowed '
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
108 "on this server"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
109 ),
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
110 ).toResponse(iq_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
111 self.xmlstream.send(error_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
112 return
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
113
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
114 defer.ensureDeferred(self.return_bookmarks(iq_elt, to_jid))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
115
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
116 async def return_bookmarks(self, iq_elt: domish.Element, requestor: jid.JID) -> None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
117 """Send IQ result for bookmark request on private XML.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
118
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
119 Retrieve bookmark from Bookmarks2 PEP node, convert them to private XML
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
120 XEP-0048 format, and send the IQ result.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
121 @param iq_elt: The incoming IQ element.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
122 @param requestor: The JID of the entity requesting the bookmarks.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
123 """
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
124 assert self.backend is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
125 assert self.xmlstream is not None
494
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
126 try:
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
127 items, __ = await self.backend.getItems(
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
128 NS_BOOKMARKS2, requestor, requestor, ext_data={"pep": True}
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
129 )
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
130 except tuple(self.error_map.keys()) as e:
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
131 return self.handle_mapped_error(e, iq_elt)
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
132
491
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
133 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
134
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
135 query_elt = iq_result_elt.addElement((NS_IQ_PRIVATE, "query"))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
136 storage_elt = query_elt.addElement((NS_STORAGE_BOOKMARKS, "storage"))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
137
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
138 # For simply add all bookmarks to get XEP-0048 private XML elements.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
139 for item_elt in items:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
140 conference_elt = next(item_elt.elements(NS_BOOKMARKS2, "conference"), None)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
141 if conference_elt is not None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
142 # The namespace is not the same for XEP-0048
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
143 conference_elt.uri = NS_STORAGE_BOOKMARKS
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
144 for elt in conference_elt.children:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
145 elt.uri = NS_STORAGE_BOOKMARKS
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
146 conference_elt["jid"] = item_elt["id"]
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
147 storage_elt.addChild(conference_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
148 else:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
149 log.msg(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
150 "Warning: Unexpectedly missing conference element: "
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
151 f"{item_elt.toXml()}"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
152 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
153
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
154 self.xmlstream.send(iq_result_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
155
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
156 def _on_set(self, iq_elt: domish.Element) -> None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
157 if not iq_elt.delegated:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
158 return
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
159 assert self.xmlstream is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
160 iq_elt.handled = True
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
161 from_jid = jid.JID(iq_elt["from"])
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
162 to_jid = jid.JID(iq_elt["to"])
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
163 if from_jid.userhostJID() != to_jid:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
164 msg = (
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
165 f"{from_jid.userhost()} is not allowed to access private storage of "
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
166 f"{to_jid.userhost()}!"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
167 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
168 log.msg(f"Hack attempt? {msg}")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
169 error_elt = jabber_error.StanzaError("forbidden", text=msg).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 query_elt = iq_elt.query
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
173 assert query_elt is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
174 storage_elt = query_elt.firstChildElement()
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
175 if (
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
176 storage_elt is None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
177 or storage_elt.name != "storage"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
178 or storage_elt.uri != NS_STORAGE_BOOKMARKS
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
179 ):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
180 error_elt = jabber_error.StanzaError(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
181 "not-allowed",
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
182 text=(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
183 f'"{NS_STORAGE_BOOKMARKS}" is the only private XML storage allowed '
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
184 "on this server"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
185 ),
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
186 ).toResponse(iq_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
187 self.xmlstream.send(error_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
188 return
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
189 defer.ensureDeferred(self.on_set(iq_elt, from_jid))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
190
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
191 async def publish_bookmarks(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
192 self, iq_elt: domish.Element, items: list[domish.Element], requestor: jid.JID
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
193 ) -> None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
194 """Publish bookmarks on Bookmarks2 PEP node"""
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
195 assert self.backend is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
196 assert self.xmlstream is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
197 try:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
198 await self.backend.publish(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
199 NS_BOOKMARKS2,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
200 items,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
201 requestor,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
202 options={const.OPT_ACCESS_MODEL: const.VAL_AMODEL_WHITELIST},
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
203 pep=True,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
204 recipient=requestor,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
205 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
206 except error.NodeNotFound:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
207 # The node doesn't exist, we create it
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
208 await self.backend.createNode(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
209 NS_BOOKMARKS2,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
210 requestor,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
211 options={const.OPT_ACCESS_MODEL: const.VAL_AMODEL_WHITELIST},
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
212 pep=True,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
213 recipient=requestor,
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
214 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
215 await self.publish_bookmarks(iq_elt, items, requestor)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
216 except Exception as e:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
217 log.err(f"Error while publishing converted bookmarks: {e}")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
218 error_elt = jabber_error.StanzaError(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
219 "internal-server-error",
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
220 text=(f"Something went wrong while publishing the bookmark items: {e}"),
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
221 ).toResponse(iq_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
222 self.xmlstream.send(error_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
223 raise e
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
224
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
225 async def on_set(self, iq_elt: domish.Element, requestor: jid.JID) -> None:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
226 """Handle IQ set request for bookmarks on private XML.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
227
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
228 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
229 It extracts conference elements from the request, transforms them into XEP-0402
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
230 format, and publishes them to XEP-0402 PEP node.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
231
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
232 @param iq_elt: The incoming IQ element containing the set request.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
233 @param requestor: The JID of the entity making the request.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
234 """
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
235 # 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
236 # 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
237 # active implementations without XEP-0402 are rare, it might not be worth the
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
238 # trouble.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
239 assert self.backend is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
240 assert self.xmlstream is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
241 query_elt = iq_elt.query
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
242 assert query_elt is not None
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
243 # <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
244 # here.
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
245 storage_elt = next(query_elt.elements(NS_STORAGE_BOOKMARKS, "storage"))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
246
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
247 items = []
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
248 for conference_elt in storage_elt.elements(NS_STORAGE_BOOKMARKS, "conference"):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
249 item_elt = domish.Element((pubsub.NS_PUBSUB, "item"))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
250 try:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
251 item_elt["id"] = conference_elt["jid"]
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
252 except AttributeError:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
253 log.msg(
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
254 "Warning: ignoring <conference> with missing jid: "
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
255 f"conference_elt.toXml()"
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
256 )
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
257 continue
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
258 new_conference_elt = item_elt.addElement((NS_BOOKMARKS2, "conference"))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
259 for attr, value in conference_elt.attributes.items():
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
260 if attr == "jid":
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
261 continue
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
262 new_conference_elt[attr] = value
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
263 for child in conference_elt.children:
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
264 new_child = domish.Element((NS_BOOKMARKS2, child.name))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
265 new_child.addContent(str(child))
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
266 new_conference_elt.addChild(new_child)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
267 items.append(item_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
268
494
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
269 try:
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
270 await self.publish_bookmarks(iq_elt, items, requestor)
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
271 except tuple(self.error_map.keys()) as e:
468b7cd6c344 bookmark compat: handle mapped errors:
Goffi <goffi@goffi.org>
parents: 491
diff changeset
272 return self.handle_mapped_error(e, iq_elt)
491
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
273
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
274 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
275 self.xmlstream.send(iq_result_elt)
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
276
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
277 def getDiscoInfo(self, requestor, service, nodeIdentifier=""):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
278 return [
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
279 disco.DiscoFeature(NS_IQ_PRIVATE),
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
280 disco.DiscoFeature(NS_BOOKMARKS_COMPAT),
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
281 ]
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
282
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
283 def getDiscoItems(self, requestor, service, nodeIdentifier=""):
4e8e8788bc86 Bookmark compatibility layer:
Goffi <goffi@goffi.org>
parents:
diff changeset
284 return []