diff --git a/synapse/auth/macaroons.py b/synapse/auth/macaroons.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/synapse/auth/macaroons.py
diff --git a/synapse/config/registration.py b/synapse/config/registration.py
index 67e780864e..62de4b399f 100644
--- a/synapse/config/registration.py
+++ b/synapse/config/registration.py
@@ -32,9 +32,11 @@ class RegistrationConfig(Config):
)
self.registration_shared_secret = config.get("registration_shared_secret")
+ self.macaroon_secret_key = config.get("macaroon_secret_key")
def default_config(self, config_dir, server_name):
registration_shared_secret = random_string_with_symbols(50)
+ macaroon_secret_key = random_string_with_symbols(50)
return """\
## Registration ##
@@ -44,6 +46,8 @@ class RegistrationConfig(Config):
# If set, allows registration by anyone who also has the shared
# secret, even if registration is otherwise disabled.
registration_shared_secret: "%(registration_shared_secret)s"
+
+ macaroon_secret_key: "%(macaroon_secret_key)s"
""" % locals()
def add_arguments(self, parser):
diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py
index 39392d9fdd..86bacdda1d 100644
--- a/synapse/handlers/register.py
+++ b/synapse/handlers/register.py
@@ -25,9 +25,9 @@ import synapse.util.stringutils as stringutils
from synapse.util.async import run_on_reactor
from synapse.http.client import CaptchaServerHttpClient
-import base64
import bcrypt
import logging
+import pymacaroons
import urllib
logger = logging.getLogger(__name__)
@@ -274,11 +274,18 @@ class RegistrationHandler(BaseHandler):
)
def generate_token(self, user_id):
- # urlsafe variant uses _ and - so use . as the separator and replace
- # all =s with .s so http clients don't quote =s when it is used as
- # query params.
- return (base64.urlsafe_b64encode(user_id).replace('=', '.') + '.' +
- stringutils.random_string(18))
+ macaroon = pymacaroons.Macaroon(
+ location = self.hs.config.server_name,
+ identifier = "key",
+ key = self.hs.config.macaroon_secret_key)
+ macaroon.add_first_party_caveat("gen = 1")
+ macaroon.add_first_party_caveat("user_id = %s" % user_id)
+ macaroon.add_first_party_caveat("type = access")
+ now = self.hs.get_clock().time()
+ expiry = now + 60 * 60
+ macaroon.add_first_party_caveat("time < %s" % expiry)
+
+ return macaroon.serialize()
def _generate_user_id(self):
return "-" + stringutils.random_string(18)
diff --git a/synapse/python_dependencies.py b/synapse/python_dependencies.py
index 115bee8c41..b6e00c27b5 100644
--- a/synapse/python_dependencies.py
+++ b/synapse/python_dependencies.py
@@ -33,6 +33,7 @@ REQUIREMENTS = {
"ujson": ["ujson"],
"blist": ["blist"],
"pysaml2": ["saml2"],
+ "pymacaroons": ["pymacaroons"],
}
CONDITIONAL_REQUIREMENTS = {
"web_client": {
|