annotate libervia/web/server/session_iface.py @ 1598:86c7a3a625d5

server: always start a new session on connection: The session was kept when a user was connecting from service profile (but not from other profiles), this was leading to session fixation vulnerability (an attacker on the same machine could get service profile session cookie, and use it when a victim would log-in). This patch fixes it by always starting a new session on connection. fix 443
author Goffi <goffi@goffi.org>
date Fri, 23 Feb 2024 13:35:24 +0100
parents 7941444c1671
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
1239
f511f8fbbf8a fixed shebangs
Goffi <goffi@goffi.org>
parents: 1237
diff changeset
1 #!/usr/bin/env python3
f511f8fbbf8a fixed shebangs
Goffi <goffi@goffi.org>
parents: 1237
diff changeset
2
1595
7941444c1671 pages: set `own_local_jid` to avoid confusion with `own_jid`:
Goffi <goffi@goffi.org>
parents: 1518
diff changeset
3 # Libervia Web Frontend
1396
822bd0139769 date update
Goffi <goffi@goffi.org>
parents: 1322
diff changeset
4 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org)
919
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
5
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
6 # This program is free software: you can redistribute it and/or modify
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
7 # it under the terms of the GNU Affero General Public License as published by
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
8 # the Free Software Foundation, either version 3 of the License, or
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
9 # (at your option) any later version.
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
10
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
11 # This program is distributed in the hope that it will be useful,
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
14 # GNU Affero General Public License for more details.
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
15
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
16 # You should have received a copy of the GNU Affero General Public License
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
1504
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
18 from collections import OrderedDict, deque
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
19 import os.path
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
20 import time
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
21 from typing import List, Dict, Optional
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
22
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
23 import shortuuid
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
24 from zope.interface import Attribute, Interface
1216
b2d067339de3 python 3 port:
Goffi <goffi@goffi.org>
parents: 1186
diff changeset
25 from zope.interface import implementer
1504
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
26
1518
eb00d593801d refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents: 1509
diff changeset
27 from libervia.backend.core.log import getLogger
1504
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
28
1518
eb00d593801d refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents: 1509
diff changeset
29 from libervia.web.server.classes import Notification
eb00d593801d refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents: 1509
diff changeset
30 from libervia.web.server.constants import Const as C
1504
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
31
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
32
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
33 log = getLogger(__name__)
919
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
34
1113
cdd389ef97bc server: code style reformatting using black
Goffi <goffi@goffi.org>
parents: 1101
diff changeset
35 FLAGS_KEY = "_flags"
1186
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
36 NOTIFICATIONS_KEY = "_notifications"
1093
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
37 MAX_CACHE_AFFILIATIONS = 100 # number of nodes to keep in cache
960
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
38
1113
cdd389ef97bc server: code style reformatting using black
Goffi <goffi@goffi.org>
parents: 1101
diff changeset
39
1506
ce879da7fcf7 server: fix `on_signal` callback
Goffi <goffi@goffi.org>
parents: 1504
diff changeset
40 class IWebSession(Interface):
1598
86c7a3a625d5 server: always start a new session on connection:
Goffi <goffi@goffi.org>
parents: 1595
diff changeset
41 profile = Attribute("Libervia profile")
919
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
42 jid = Attribute("JID associated with the profile")
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
43 uuid = Attribute("uuid associated with the profile session")
947
92f0eeb6dc72 pages: cache identities identities in session + get identities for comments in blog
Goffi <goffi@goffi.org>
parents: 919
diff changeset
44 identities = Attribute("Identities of XMPP entities")
919
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
45
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
46
1506
ce879da7fcf7 server: fix `on_signal` callback
Goffi <goffi@goffi.org>
parents: 1504
diff changeset
47 @implementer(IWebSession)
ce879da7fcf7 server: fix `on_signal` callback
Goffi <goffi@goffi.org>
parents: 1504
diff changeset
48 class WebSession:
ce879da7fcf7 server: fix `on_signal` callback
Goffi <goffi@goffi.org>
parents: 1504
diff changeset
49 profiles_map: Dict[Optional[str], List["WebSession"]] = {}
919
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
50
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
51 def __init__(self, session):
1504
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
52 self._profile = None
919
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
53 self.jid = None
1090
9c41b7e91172 server: set jid and started time in session on log-in:
Goffi <goffi@goffi.org>
parents: 1055
diff changeset
54 self.started = time.time()
9c41b7e91172 server: set jid and started time in session on log-in:
Goffi <goffi@goffi.org>
parents: 1055
diff changeset
55 # time when the backend session was started
9c41b7e91172 server: set jid and started time in session on log-in:
Goffi <goffi@goffi.org>
parents: 1055
diff changeset
56 self.backend_started = None
1216
b2d067339de3 python 3 port:
Goffi <goffi@goffi.org>
parents: 1186
diff changeset
57 self.uuid = str(shortuuid.uuid())
1322
a0954b6610aa pages: identities are not using `data_objects` anymore:
Goffi <goffi@goffi.org>
parents: 1275
diff changeset
58 self.identities = {}
1216
b2d067339de3 python 3 port:
Goffi <goffi@goffi.org>
parents: 1186
diff changeset
59 self.csrf_token = str(shortuuid.uuid())
1504
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
60 self.ws_token = str(shortuuid.uuid())
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
61 self.ws_socket = None
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
62 self.ws_buffer = deque(maxlen=200)
1165
6424d3684d1e pages: locale handling:
Goffi <goffi@goffi.org>
parents: 1144
diff changeset
63 self.locale = None # i18n of the pages
1275
334d044f2713 server: default theme can now be specified in site section of `sat.conf` with `theme` key
Goffi <goffi@goffi.org>
parents: 1270
diff changeset
64 self.theme = None
960
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
65 self.pages_data = {} # used to keep data accross reloads (key is page instance)
1093
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
66 self.affiliations = OrderedDict() # cache for node affiliations
1504
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
67 self.profiles_map.setdefault(C.SERVICE_PROFILE, []).append(self)
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
68 log.debug(
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
69 f"session started for {C.SERVICE_PROFILE} "
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
70 f"({len(self.get_profile_sessions(C.SERVICE_PROFILE))} session(s) active)"
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
71 )
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
72
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
73 @property
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
74 def profile(self) -> Optional[str]:
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
75 return self._profile
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
76
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
77 @profile.setter
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
78 def profile(self, profile: Optional[str]) -> None:
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
79 old_profile = self._profile or C.SERVICE_PROFILE
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
80 new_profile = profile or C.SERVICE_PROFILE
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
81 try:
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
82 self.profiles_map[old_profile].remove(self)
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
83 except (ValueError, KeyError):
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
84 log.warning(f"session was not registered for profile {old_profile}")
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
85 else:
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
86 nb_session_old = len(self.get_profile_sessions(old_profile))
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
87 log.debug(f"{old_profile} has now {nb_session_old} session(s) active")
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
88
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
89 self._profile = profile
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
90 self.profiles_map.setdefault(new_profile, []).append(self)
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
91 nb_session_new = len(self.get_profile_sessions(new_profile))
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
92 log.debug(f"{new_profile} has now {nb_session_new} session(s) active")
960
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
93
995
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents: 964
diff changeset
94 @property
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents: 964
diff changeset
95 def cache_dir(self):
1055
c2037b44f84e server: fixed cache_dir for service profile in session interface
Goffi <goffi@goffi.org>
parents: 1054
diff changeset
96 if self.profile is None:
1216
b2d067339de3 python 3 port:
Goffi <goffi@goffi.org>
parents: 1186
diff changeset
97 return self.service_cache_url + "/"
b2d067339de3 python 3 port:
Goffi <goffi@goffi.org>
parents: 1186
diff changeset
98 return os.path.join("/", C.CACHE_DIR, self.uuid) + "/"
995
f88325b56a6a server: dynamic pages first draft:
Goffi <goffi@goffi.org>
parents: 964
diff changeset
99
1094
8a270f32de81 server (session): new "connected" property, which is True when a user is logged
Goffi <goffi@goffi.org>
parents: 1093
diff changeset
100 @property
8a270f32de81 server (session): new "connected" property, which is True when a user is logged
Goffi <goffi@goffi.org>
parents: 1093
diff changeset
101 def connected(self):
8a270f32de81 server (session): new "connected" property, which is True when a user is logged
Goffi <goffi@goffi.org>
parents: 1093
diff changeset
102 return self.profile is not None
8a270f32de81 server (session): new "connected" property, which is True when a user is logged
Goffi <goffi@goffi.org>
parents: 1093
diff changeset
103
1101
9f7a628ce893 server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents: 1094
diff changeset
104 @property
9f7a628ce893 server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents: 1094
diff changeset
105 def guest(self):
9f7a628ce893 server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents: 1094
diff changeset
106 """True if this is a guest session"""
9f7a628ce893 server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents: 1094
diff changeset
107 if self.profile is None:
9f7a628ce893 server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents: 1094
diff changeset
108 return False
9f7a628ce893 server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents: 1094
diff changeset
109 else:
1113
cdd389ef97bc server: code style reformatting using black
Goffi <goffi@goffi.org>
parents: 1101
diff changeset
110 return self.profile.startswith("guest@@")
1101
9f7a628ce893 server (session): new "guest" property, True when connected user is a guest
Goffi <goffi@goffi.org>
parents: 1094
diff changeset
111
1504
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
112 @classmethod
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
113 def send(cls, profile: str, data_type: str, data: dict) -> None:
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
114 """Send a message to all session
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
115
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
116 If the session doesn't have an active websocket, the message is buffered until a
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
117 socket is available
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
118 """
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
119 for session in cls.profiles_map.get(profile, []):
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
120 if session.ws_socket is None or not session.ws_socket.init_ok:
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
121 session.ws_buffer.append({"data_type": data_type, "data": data})
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
122 else:
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
123 session.ws_socket.send(data_type, data)
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
124
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
125 def on_expire(self) -> None:
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
126 profile = self._profile or C.SERVICE_PROFILE
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
127 try:
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
128 self.profiles_map[profile].remove(self)
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
129 except (ValueError, KeyError):
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
130 log.warning(f"session was not registered for profile {profile}")
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
131 else:
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
132 nb_session = len(self.get_profile_sessions(profile))
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
133 log.debug(
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
134 f"Session for profile {profile} expired. {profile} has now {nb_session} "
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
135 f"session(s) active."
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
136 )
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
137
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
138 @classmethod
1506
ce879da7fcf7 server: fix `on_signal` callback
Goffi <goffi@goffi.org>
parents: 1504
diff changeset
139 def get_profile_sessions(cls, profile: str) -> List["WebSession"]:
1504
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
140 return cls.profiles_map.get(profile, [])
409d10211b20 server, browser: dynamic pages refactoring:
Goffi <goffi@goffi.org>
parents: 1396
diff changeset
141
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
142 def get_page_data(self, page, key):
960
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
143 """get session data for a page
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
144
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
145 @param page(LiberviaPage): instance of the page
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
146 @param key(object): data key
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
147 return (None, object): value of the key
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
148 None if not found or page_data doesn't exist
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
149 """
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
150 return self.pages_data.get(page, {}).get(key)
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
151
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
152 def pop_page_data(self, page, key, default=None):
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
153 """like get_page_data, but remove key once value is gotten
960
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
154
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
155 @param page(LiberviaPage): instance of the page
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
156 @param key(object): data key
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
157 @param default(object): value to return if key is not found
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
158 @return (object): found value or default
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
159 """
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
160 page_data = self.pages_data.get(page)
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
161 if page_data is None:
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
162 return default
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
163 value = page_data.pop(key, default)
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
164 if not page_data:
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
165 # no need to keep unused page_data
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
166 del self.pages_data[page]
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
167 return value
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
168
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
169 def set_page_data(self, page, key, value):
960
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
170 """set data to persist on reload
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
171
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
172 @param page(LiberviaPage): instance of the page
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
173 @param key(object): data key
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
174 @param value(object): value to set
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
175 @return (object): set value
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
176 """
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
177 page_data = self.pages_data.setdefault(page, {})
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
178 page_data[key] = value
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
179 return value
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
180
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
181 def set_page_flag(self, page, flag):
960
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
182 """set a flag for this page
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
183
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
184 @param page(LiberviaPage): instance of the page
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
185 @param flag(unicode): flag to set
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
186 """
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
187 flags = self.get_page_data(page, FLAGS_KEY)
960
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
188 if flags is None:
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
189 flags = self.set_page_data(page, FLAGS_KEY, set())
960
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
190 flags.add(flag)
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
191
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
192 def pop_page_flag(self, page, flag):
960
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
193 """return True if flag is set
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
194
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
195 flag is removed if it was set
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
196 @param page(LiberviaPage): instance of the page
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
197 @param flag(unicode): flag to set
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
198 @return (bool): True if flaag was set
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
199 """
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
200 page_data = self.pages_data.get(page, {})
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
201 flags = page_data.get(FLAGS_KEY)
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
202 if flags is None:
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
203 return False
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
204 if flag in flags:
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
205 flags.remove(flag)
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
206 # we remove data if they are not used anymore
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
207 if not flags:
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
208 del page_data[FLAGS_KEY]
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
209 if not page_data:
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
210 del self.pages_data[page]
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
211 return True
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
212 else:
e59edcae4c18 pages(session): added method to handle reload resistant page specific data:
Goffi <goffi@goffi.org>
parents: 957
diff changeset
213 return False
919
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
214
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
215 def set_page_notification(self, page, message, level=C.LVL_INFO):
1186
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
216 """set a flag for this page
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
217
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
218 @param page(LiberviaPage): instance of the page
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
219 @param flag(unicode): flag to set
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
220 """
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
221 notif = Notification(message, level)
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
222 notifs = self.get_page_data(page, NOTIFICATIONS_KEY)
1186
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
223 if notifs is None:
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
224 notifs = self.set_page_data(page, NOTIFICATIONS_KEY, [])
1186
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
225 notifs.append(notif)
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
226
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
227 def pop_page_notifications(self, page):
1186
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
228 """Return and remove last page notification
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
229
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
230 @param page(LiberviaPage): instance of the page
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
231 @return (list[Notification]): notifications if any
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
232 """
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
233 page_data = self.pages_data.get(page, {})
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
234 notifs = page_data.get(NOTIFICATIONS_KEY)
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
235 if not notifs:
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
236 return []
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
237 ret = notifs[:]
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
238 del notifs[:]
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
239 return ret
352865f4a268 server: added a generic way to have notification messages in pages
Goffi <goffi@goffi.org>
parents: 1165
diff changeset
240
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
241 def get_affiliation(self, service, node):
1093
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
242 """retrieve affiliation for a pubsub node
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
243
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
244 @param service(jid.JID): pubsub service
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
245 @param node(unicode): pubsub node
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
246 @return (unicode, None): affiliation, or None if it is not in cache
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
247 """
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
248 if service.resource:
1216
b2d067339de3 python 3 port:
Goffi <goffi@goffi.org>
parents: 1186
diff changeset
249 raise ValueError("Service must not have a resource")
1093
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
250 if not node:
1216
b2d067339de3 python 3 port:
Goffi <goffi@goffi.org>
parents: 1186
diff changeset
251 raise ValueError("node must be set")
1093
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
252 try:
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
253 affiliation = self.affiliations.pop((service, node))
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
254 except KeyError:
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
255 return None
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
256 else:
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
257 # we replace at the top to get the most recently used on top
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
258 # so less recently used will be removed if cache is full
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
259 self.affiliations[(service, node)] = affiliation
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
260 return affiliation
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
261
1509
106bae41f5c8 massive refactoring from camelCase -> snake_case. See backend commit log for more details
Goffi <goffi@goffi.org>
parents: 1506
diff changeset
262 def set_affiliation(self, service, node, affiliation):
1093
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
263 """cache affiliation for a node
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
264
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
265 will empty cache when it become too big
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
266 @param service(jid.JID): pubsub service
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
267 @param node(unicode): pubsub node
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
268 @param affiliation(unicode): affiliation to this node
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
269 """
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
270 if service.resource:
1216
b2d067339de3 python 3 port:
Goffi <goffi@goffi.org>
parents: 1186
diff changeset
271 raise ValueError("Service must not have a resource")
1093
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
272 if not node:
1216
b2d067339de3 python 3 port:
Goffi <goffi@goffi.org>
parents: 1186
diff changeset
273 raise ValueError("node must be set")
1093
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
274 self.affiliations[(service, node)] = affiliation
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
275 while len(self.affiliations) > MAX_CACHE_AFFILIATIONS:
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
276 self.affiliations.popitem(last=False)
eda7a1c6532a server: new getAffiliation method:
Goffi <goffi@goffi.org>
parents: 1090
diff changeset
277
919
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
278
1518
eb00d593801d refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents: 1509
diff changeset
279 class IWebGuestSession(Interface):
919
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
280 id = Attribute("UUID of the guest")
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
281 data = Attribute("data associated with the guest")
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
282
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
283
1518
eb00d593801d refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents: 1509
diff changeset
284 @implementer(IWebGuestSession)
eb00d593801d refactoring: rename `libervia` to `libervia.web` + update imports following backend changes
Goffi <goffi@goffi.org>
parents: 1509
diff changeset
285 class WebGuestSession(object):
919
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
286
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
287 def __init__(self, session):
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
288 self.id = None
7b267496da1d server: moved session interfaces to session_iface module + added SATGuestSession
Goffi <goffi@goffi.org>
parents:
diff changeset
289 self.data = None