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
|
import hmac
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from synapse.util.async import run_on_reactor
|
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
|
# 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))
|
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):
|
class RegisterRestServlet(RestServlet):
|
||||||
PATTERNS = client_v2_patterns("/register$")
|
PATTERNS = client_v2_patterns("/register$")
|
||||||
|
|
||||||
|
@ -555,4 +590,5 @@ class RegisterRestServlet(RestServlet):
|
||||||
def register_servlets(hs, http_server):
|
def register_servlets(hs, http_server):
|
||||||
EmailRegisterRequestTokenRestServlet(hs).register(http_server)
|
EmailRegisterRequestTokenRestServlet(hs).register(http_server)
|
||||||
MsisdnRegisterRequestTokenRestServlet(hs).register(http_server)
|
MsisdnRegisterRequestTokenRestServlet(hs).register(http_server)
|
||||||
|
UsernameAvailabilityRestServlet(hs).register(http_server)
|
||||||
RegisterRestServlet(hs).register(http_server)
|
RegisterRestServlet(hs).register(http_server)
|
||||||
|
|
Loading…
Reference in New Issue