comparison libervia/backend/stdui/ui_profile_manager.py @ 4071:4b842c1fb686

refactoring: renamed `sat` package to `libervia.backend`
author Goffi <goffi@goffi.org>
date Fri, 02 Jun 2023 11:49:51 +0200
parents sat/stdui/ui_profile_manager.py@524856bd7b19
children
comparison
equal deleted inserted replaced
4070:d10748475025 4071:4b842c1fb686
1 #!/usr/bin/env python3
2
3
4 # SAT standard user interface for managing contacts
5 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org)
6 # Copyright (C) 2013-2016 Adrien Cossa (souliane@mailoo.org)
7
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU Affero General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU Affero General Public License for more details.
17
18 # You should have received a copy of the GNU Affero General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
21 from libervia.backend.core.i18n import D_
22 from libervia.backend.core.constants import Const as C
23 from libervia.backend.core.log import getLogger
24 from libervia.backend.core import exceptions
25 from libervia.backend.tools import xml_tools
26 from libervia.backend.memory.memory import ProfileSessions
27 from twisted.internet import defer
28 from twisted.words.protocols.jabber import jid
29
30
31 log = getLogger(__name__)
32
33
34 class ProfileManager(object):
35 """Manage profiles."""
36
37 def __init__(self, host):
38 self.host = host
39 self.profile_ciphers = {}
40 self._sessions = ProfileSessions()
41 host.register_callback(
42 self._authenticate_profile, force_id=C.AUTHENTICATE_PROFILE_ID, with_data=True
43 )
44 host.register_callback(
45 self._change_xmpp_password, force_id=C.CHANGE_XMPP_PASSWD_ID, with_data=True
46 )
47 self.__new_xmpp_passwd_id = host.register_callback(
48 self._change_xmpp_password_cb, with_data=True
49 )
50
51 def _start_session_eb(self, fail, first, profile):
52 """Errback method for start_session during profile authentication
53
54 @param first(bool): if True, this is the first try and we have tryied empty password
55 in this case we ask for a password to the user.
56 @param profile(unicode, None): %(doc_profile)s
57 must only be used if first is True
58 """
59 if first:
60 # first call, we ask for the password
61 form_ui = xml_tools.XMLUI(
62 "form", title=D_("Profile password for {}").format(profile), submit_id=""
63 )
64 form_ui.addPassword("profile_password", value="")
65 d = xml_tools.deferred_ui(self.host, form_ui, chained=True)
66 d.addCallback(self._authenticate_profile, profile)
67 return {"xmlui": form_ui.toXml()}
68
69 assert profile is None
70
71 if fail.check(exceptions.PasswordError):
72 dialog = xml_tools.XMLUI("popup", title=D_("Connection error"))
73 dialog.addText(D_("The provided profile password doesn't match."))
74 else:
75 log.error("Unexpected exceptions: {}".format(fail))
76 dialog = xml_tools.XMLUI("popup", title=D_("Internal error"))
77 dialog.addText(D_("Internal error: {}".format(fail)))
78 return {"xmlui": dialog.toXml(), "validated": C.BOOL_FALSE}
79
80 def _authenticate_profile(self, data, profile):
81 if C.bool(data.get("cancelled", "false")):
82 return {}
83 if self.host.memory.is_session_started(profile):
84 return {"validated": C.BOOL_TRUE}
85 try:
86 password = data[xml_tools.form_escape("profile_password")]
87 except KeyError:
88 # first request, we try empty password
89 password = ""
90 first = True
91 eb_profile = profile
92 else:
93 first = False
94 eb_profile = None
95 d = self.host.memory.start_session(password, profile)
96 d.addCallback(lambda __: {"validated": C.BOOL_TRUE})
97 d.addErrback(self._start_session_eb, first, eb_profile)
98 return d
99
100 def _change_xmpp_password(self, data, profile):
101 session_data = self._sessions.profile_get_unique(profile)
102 if not session_data:
103 server = self.host.memory.param_get_a(
104 C.FORCE_SERVER_PARAM, "Connection", profile_key=profile
105 )
106 if not server:
107 server = jid.parse(
108 self.host.memory.param_get_a(
109 "JabberID", "Connection", profile_key=profile
110 )
111 )[1]
112 session_id, session_data = self._sessions.new_session(
113 {"count": 0, "server": server}, profile=profile
114 )
115 if (
116 session_data["count"] > 2
117 ): # 3 attempts with a new password after the initial try
118 self._sessions.profile_del_unique(profile)
119 _dialog = xml_tools.XMLUI("popup", title=D_("Connection error"))
120 _dialog.addText(
121 D_("Can't connect to %s. Please check your connection details.")
122 % session_data["server"]
123 )
124 return {"xmlui": _dialog.toXml()}
125 session_data["count"] += 1
126 counter = " (%d)" % session_data["count"] if session_data["count"] > 1 else ""
127 title = D_("XMPP password for %(profile)s%(counter)s") % {
128 "profile": profile,
129 "counter": counter,
130 }
131 form_ui = xml_tools.XMLUI(
132 "form", title=title, submit_id=self.__new_xmpp_passwd_id
133 )
134 form_ui.addText(
135 D_(
136 "Can't connect to %s. Please check your connection details or try with another password."
137 )
138 % session_data["server"]
139 )
140 form_ui.addPassword("xmpp_password", value="")
141 return {"xmlui": form_ui.toXml()}
142
143 def _change_xmpp_password_cb(self, data, profile):
144 xmpp_password = data[xml_tools.form_escape("xmpp_password")]
145 d = self.host.memory.param_set(
146 "Password", xmpp_password, "Connection", profile_key=profile
147 )
148 d.addCallback(lambda __: defer.ensureDeferred(self.host.connect(profile)))
149 d.addCallback(lambda __: {})
150 d.addErrback(lambda __: self._change_xmpp_password({}, profile))
151 return d