diff --git a/changelog.d/5516.feature b/changelog.d/5516.feature
new file mode 100644
index 0000000000..fdf91c35e4
--- /dev/null
+++ b/changelog.d/5516.feature
@@ -0,0 +1 @@
+Allow configuration of the path used for ACME account keys.
diff --git a/changelog.d/5521.feature b/changelog.d/5521.feature
new file mode 100644
index 0000000000..fdf91c35e4
--- /dev/null
+++ b/changelog.d/5521.feature
@@ -0,0 +1 @@
+Allow configuration of the path used for ACME account keys.
diff --git a/changelog.d/5521.misc b/changelog.d/5521.misc
deleted file mode 100644
index e3a14fdeaf..0000000000
--- a/changelog.d/5521.misc
+++ /dev/null
@@ -1 +0,0 @@
-Factor acme bits out to a separate file.
diff --git a/changelog.d/5522.feature b/changelog.d/5522.feature
new file mode 100644
index 0000000000..fdf91c35e4
--- /dev/null
+++ b/changelog.d/5522.feature
@@ -0,0 +1 @@
+Allow configuration of the path used for ACME account keys.
diff --git a/changelog.d/5522.misc b/changelog.d/5522.misc
deleted file mode 100644
index 17a7be5c99..0000000000
--- a/changelog.d/5522.misc
+++ /dev/null
@@ -1 +0,0 @@
-Pass config_dir_path and data_dir_path into Config.read_config.
diff --git a/changelog.d/5531.feature b/changelog.d/5531.feature
new file mode 100644
index 0000000000..5c6bab2c31
--- /dev/null
+++ b/changelog.d/5531.feature
@@ -0,0 +1 @@
+Add support for handling pagination APIs on client reader worker.
diff --git a/docs/sample_config.yaml b/docs/sample_config.yaml
index f4fd113211..92a23245ff 100644
--- a/docs/sample_config.yaml
+++ b/docs/sample_config.yaml
@@ -406,6 +406,13 @@ acme:
#
#domain: matrix.example.com
+ # file to use for the account key. This will be generated if it doesn't
+ # exist.
+ #
+ # If unspecified, we will use CONFDIR/client.key.
+ #
+ account_key_file: DATADIR/acme_account.key
+
# 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/config/_base.py b/synapse/config/_base.py
index 6baa315874..21d110c82d 100644
--- a/synapse/config/_base.py
+++ b/synapse/config/_base.py
@@ -414,9 +414,6 @@ class Config(object):
Returns: dict
"""
- # FIXME: get rid of this
- self.config_dir_path = config_dir_path
-
# first we read the config files into a dict
specified_config = {}
for config_file in config_files:
diff --git a/synapse/config/tls.py b/synapse/config/tls.py
index 28be4366d6..9a66e8cc4b 100644
--- a/synapse/config/tls.py
+++ b/synapse/config/tls.py
@@ -33,7 +33,7 @@ logger = logging.getLogger(__name__)
class TlsConfig(Config):
- def read_config(self, config, **kwargs):
+ def read_config(self, config, config_dir_path, **kwargs):
acme_config = config.get("acme", None)
if acme_config is None:
@@ -50,6 +50,10 @@ class TlsConfig(Config):
self.acme_reprovision_threshold = acme_config.get("reprovision_threshold", 30)
self.acme_domain = acme_config.get("domain", config.get("server_name"))
+ self.acme_account_key_file = self.abspath(
+ acme_config.get("account_key_file", config_dir_path + "/client.key")
+ )
+
self.tls_certificate_file = self.abspath(config.get("tls_certificate_path"))
self.tls_private_key_file = self.abspath(config.get("tls_private_key_path"))
@@ -213,11 +217,12 @@ class TlsConfig(Config):
if sha256_fingerprint not in sha256_fingerprints:
self.tls_fingerprints.append({"sha256": sha256_fingerprint})
- def default_config(self, config_dir_path, server_name, **kwargs):
+ def default_config(self, config_dir_path, server_name, data_dir_path, **kwargs):
base_key_name = os.path.join(config_dir_path, server_name)
tls_certificate_path = base_key_name + ".tls.crt"
tls_private_key_path = base_key_name + ".tls.key"
+ default_acme_account_file = os.path.join(data_dir_path, "acme_account.key")
# this is to avoid the max line length. Sorrynotsorry
proxypassline = (
@@ -343,6 +348,13 @@ class TlsConfig(Config):
#
#domain: matrix.example.com
+ # file to use for the account key. This will be generated if it doesn't
+ # exist.
+ #
+ # If unspecified, we will use CONFDIR/client.key.
+ #
+ account_key_file: %(default_acme_account_file)s
+
# 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/handlers/acme.py b/synapse/handlers/acme.py
index a760372203..fbef2f3d38 100644
--- a/synapse/handlers/acme.py
+++ b/synapse/handlers/acme.py
@@ -47,7 +47,7 @@ class AcmeHandler(object):
self._issuer = acme_issuing_service.create_issuing_service(
self.reactor,
acme_url=self.hs.config.acme_url,
- pem_path=self.hs.config.config_dir_path,
+ account_key_file=self.hs.config.acme_account_key_file,
well_known_resource=well_known,
)
diff --git a/synapse/handlers/acme_issuing_service.py b/synapse/handlers/acme_issuing_service.py
index 70e73d2be0..e1d4224e74 100644
--- a/synapse/handlers/acme_issuing_service.py
+++ b/synapse/handlers/acme_issuing_service.py
@@ -21,28 +21,34 @@ This file contains the unconditional imports on the acme and cryptography bits t
only need (and may only have available) if we are doing ACME, so is designed to be
imported conditionally.
"""
+import logging
import attr
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import serialization
+from josepy import JWKRSA
from josepy.jwa import RS256
from txacme.challenges import HTTP01Responder
from txacme.client import Client
-from txacme.endpoint import load_or_create_client_key
from txacme.interfaces import ICertificateStore
from txacme.service import AcmeIssuingService
+from txacme.util import generate_private_key
from zope.interface import implementer
from twisted.internet import defer
from twisted.python.filepath import FilePath
from twisted.python.url import URL
+logger = logging.getLogger(__name__)
-def create_issuing_service(reactor, acme_url, pem_path, well_known_resource):
+
+def create_issuing_service(reactor, acme_url, account_key_file, well_known_resource):
"""Create an ACME issuing service, and attach it to a web Resource
Args:
reactor: twisted reactor
acme_url (str): URL to use to request certificates
- pem_path (str): where to store the client key
+ account_key_file (str): where to store the account key
well_known_resource (twisted.web.IResource): web resource for .well-known.
we will attach a child resource for "acme-challenge".
@@ -61,7 +67,7 @@ def create_issuing_service(reactor, acme_url, pem_path, well_known_resource):
lambda: Client.from_url(
reactor=reactor,
url=URL.from_text(acme_url),
- key=load_or_create_client_key(FilePath(pem_path)),
+ key=load_or_create_client_key(account_key_file),
alg=RS256,
)
),
@@ -82,3 +88,30 @@ class ErsatzStore(object):
def store(self, server_name, pem_objects):
self.certs[server_name] = [o.as_bytes() for o in pem_objects]
return defer.succeed(None)
+
+
+def load_or_create_client_key(key_file):
+ """Load the ACME account key from a file, creating it if it does not exist.
+
+ Args:
+ key_file (str): name of the file to use as the account key
+ """
+ # this is based on txacme.endpoint.load_or_create_client_key, but doesn't
+ # hardcode the 'client.key' filename
+ acme_key_file = FilePath(key_file)
+ if acme_key_file.exists():
+ logger.info("Loading ACME account key from '%s'", acme_key_file)
+ key = serialization.load_pem_private_key(
+ acme_key_file.getContent(), password=None, backend=default_backend()
+ )
+ else:
+ logger.info("Saving new ACME account key to '%s'", acme_key_file)
+ key = generate_private_key("rsa")
+ acme_key_file.setContent(
+ key.private_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PrivateFormat.TraditionalOpenSSL,
+ encryption_algorithm=serialization.NoEncryption(),
+ )
+ )
+ return JWKRSA(key=key)
diff --git a/synapse/handlers/pagination.py b/synapse/handlers/pagination.py
index 062e026e5f..76ee97ddd3 100644
--- a/synapse/handlers/pagination.py
+++ b/synapse/handlers/pagination.py
@@ -180,9 +180,7 @@ class PaginationHandler(object):
room_token = pagin_config.from_token.room_key
else:
pagin_config.from_token = (
- yield self.hs.get_event_sources().get_current_token_for_room(
- room_id=room_id
- )
+ yield self.hs.get_event_sources().get_current_token_for_pagination()
)
room_token = pagin_config.from_token.room_key
diff --git a/synapse/streams/events.py b/synapse/streams/events.py
index 9b416f2f40..488c49747a 100644
--- a/synapse/streams/events.py
+++ b/synapse/streams/events.py
@@ -59,21 +59,25 @@ class EventSources(object):
defer.returnValue(token)
@defer.inlineCallbacks
- def get_current_token_for_room(self, room_id):
- push_rules_key, _ = self.store.get_push_rules_stream_token()
- to_device_key = self.store.get_to_device_stream_token()
- device_list_key = self.store.get_device_stream_token()
- groups_key = self.store.get_group_stream_token()
+ def get_current_token_for_pagination(self):
+ """Get the current token for a given room to be used to paginate
+ events.
+ The returned token does not have the current values for fields other
+ than `room`, since they are not used during pagination.
+
+ Retuns:
+ Deferred[StreamToken]
+ """
token = StreamToken(
- room_key=(yield self.sources["room"].get_current_key_for_room(room_id)),
- presence_key=(yield self.sources["presence"].get_current_key()),
- typing_key=(yield self.sources["typing"].get_current_key()),
- receipt_key=(yield self.sources["receipt"].get_current_key()),
- account_data_key=(yield self.sources["account_data"].get_current_key()),
- push_rules_key=push_rules_key,
- to_device_key=to_device_key,
- device_list_key=device_list_key,
- groups_key=groups_key,
+ room_key=(yield self.sources["room"].get_current_key()),
+ presence_key=0,
+ typing_key=0,
+ receipt_key=0,
+ account_data_key=0,
+ push_rules_key=0,
+ to_device_key=0,
+ device_list_key=0,
+ groups_key=0,
)
defer.returnValue(token)
|