changeset 750:8ac862f6e5b3

browser and server sides: allow to connect with a JID that is not registered on the local server
author souliane <souliane@mailoo.org>
date Mon, 20 Jul 2015 10:16:10 +0200
parents 7168a9873dde
children 2ddd85551612
files src/browser/sat_browser/register.py src/server/server.py
diffstat 2 files changed, 34 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/browser/sat_browser/register.py	Mon Nov 23 22:02:18 2015 +0100
+++ b/src/browser/sat_browser/register.py	Mon Jul 20 10:16:10 2015 +0200
@@ -171,8 +171,8 @@
         pass
 
     def onLogin(self, button):
-        if not re.match(r'^[a-z0-9_-]+$', self.login_box.getText(), re.IGNORECASE):
-            self.login_warning_msg.setText('Invalid login, valid characters are a-z A-Z 0-9 _ -')
+        if not re.match(r'^[a-z0-9_-]+(@[a-z0-9_-]+\.[a-z0-9_-]+)?$', self.login_box.getText(), re.IGNORECASE):
+            self.login_warning_msg.setHTML('Invalid login, valid characters<br>are a-z A-Z 0-9 _ - or a bare JID')
         else:
             self.submit_type.setValue('login')
             self.submit(None)
@@ -182,7 +182,7 @@
         self.register_login_box.setText(self.register_login_box.getText().lower())
         if not re.match(r'^[a-z0-9_-]+$', self.register_login_box.getText(), re.IGNORECASE):
             self.register_warning_msg.setHTML(_('Invalid login, valid characters<br>are a-z A-Z 0-9 _ -'))
-        elif not re.match(r'^.+@.+\..+', self.email_box.getText(), re.IGNORECASE):
+        elif not re.match(r'^[a-z0-9_-]+@[a-z0-9_-]+\.[a-z0-9_-]+$', self.email_box.getText(), re.IGNORECASE):
             self.register_warning_msg.setHTML(_('Invalid email address'))
         elif len(self.register_pass_box.getText()) < C.PASSWORD_MIN_LENGTH:
             self.register_warning_msg.setHTML(_('Your password must contain<br>at least %d characters.') % C.PASSWORD_MIN_LENGTH)
--- a/src/server/server.py	Mon Nov 23 22:02:18 2015 +0100
+++ b/src/server/server.py	Mon Jul 20 10:16:10 2015 +0200
@@ -25,7 +25,7 @@
 from twisted.web.util import Redirect, redirectTo
 from twisted.python.components import registerAdapter
 from twisted.python.failure import Failure
-from twisted.words.protocols.jabber.jid import JID
+from twisted.words.protocols.jabber import jid
 
 from txjsonrpc.web import jsonrpc
 from txjsonrpc import jsonrpclib
@@ -484,8 +484,8 @@
         sat_jid = sat_session.jid
         if not sat_jid:
             # we keep a session cache for jid to avoir jid spoofing
-            sat_jid = sat_session.jid = JID(self.sat_host.bridge.getParamA("JabberID", "Connection", profile_key=profile))
-        if JID(from_jid).userhost() != sat_jid.userhost() and JID(to_jid).userhost() != sat_jid.userhost():
+            sat_jid = sat_session.jid = jid.JID(self.sat_host.bridge.getParamA("JabberID", "Connection", profile_key=profile))
+        if jid.JID(from_jid).userhost() != sat_jid.userhost() and jid.JID(to_jid).userhost() != sat_jid.userhost():
             log.error(u"Trying to get history from a different jid (given (browser): {}, real (backend): {}), maybe a hack attempt ?".format(from_jid, sat_jid))
             return {}
         d = self.asyncBridgeCall("getHistory", from_jid, to_jid, size, between, search, profile)
@@ -526,7 +526,7 @@
         """Quit a Multi-User Chat room"""
         profile = ISATSession(self.session).profile
         try:
-            room_jid = JID(room_jid)
+            room_jid = jid.JID(room_jid)
         except:
             log.warning('Invalid room jid')
             return
@@ -785,43 +785,53 @@
                 value will be given by self._logged or auth_eb
         """
         try:
-            login_ = request.args['login'][0]
-            password_ = request.args['login_password'][0]
+            login = request.args['login'][0]
+            password = request.args['login_password'][0]
         except KeyError:
             return C.BAD_REQUEST
 
-        if login_.startswith('@'):
+        if login.startswith('@'):  # this is checked by javascript but also here for security reason
             raise Exception('No profile_key allowed')
 
-        profile_check = self.sat_host.bridge.getProfileName(login_)
-        if ((not profile_check or profile_check != login_) or
-            (not password_ and profile_check not in self.sat_host.empty_password_allowed_warning_dangerous_list)):
-            return C.PROFILE_AUTH_ERROR
-            # profiles with empty passwords are restricted to local frontends
+        try:
+            profile = self.sat_host.bridge.getProfileName(login)
+        except Exception as e:
+            try:  # try to connect using XMPP credentials instead of SàT profile credentials
+                jid.JID(login)
+            except (RuntimeError, jid.InvalidFormat, AttributeError):
+                return C.PROFILE_AUTH_ERROR
+            profile = login
+            connect_method = "asyncConnectWithXMPPCredentials"
+        else:
+            if profile != login:
+                return C.PROFILE_AUTH_ERROR
+            if not password and profile not in self.sat_host.empty_password_allowed_warning_dangerous_list:
+                return C.PROFILE_AUTH_ERROR  # profiles with empty passwords are restricted to local frontends
+            connect_method = "asyncConnect"
 
-        if self.waiting_profiles.getRequest(login_):
+        if self.waiting_profiles.getRequest(profile):
             return C.ALREADY_WAITING
 
         def auth_eb(failure):
             fault = failure.value.faultString
-            self.waiting_profiles.purgeRequest(login_)
-            if fault == 'PasswordError':
-                log.info(u"Profile %s doesn't exist or the submitted password is wrong" % login_)
+            self.waiting_profiles.purgeRequest(profile)
+            if fault in ('PasswordError', 'ProfileUnknownError'):
+                log.info(u"Profile %s doesn't exist or the submitted password is wrong" % profile)
                 request.write(C.PROFILE_AUTH_ERROR)
             elif fault == 'SASLAuthError':
-                log.info(u"The XMPP password of profile %s is wrong" % login_)
+                log.info(u"The XMPP password of profile %s is wrong" % profile)
                 request.write(C.XMPP_AUTH_ERROR)
             elif fault == 'NoReply':
                 log.info(_("Did not receive a reply (the timeout expired or the connection is broken)"))
                 request.write(C.NO_REPLY)
             else:
-                log.error(u'Unmanaged fault string %s in errback for the connection of profile %s' % (fault, login_))
+                log.error(u'Unmanaged fault string %s in errback for the connection of profile %s' % (fault, profile))
                 request.write(C.UNKNOWN_ERROR % fault)
             request.finish()
 
-        self.waiting_profiles.setRequest(request, login_)
-        d = self.asyncBridgeCall("asyncConnect", login_, password_)
-        d.addCallbacks(lambda connected: self._logged(login_, request) if connected else None, auth_eb)
+        self.waiting_profiles.setRequest(request, profile)
+        d = self.asyncBridgeCall(connect_method, profile, password)
+        d.addCallbacks(lambda connected: self._logged(profile, request) if connected else None, auth_eb)
 
         return server.NOT_DONE_YET