Implement username availability checker
Outlined here: https://github.com/vector-im/riot-web/issues/3605#issuecomment-298679388 ```HTTP GET /_matrix/.../register/available { "username": "desiredlocalpart123" } ``` If available, the response looks like ```HTTP HTTP/1.1 200 OK { "available": true } ``` Otherwise, ```HTTP HTTP/1.1 429 { "errcode": "M_LIMIT_EXCEEDED", "error": "Too Many Requests", "retry_after_ms": 2000 } ``` or ```HTTP HTTP/1.1 400 { "errcode": "M_USER_IN_USE", "error": "User ID already taken." } ``` or ```HTTP HTTP/1.1 400 { "errcode": "M_INVALID_USERNAME", "error": "Some reason for username being invalid" } ```
This commit is contained in:
parent
82475a18d9
commit
34ed4f4206
|
@ -31,6 +31,7 @@ import logging
|
|||
import hmac
|
||||
from hashlib import sha1
|
||||
from synapse.util.async import run_on_reactor
|
||||
from synapse.util.ratelimitutils import FederationRateLimiter
|
||||
|
||||
|
||||
# We ought to be using hmac.compare_digest() but on older pythons it doesn't
|
||||
|
@ -115,6 +116,40 @@ class MsisdnRegisterRequestTokenRestServlet(RestServlet):
|
|||
defer.returnValue((200, ret))
|
||||
|
||||
|
||||
class UsernameAvailabilityRestServlet(RestServlet):
|
||||
PATTERNS = client_v2_patterns("/register/available")
|
||||
|
||||
def __init__(self, hs):
|
||||
"""
|
||||
Args:
|
||||
hs (synapse.server.HomeServer): server
|
||||
"""
|
||||
super(UsernameAvailabilityRestServlet, self).__init__()
|
||||
self.hs = hs
|
||||
self.registration_handler = hs.get_handlers().registration_handler
|
||||
self.ratelimiter = FederationRateLimiter(
|
||||
hs.get_clock(),
|
||||
window_size=2000, # Time window of 2s
|
||||
sleep_limit=1, # Artificially delay requests if rate > sleep_limit/window_size
|
||||
sleep_msec=1000, # Amount of artificial delay to apply
|
||||
reject_limit=1, # Error with 429 if more than reject_limit requests are queued
|
||||
concurrent_requests=1, # Allow 1 request at a time
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def on_GET(self, request):
|
||||
ip = self.hs.get_ip_from_request(request)
|
||||
with self.ratelimiter.ratelimit(ip) as wait_deferred:
|
||||
yield wait_deferred
|
||||
|
||||
body = parse_json_object_from_request(request)
|
||||
assert_params_in_request(body, ['username'])
|
||||
|
||||
yield self.registration_handler.check_username(body['username'])
|
||||
|
||||
defer.returnValue((200, {"available": True}))
|
||||
|
||||
|
||||
class RegisterRestServlet(RestServlet):
|
||||
PATTERNS = client_v2_patterns("/register$")
|
||||
|
||||
|
@ -555,4 +590,5 @@ class RegisterRestServlet(RestServlet):
|
|||
def register_servlets(hs, http_server):
|
||||
EmailRegisterRequestTokenRestServlet(hs).register(http_server)
|
||||
MsisdnRegisterRequestTokenRestServlet(hs).register(http_server)
|
||||
UsernameAvailabilityRestServlet(hs).register(http_server)
|
||||
RegisterRestServlet(hs).register(http_server)
|
||||
|
|
Loading…
Reference in New Issue