Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1157 from Rugvip/nolimit
Browse files Browse the repository at this point in the history
Remove rate limiting from app service senders and fix get_or_create_user requester
  • Loading branch information
erikjohnston authored Oct 11, 2016
2 parents a940618 + 7b5546d commit a2f2516
Show file tree
Hide file tree
Showing 14 changed files with 64 additions and 77 deletions.
7 changes: 3 additions & 4 deletions synapse/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ def get_user_by_req(self, request, allow_guest=False, rights="access"):

@defer.inlineCallbacks
def _get_appservice_user_id(self, request):
app_service = yield self.store.get_app_service_by_token(
app_service = self.store.get_app_service_by_token(
get_access_token_from_request(
request, self.TOKEN_NOT_FOUND_HTTP_STATUS
)
Expand Down Expand Up @@ -855,13 +855,12 @@ def _look_up_user_by_access_token(self, token):
}
defer.returnValue(user_info)

@defer.inlineCallbacks
def get_appservice_by_req(self, request):
try:
token = get_access_token_from_request(
request, self.TOKEN_NOT_FOUND_HTTP_STATUS
)
service = yield self.store.get_app_service_by_token(token)
service = self.store.get_app_service_by_token(token)
if not service:
logger.warn("Unrecognised appservice access token: %s" % (token,))
raise AuthError(
Expand All @@ -870,7 +869,7 @@ def get_appservice_by_req(self, request):
errcode=Codes.UNKNOWN_TOKEN
)
request.authenticated_entity = service.sender
defer.returnValue(service)
return defer.succeed(service)
except KeyError:
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS, "Missing access token."
Expand Down
8 changes: 7 additions & 1 deletion synapse/handlers/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,14 @@ def __init__(self, hs):

def ratelimit(self, requester):
time_now = self.clock.time()
user_id = requester.user.to_string()

app_service = self.store.get_app_service_by_user_id(user_id)
if app_service is not None:
return # do not ratelimit app service senders

allowed, time_allowed = self.ratelimiter.send_message(
requester.user.to_string(), time_now,
user_id, time_now,
msg_rate_hz=self.hs.config.rc_messages_per_second,
burst_count=self.hs.config.rc_message_burst_count,
)
Expand Down
20 changes: 9 additions & 11 deletions synapse/handlers/appservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def notify_interested_services(self, current_id):
Args:
current_id(int): The current maximum ID.
"""
services = yield self.store.get_app_services()
services = self.store.get_app_services()
if not services or not self.notify_appservices:
return

Expand Down Expand Up @@ -142,7 +142,7 @@ def query_room_alias_exists(self, room_alias):
association can be found.
"""
room_alias_str = room_alias.to_string()
services = yield self.store.get_app_services()
services = self.store.get_app_services()
alias_query_services = [
s for s in services if (
s.is_interested_in_alias(room_alias_str)
Expand Down Expand Up @@ -177,7 +177,7 @@ def query_3pe(self, kind, protocol, fields):

@defer.inlineCallbacks
def get_3pe_protocols(self, only_protocol=None):
services = yield self.store.get_app_services()
services = self.store.get_app_services()
protocols = {}

# Collect up all the individual protocol responses out of the ASes
Expand Down Expand Up @@ -224,31 +224,29 @@ def _get_services_for_event(self, event):
list<ApplicationService>: A list of services interested in this
event based on the service regex.
"""
services = yield self.store.get_app_services()
services = self.store.get_app_services()
interested_list = [
s for s in services if (
yield s.is_interested(event, self.store)
)
]
defer.returnValue(interested_list)

@defer.inlineCallbacks
def _get_services_for_user(self, user_id):
services = yield self.store.get_app_services()
services = self.store.get_app_services()
interested_list = [
s for s in services if (
s.is_interested_in_user(user_id)
)
]
defer.returnValue(interested_list)
return defer.succeed(interested_list)

@defer.inlineCallbacks
def _get_services_for_3pn(self, protocol):
services = yield self.store.get_app_services()
services = self.store.get_app_services()
interested_list = [
s for s in services if s.is_interested_in_protocol(protocol)
]
defer.returnValue(interested_list)
return defer.succeed(interested_list)

@defer.inlineCallbacks
def _is_unknown_user(self, user_id):
Expand All @@ -264,7 +262,7 @@ def _is_unknown_user(self, user_id):
return

# user not found; could be the AS though, so check.
services = yield self.store.get_app_services()
services = self.store.get_app_services()
service_list = [s for s in services if s.sender == user_id]
defer.returnValue(len(service_list) == 0)

Expand Down
11 changes: 4 additions & 7 deletions synapse/handlers/directory.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,28 +288,25 @@ def get_association_from_room_alias(self, room_alias):
result = yield as_handler.query_room_alias_exists(room_alias)
defer.returnValue(result)

@defer.inlineCallbacks
def can_modify_alias(self, alias, user_id=None):
# Any application service "interested" in an alias they are regexing on
# can modify the alias.
# Users can only modify the alias if ALL the interested services have
# non-exclusive locks on the alias (or there are no interested services)
services = yield self.store.get_app_services()
services = self.store.get_app_services()
interested_services = [
s for s in services if s.is_interested_in_alias(alias.to_string())
]

for service in interested_services:
if user_id == service.sender:
# this user IS the app service so they can do whatever they like
defer.returnValue(True)
return
return defer.succeed(True)
elif service.is_exclusive_alias(alias.to_string()):
# another service has an exclusive lock on this alias.
defer.returnValue(False)
return
return defer.succeed(False)
# either no interested services, or no service with an exclusive lock
defer.returnValue(True)
return defer.succeed(True)

@defer.inlineCallbacks
def _user_can_delete_alias(self, alias, user_id):
Expand Down
8 changes: 4 additions & 4 deletions synapse/handlers/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ def get_displayname(self, target_user):
defer.returnValue(result["displayname"])

@defer.inlineCallbacks
def set_displayname(self, target_user, requester, new_displayname):
def set_displayname(self, target_user, requester, new_displayname, by_admin=False):
"""target_user is the user whose displayname is to be changed;
auth_user is the user attempting to make this change."""
if not self.hs.is_mine(target_user):
raise SynapseError(400, "User is not hosted on this Home Server")

if target_user != requester.user:
if not by_admin and target_user != requester.user:
raise AuthError(400, "Cannot set another user's displayname")

if new_displayname == '':
Expand Down Expand Up @@ -111,13 +111,13 @@ def get_avatar_url(self, target_user):
defer.returnValue(result["avatar_url"])

@defer.inlineCallbacks
def set_avatar_url(self, target_user, requester, new_avatar_url):
def set_avatar_url(self, target_user, requester, new_avatar_url, by_admin=False):
"""target_user is the user whose avatar_url is to be changed;
auth_user is the user attempting to make this change."""
if not self.hs.is_mine(target_user):
raise SynapseError(400, "User is not hosted on this Home Server")

if target_user != requester.user:
if not by_admin and target_user != requester.user:
raise AuthError(400, "Cannot set another user's avatar_url")

yield self.store.set_profile_avatar_url(
Expand Down
11 changes: 4 additions & 7 deletions synapse/handlers/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

from twisted.internet import defer

import synapse.types
from synapse.api.errors import (
AuthError, Codes, SynapseError, RegistrationError, InvalidCaptchaError
)
Expand Down Expand Up @@ -194,7 +193,7 @@ def register(
def appservice_register(self, user_localpart, as_token):
user = UserID(user_localpart, self.hs.hostname)
user_id = user.to_string()
service = yield self.store.get_app_service_by_token(as_token)
service = self.store.get_app_service_by_token(as_token)
if not service:
raise AuthError(403, "Invalid application service token.")
if not service.is_interested_in_user(user_id):
Expand Down Expand Up @@ -305,11 +304,10 @@ def bind_emails(self, user_id, threepidCreds):
# XXX: This should be a deferred list, shouldn't it?
yield identity_handler.bind_threepid(c, user_id)

@defer.inlineCallbacks
def check_user_id_not_appservice_exclusive(self, user_id, allowed_appservice=None):
# valid user IDs must not clash with any user ID namespaces claimed by
# application services.
services = yield self.store.get_app_services()
services = self.store.get_app_services()
interested_services = [
s for s in services
if s.is_interested_in_user(user_id)
Expand Down Expand Up @@ -371,7 +369,7 @@ def _submit_captcha(self, ip_addr, private_key, challenge, response):
defer.returnValue(data)

@defer.inlineCallbacks
def get_or_create_user(self, localpart, displayname, duration_in_ms,
def get_or_create_user(self, requester, localpart, displayname, duration_in_ms,
password_hash=None):
"""Creates a new user if the user does not exist,
else revokes all previous access tokens and generates a new one.
Expand Down Expand Up @@ -418,9 +416,8 @@ def get_or_create_user(self, localpart, displayname, duration_in_ms,
if displayname is not None:
logger.info("setting user display name: %s -> %s", user_id, displayname)
profile_handler = self.hs.get_handlers().profile_handler
requester = synapse.types.create_requester(user)
yield profile_handler.set_displayname(
user, requester, displayname
user, requester, displayname, by_admin=True,
)

defer.returnValue((user_id, token))
Expand Down
2 changes: 1 addition & 1 deletion synapse/handlers/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ def get_new_events(
logger.warn("Stream has topological part!!!! %r", from_key)
from_key = "s%s" % (from_token.stream,)

app_service = yield self.store.get_app_service_by_user_id(
app_service = self.store.get_app_service_by_user_id(
user.to_string()
)
if app_service:
Expand Down
2 changes: 1 addition & 1 deletion synapse/handlers/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,7 @@ def _get_rooms_changed(self, sync_result_builder, ignored_users):

assert since_token

app_service = yield self.store.get_app_service_by_user_id(user_id)
app_service = self.store.get_app_service_by_user_id(user_id)
if app_service:
rooms = yield self.store.get_app_service_rooms(app_service)
joined_room_ids = set(r.room_id for r in rooms)
Expand Down
11 changes: 7 additions & 4 deletions synapse/rest/client/v1/register.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from .base import ClientV1RestServlet, client_path_patterns
import synapse.util.stringutils as stringutils
from synapse.http.servlet import parse_json_object_from_request
from synapse.types import create_requester

from synapse.util.async import run_on_reactor

Expand Down Expand Up @@ -391,23 +392,24 @@ def on_POST(self, request):
user_json = parse_json_object_from_request(request)

access_token = get_access_token_from_request(request)
app_service = yield self.store.get_app_service_by_token(
app_service = self.store.get_app_service_by_token(
access_token
)
if not app_service:
raise SynapseError(403, "Invalid application service token.")

logger.debug("creating user: %s", user_json)
requester = create_requester(app_service.sender)

response = yield self._do_create(user_json)
logger.debug("creating user: %s", user_json)
response = yield self._do_create(requester, user_json)

defer.returnValue((200, response))

def on_OPTIONS(self, request):
return 403, {}

@defer.inlineCallbacks
def _do_create(self, user_json):
def _do_create(self, requester, user_json):
yield run_on_reactor()

if "localpart" not in user_json:
Expand All @@ -433,6 +435,7 @@ def _do_create(self, user_json):

handler = self.handlers.registration_handler
user_id, token = yield handler.get_or_create_user(
requester=requester,
localpart=localpart,
displayname=displayname,
duration_in_ms=(duration_seconds * 1000),
Expand Down
12 changes: 6 additions & 6 deletions synapse/storage/appservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def __init__(self, hs):
)

def get_app_services(self):
return defer.succeed(self.services_cache)
return self.services_cache

def get_app_service_by_user_id(self, user_id):
"""Retrieve an application service from their user ID.
Expand All @@ -54,8 +54,8 @@ def get_app_service_by_user_id(self, user_id):
"""
for service in self.services_cache:
if service.sender == user_id:
return defer.succeed(service)
return defer.succeed(None)
return service
return None

def get_app_service_by_token(self, token):
"""Get the application service with the given appservice token.
Expand All @@ -67,8 +67,8 @@ def get_app_service_by_token(self, token):
"""
for service in self.services_cache:
if service.token == token:
return defer.succeed(service)
return defer.succeed(None)
return service
return None

def get_app_service_rooms(self, service):
"""Get a list of RoomsForUser for this application service.
Expand Down Expand Up @@ -163,7 +163,7 @@ def get_appservices_by_state(self, state):
["as_id"]
)
# NB: This assumes this class is linked with ApplicationServiceStore
as_list = yield self.get_app_services()
as_list = self.get_app_services()
services = []

for res in results:
Expand Down
8 changes: 5 additions & 3 deletions tests/handlers/test_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from .. import unittest

from synapse.handlers.register import RegistrationHandler
from synapse.types import UserID
from synapse.types import UserID, create_requester

from tests.utils import setup_test_homeserver

Expand Down Expand Up @@ -57,8 +57,9 @@ def test_user_is_created_and_logged_in_if_doesnt_exist(self):
local_part = "someone"
display_name = "someone"
user_id = "@someone:test"
requester = create_requester("@as:test")
result_user_id, result_token = yield self.handler.get_or_create_user(
local_part, display_name, duration_ms)
requester, local_part, display_name, duration_ms)
self.assertEquals(result_user_id, user_id)
self.assertEquals(result_token, 'secret')

Expand All @@ -74,7 +75,8 @@ def test_if_user_exists(self):
local_part = "frank"
display_name = "Frank"
user_id = "@frank:test"
requester = create_requester("@as:test")
result_user_id, result_token = yield self.handler.get_or_create_user(
local_part, display_name, duration_ms)
requester, local_part, display_name, duration_ms)
self.assertEquals(result_user_id, user_id)
self.assertEquals(result_token, 'secret')
Loading

0 comments on commit a2f2516

Please sign in to comment.