|
@@ -16,6 +16,7 @@
|
|
|
|
|
|
import hmac
|
|
|
import logging
|
|
|
+from typing import List, Union
|
|
|
|
|
|
from six import string_types
|
|
|
|
|
@@ -31,8 +32,11 @@ from synapse.api.errors import (
|
|
|
ThreepidValidationError,
|
|
|
UnrecognizedRequestError,
|
|
|
)
|
|
|
+from synapse.config.captcha import CaptchaConfig
|
|
|
+from synapse.config.consent_config import ConsentConfig
|
|
|
from synapse.config.emailconfig import ThreepidBehaviour
|
|
|
from synapse.config.ratelimiting import FederationRateLimitConfig
|
|
|
+from synapse.config.registration import RegistrationConfig
|
|
|
from synapse.config.server import is_threepid_reserved
|
|
|
from synapse.http.server import finish_request
|
|
|
from synapse.http.servlet import (
|
|
@@ -371,6 +375,8 @@ class RegisterRestServlet(RestServlet):
|
|
|
self.ratelimiter = hs.get_registration_ratelimiter()
|
|
|
self.clock = hs.get_clock()
|
|
|
|
|
|
+ self._registration_flows = _calculate_registration_flows(hs.config)
|
|
|
+
|
|
|
@interactive_auth_handler
|
|
|
@defer.inlineCallbacks
|
|
|
def on_POST(self, request):
|
|
@@ -491,69 +497,8 @@ class RegisterRestServlet(RestServlet):
|
|
|
assigned_user_id=registered_user_id,
|
|
|
)
|
|
|
|
|
|
- # FIXME: need a better error than "no auth flow found" for scenarios
|
|
|
- # where we required 3PID for registration but the user didn't give one
|
|
|
- require_email = "email" in self.hs.config.registrations_require_3pid
|
|
|
- require_msisdn = "msisdn" in self.hs.config.registrations_require_3pid
|
|
|
-
|
|
|
- show_msisdn = True
|
|
|
- if self.hs.config.disable_msisdn_registration:
|
|
|
- show_msisdn = False
|
|
|
- require_msisdn = False
|
|
|
-
|
|
|
- flows = []
|
|
|
- if self.hs.config.enable_registration_captcha:
|
|
|
- # only support 3PIDless registration if no 3PIDs are required
|
|
|
- if not require_email and not require_msisdn:
|
|
|
- # Also add a dummy flow here, otherwise if a client completes
|
|
|
- # recaptcha first we'll assume they were going for this flow
|
|
|
- # and complete the request, when they could have been trying to
|
|
|
- # complete one of the flows with email/msisdn auth.
|
|
|
- flows.extend([[LoginType.RECAPTCHA, LoginType.DUMMY]])
|
|
|
- # only support the email-only flow if we don't require MSISDN 3PIDs
|
|
|
- if not require_msisdn:
|
|
|
- flows.extend([[LoginType.RECAPTCHA, LoginType.EMAIL_IDENTITY]])
|
|
|
-
|
|
|
- if show_msisdn:
|
|
|
- # only support the MSISDN-only flow if we don't require email 3PIDs
|
|
|
- if not require_email:
|
|
|
- flows.extend([[LoginType.RECAPTCHA, LoginType.MSISDN]])
|
|
|
- # always let users provide both MSISDN & email
|
|
|
- flows.extend(
|
|
|
- [[LoginType.RECAPTCHA, LoginType.MSISDN, LoginType.EMAIL_IDENTITY]]
|
|
|
- )
|
|
|
- else:
|
|
|
- # only support 3PIDless registration if no 3PIDs are required
|
|
|
- if not require_email and not require_msisdn:
|
|
|
- flows.extend([[LoginType.DUMMY]])
|
|
|
- # only support the email-only flow if we don't require MSISDN 3PIDs
|
|
|
- if not require_msisdn:
|
|
|
- flows.extend([[LoginType.EMAIL_IDENTITY]])
|
|
|
-
|
|
|
- if show_msisdn:
|
|
|
- # only support the MSISDN-only flow if we don't require email 3PIDs
|
|
|
- if not require_email or require_msisdn:
|
|
|
- flows.extend([[LoginType.MSISDN]])
|
|
|
- # always let users provide both MSISDN & email
|
|
|
- flows.extend([[LoginType.MSISDN, LoginType.EMAIL_IDENTITY]])
|
|
|
-
|
|
|
- # Append m.login.terms to all flows if we're requiring consent
|
|
|
- if self.hs.config.user_consent_at_registration:
|
|
|
- new_flows = []
|
|
|
- for flow in flows:
|
|
|
- inserted = False
|
|
|
- # m.login.terms should go near the end but before msisdn or email auth
|
|
|
- for i, stage in enumerate(flow):
|
|
|
- if stage == LoginType.EMAIL_IDENTITY or stage == LoginType.MSISDN:
|
|
|
- flow.insert(i, LoginType.TERMS)
|
|
|
- inserted = True
|
|
|
- break
|
|
|
- if not inserted:
|
|
|
- flow.append(LoginType.TERMS)
|
|
|
- flows.extend(new_flows)
|
|
|
-
|
|
|
auth_result, params, session_id = yield self.auth_handler.check_auth(
|
|
|
- flows, body, self.hs.get_ip_from_request(request)
|
|
|
+ self._registration_flows, body, self.hs.get_ip_from_request(request)
|
|
|
)
|
|
|
|
|
|
# Check that we're not trying to register a denied 3pid.
|
|
@@ -716,6 +661,61 @@ class RegisterRestServlet(RestServlet):
|
|
|
)
|
|
|
|
|
|
|
|
|
+def _calculate_registration_flows(
|
|
|
+ # technically `config` has to provide *all* of these interfaces, not just one
|
|
|
+ config: Union[RegistrationConfig, ConsentConfig, CaptchaConfig],
|
|
|
+) -> List[List[str]]:
|
|
|
+ """Get a suitable flows list for registration
|
|
|
+
|
|
|
+ Args:
|
|
|
+ config: server configuration
|
|
|
+
|
|
|
+ Returns: a list of supported flows
|
|
|
+ """
|
|
|
+ # FIXME: need a better error than "no auth flow found" for scenarios
|
|
|
+ # where we required 3PID for registration but the user didn't give one
|
|
|
+ require_email = "email" in config.registrations_require_3pid
|
|
|
+ require_msisdn = "msisdn" in config.registrations_require_3pid
|
|
|
+
|
|
|
+ show_msisdn = True
|
|
|
+ if config.disable_msisdn_registration:
|
|
|
+ show_msisdn = False
|
|
|
+ require_msisdn = False
|
|
|
+
|
|
|
+ flows = []
|
|
|
+
|
|
|
+ # only support 3PIDless registration if no 3PIDs are required
|
|
|
+ if not require_email and not require_msisdn:
|
|
|
+ # Add a dummy step here, otherwise if a client completes
|
|
|
+ # recaptcha first we'll assume they were going for this flow
|
|
|
+ # and complete the request, when they could have been trying to
|
|
|
+ # complete one of the flows with email/msisdn auth.
|
|
|
+ flows.append([LoginType.DUMMY])
|
|
|
+
|
|
|
+ # only support the email-only flow if we don't require MSISDN 3PIDs
|
|
|
+ if not require_msisdn:
|
|
|
+ flows.append([LoginType.EMAIL_IDENTITY])
|
|
|
+
|
|
|
+ # only support the MSISDN-only flow if we don't require email 3PIDs
|
|
|
+ if show_msisdn and not require_email:
|
|
|
+ flows.append([LoginType.MSISDN])
|
|
|
+
|
|
|
+ if show_msisdn:
|
|
|
+ flows.append([LoginType.MSISDN, LoginType.EMAIL_IDENTITY])
|
|
|
+
|
|
|
+ # Prepend m.login.terms to all flows if we're requiring consent
|
|
|
+ if config.user_consent_at_registration:
|
|
|
+ for flow in flows:
|
|
|
+ flow.insert(0, LoginType.TERMS)
|
|
|
+
|
|
|
+ # Prepend recaptcha to all flows if we're requiring captcha
|
|
|
+ if config.enable_registration_captcha:
|
|
|
+ for flow in flows:
|
|
|
+ flow.insert(0, LoginType.RECAPTCHA)
|
|
|
+
|
|
|
+ return flows
|
|
|
+
|
|
|
+
|
|
|
def register_servlets(hs, http_server):
|
|
|
EmailRegisterRequestTokenRestServlet(hs).register(http_server)
|
|
|
MsisdnRegisterRequestTokenRestServlet(hs).register(http_server)
|