summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--changelog.d/4642.feature1
-rw-r--r--changelog.d/4652.feature1
-rw-r--r--changelog.d/4666.feature2
-rw-r--r--changelog.d/4670.feature1
-rw-r--r--changelog.d/4674.feature1
-rw-r--r--docs/workers.rst3
-rw-r--r--synapse/app/client_reader.py2
-rw-r--r--synapse/config/tls.py15
-rw-r--r--synapse/crypto/context_factory.py14
-rw-r--r--synapse/handlers/acme.py9
-rw-r--r--synapse/handlers/room.py22
-rw-r--r--synapse/storage/registration.py82
12 files changed, 98 insertions, 55 deletions
diff --git a/changelog.d/4642.feature b/changelog.d/4642.feature
new file mode 100644
index 0000000000..bfbf95bcbb
--- /dev/null
+++ b/changelog.d/4642.feature
@@ -0,0 +1 @@
+Transfer bans on room upgrade.
\ No newline at end of file
diff --git a/changelog.d/4652.feature b/changelog.d/4652.feature
new file mode 100644
index 0000000000..ebe6880b21
--- /dev/null
+++ b/changelog.d/4652.feature
@@ -0,0 +1 @@
+Support .well-known delegation when issuing certificates through ACME.
diff --git a/changelog.d/4666.feature b/changelog.d/4666.feature
index 421060f9f9..b3a3915eb0 100644
--- a/changelog.d/4666.feature
+++ b/changelog.d/4666.feature
@@ -1 +1 @@
-Allow registration to be handled by a worker instance.
+Allow registration and login to be handled by a worker instance.
diff --git a/changelog.d/4670.feature b/changelog.d/4670.feature
new file mode 100644
index 0000000000..b3a3915eb0
--- /dev/null
+++ b/changelog.d/4670.feature
@@ -0,0 +1 @@
+Allow registration and login to be handled by a worker instance.
diff --git a/changelog.d/4674.feature b/changelog.d/4674.feature
new file mode 100644
index 0000000000..84630bb201
--- /dev/null
+++ b/changelog.d/4674.feature
@@ -0,0 +1 @@
+Reduce the overhead of creating outbound federation connections over TLS by caching the TLS client options.
diff --git a/docs/workers.rst b/docs/workers.rst
index 6ce7d88c11..3ba5879f76 100644
--- a/docs/workers.rst
+++ b/docs/workers.rst
@@ -222,11 +222,12 @@ following regular expressions::
     ^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/context/.*$
     ^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/members$
     ^/_matrix/client/(api/v1|r0|unstable)/rooms/.*/state$
+    ^/_matrix/client/(api/v1|r0|unstable)/login$
 
 Additionally, the following REST endpoints can be handled, but all requests must
 be routed to the same instance::
 
-    ^/_matrix/client/(api/v1|r0|unstable)/register$
+    ^/_matrix/client/(r0|unstable)/register$
 
 
 ``synapse.app.user_dir``
diff --git a/synapse/app/client_reader.py b/synapse/app/client_reader.py
index 9250b6c239..043b48f8f3 100644
--- a/synapse/app/client_reader.py
+++ b/synapse/app/client_reader.py
@@ -40,6 +40,7 @@ from synapse.replication.slave.storage.registration import SlavedRegistrationSto
 from synapse.replication.slave.storage.room import RoomStore
 from synapse.replication.slave.storage.transactions import SlavedTransactionStore
 from synapse.replication.tcp.client import ReplicationClientHandler
+from synapse.rest.client.v1.login import LoginRestServlet
 from synapse.rest.client.v1.room import (
     JoinedRoomMemberListRestServlet,
     PublicRoomListRestServlet,
@@ -94,6 +95,7 @@ class ClientReaderServer(HomeServer):
                     RoomStateRestServlet(self).register(resource)
                     RoomEventContextServlet(self).register(resource)
                     RegisterRestServlet(self).register(resource)
+                    LoginRestServlet(self).register(resource)
 
                     resources.update({
                         "/_matrix/client/r0": resource,
diff --git a/synapse/config/tls.py b/synapse/config/tls.py
index 5fb3486db1..38425bb056 100644
--- a/synapse/config/tls.py
+++ b/synapse/config/tls.py
@@ -42,6 +42,7 @@ class TlsConfig(Config):
         self.acme_port = acme_config.get("port", 80)
         self.acme_bind_addresses = acme_config.get("bind_addresses", ['::', '0.0.0.0'])
         self.acme_reprovision_threshold = acme_config.get("reprovision_threshold", 30)
+        self.acme_domain = acme_config.get("domain", config.get("server_name"))
 
         self.tls_certificate_file = self.abspath(config.get("tls_certificate_path"))
         self.tls_private_key_file = self.abspath(config.get("tls_private_key_path"))
@@ -229,6 +230,20 @@ class TlsConfig(Config):
             #
             # reprovision_threshold: 30
 
+            # The domain that the certificate should be for. Normally this
+            # should be the same as your Matrix domain (i.e., 'server_name'), but,
+            # by putting a file at 'https://<server_name>/.well-known/matrix/server',
+            # you can delegate incoming traffic to another server. If you do that,
+            # you should give the target of the delegation here.
+            #
+            # For example: if your 'server_name' is 'example.com', but
+            # 'https://example.com/.well-known/matrix/server' delegates to
+            # 'matrix.example.com', you should put 'matrix.example.com' here.
+            #
+            # If not set, defaults to your 'server_name'.
+            #
+            # domain: matrix.example.com
+
         # List of allowed TLS fingerprints for this server to publish along
         # with the signing keys for this server. Other matrix servers that
         # make HTTPS requests to this server will check that the TLS
diff --git a/synapse/crypto/context_factory.py b/synapse/crypto/context_factory.py
index 85f2848fb1..49cbc7098f 100644
--- a/synapse/crypto/context_factory.py
+++ b/synapse/crypto/context_factory.py
@@ -1,4 +1,5 @@
 # Copyright 2014-2016 OpenMarket Ltd
+# Copyright 2019 New Vector Ltd
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -11,6 +12,7 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+
 import logging
 
 from zope.interface import implementer
@@ -105,9 +107,7 @@ class ClientTLSOptions(object):
             self._hostnameBytes = _idnaBytes(hostname)
             self._sendSNI = True
 
-        ctx.set_info_callback(
-            _tolerateErrors(self._identityVerifyingInfoCallback)
-        )
+        ctx.set_info_callback(_tolerateErrors(self._identityVerifyingInfoCallback))
 
     def clientConnectionForTLS(self, tlsProtocol):
         context = self._ctx
@@ -128,10 +128,8 @@ class ClientTLSOptionsFactory(object):
 
     def __init__(self, config):
         # We don't use config options yet
-        pass
+        self._options = CertificateOptions(verify=False)
 
     def get_options(self, host):
-        return ClientTLSOptions(
-            host,
-            CertificateOptions(verify=False).getContext()
-        )
+        # Use _makeContext so that we get a fresh OpenSSL CTX each time.
+        return ClientTLSOptions(host, self._options._makeContext())
diff --git a/synapse/handlers/acme.py b/synapse/handlers/acme.py
index dd0b217965..813777bf18 100644
--- a/synapse/handlers/acme.py
+++ b/synapse/handlers/acme.py
@@ -56,6 +56,7 @@ class AcmeHandler(object):
     def __init__(self, hs):
         self.hs = hs
         self.reactor = hs.get_reactor()
+        self._acme_domain = hs.config.acme_domain
 
     @defer.inlineCallbacks
     def start_listening(self):
@@ -123,15 +124,15 @@ class AcmeHandler(object):
     @defer.inlineCallbacks
     def provision_certificate(self):
 
-        logger.warning("Reprovisioning %s", self.hs.hostname)
+        logger.warning("Reprovisioning %s", self._acme_domain)
 
         try:
-            yield self._issuer.issue_cert(self.hs.hostname)
+            yield self._issuer.issue_cert(self._acme_domain)
         except Exception:
             logger.exception("Fail!")
             raise
-        logger.warning("Reprovisioned %s, saving.", self.hs.hostname)
-        cert_chain = self._store.certs[self.hs.hostname]
+        logger.warning("Reprovisioned %s, saving.", self._acme_domain)
+        cert_chain = self._store.certs[self._acme_domain]
 
         try:
             with open(self.hs.config.tls_private_key_file, "wb") as private_key_file:
diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py
index f9af1f0046..67b15697fd 100644
--- a/synapse/handlers/room.py
+++ b/synapse/handlers/room.py
@@ -311,6 +311,28 @@ class RoomCreationHandler(BaseHandler):
             creation_content=creation_content,
         )
 
+        # Transfer membership events
+        old_room_member_state_ids = yield self.store.get_filtered_current_state_ids(
+            old_room_id, StateFilter.from_types([(EventTypes.Member, None)]),
+        )
+
+        # map from event_id to BaseEvent
+        old_room_member_state_events = yield self.store.get_events(
+            old_room_member_state_ids.values(),
+        )
+        for k, old_event in iteritems(old_room_member_state_events):
+            # Only transfer ban events
+            if ("membership" in old_event.content and
+                    old_event.content["membership"] == "ban"):
+                yield self.room_member_handler.update_membership(
+                    requester,
+                    UserID.from_string(old_event['state_key']),
+                    new_room_id,
+                    "ban",
+                    ratelimit=False,
+                    content=old_event.content,
+                )
+
         # XXX invites/joins
         # XXX 3pid invites
 
diff --git a/synapse/storage/registration.py b/synapse/storage/registration.py
index 3bc5def48e..9b9572890b 100644
--- a/synapse/storage/registration.py
+++ b/synapse/storage/registration.py
@@ -254,6 +254,47 @@ class RegistrationWorkerStore(SQLBaseStore):
             defer.returnValue(ret["guest_access_token"])
         defer.returnValue(None)
 
+    @defer.inlineCallbacks
+    def get_user_id_by_threepid(self, medium, address):
+        """Returns user id from threepid
+
+        Args:
+            medium (str): threepid medium e.g. email
+            address (str): threepid address e.g. me@example.com
+
+        Returns:
+            Deferred[str|None]: user id or None if no user id/threepid mapping exists
+        """
+        user_id = yield self.runInteraction(
+            "get_user_id_by_threepid", self.get_user_id_by_threepid_txn,
+            medium, address
+        )
+        defer.returnValue(user_id)
+
+    def get_user_id_by_threepid_txn(self, txn, medium, address):
+        """Returns user id from threepid
+
+        Args:
+            txn (cursor):
+            medium (str): threepid medium e.g. email
+            address (str): threepid address e.g. me@example.com
+
+        Returns:
+            str|None: user id or None if no user id/threepid mapping exists
+        """
+        ret = self._simple_select_one_txn(
+            txn,
+            "user_threepids",
+            {
+                "medium": medium,
+                "address": address
+            },
+            ['user_id'], True
+        )
+        if ret:
+            return ret['user_id']
+        return None
+
 
 class RegistrationStore(RegistrationWorkerStore,
                         background_updates.BackgroundUpdateStore):
@@ -613,47 +654,6 @@ class RegistrationStore(RegistrationWorkerStore,
         )
         defer.returnValue(ret)
 
-    @defer.inlineCallbacks
-    def get_user_id_by_threepid(self, medium, address):
-        """Returns user id from threepid
-
-        Args:
-            medium (str): threepid medium e.g. email
-            address (str): threepid address e.g. me@example.com
-
-        Returns:
-            Deferred[str|None]: user id or None if no user id/threepid mapping exists
-        """
-        user_id = yield self.runInteraction(
-            "get_user_id_by_threepid", self.get_user_id_by_threepid_txn,
-            medium, address
-        )
-        defer.returnValue(user_id)
-
-    def get_user_id_by_threepid_txn(self, txn, medium, address):
-        """Returns user id from threepid
-
-        Args:
-            txn (cursor):
-            medium (str): threepid medium e.g. email
-            address (str): threepid address e.g. me@example.com
-
-        Returns:
-            str|None: user id or None if no user id/threepid mapping exists
-        """
-        ret = self._simple_select_one_txn(
-            txn,
-            "user_threepids",
-            {
-                "medium": medium,
-                "address": address
-            },
-            ['user_id'], True
-        )
-        if ret:
-            return ret['user_id']
-        return None
-
     def user_delete_threepid(self, user_id, medium, address):
         return self._simple_delete(
             "user_threepids",