diff --git a/changelog.d/4163.bugfix b/changelog.d/4163.bugfix
new file mode 100644
index 0000000000..c7e0ee229d
--- /dev/null
+++ b/changelog.d/4163.bugfix
@@ -0,0 +1 @@
+Generating the user consent URI no longer fails on Python 3.
diff --git a/changelog.d/4164.bugfix b/changelog.d/4164.bugfix
new file mode 100644
index 0000000000..f70e0b2056
--- /dev/null
+++ b/changelog.d/4164.bugfix
@@ -0,0 +1 @@
+Fix noop checks when updating device keys, reducing spurious device list update notifications.
diff --git a/scripts-dev/federation_client.py b/scripts-dev/federation_client.py
index 2566ce7cef..e0287c8c6c 100755
--- a/scripts-dev/federation_client.py
+++ b/scripts-dev/federation_client.py
@@ -154,10 +154,15 @@ def request_json(method, origin_name, origin_key, destination, path, content):
s = requests.Session()
s.mount("matrix://", MatrixConnectionAdapter())
+ headers = {"Host": destination, "Authorization": authorization_headers[0]}
+
+ if method == "POST":
+ headers["Content-Type"] = "application/json"
+
result = s.request(
method=method,
url=dest,
- headers={"Host": destination, "Authorization": authorization_headers[0]},
+ headers=headers,
verify=False,
data=content,
)
@@ -203,7 +208,7 @@ def main():
parser.add_argument(
"-X",
"--method",
- help="HTTP method to use for the request. Defaults to GET if --data is"
+ help="HTTP method to use for the request. Defaults to GET if --body is"
"unspecified, POST if it is.",
)
diff --git a/synapse/http/servlet.py b/synapse/http/servlet.py
index a1e4b88e6d..528125e737 100644
--- a/synapse/http/servlet.py
+++ b/synapse/http/servlet.py
@@ -121,16 +121,15 @@ def parse_string(request, name, default=None, required=False,
Args:
request: the twisted HTTP request.
- name (bytes/unicode): the name of the query parameter.
- default (bytes/unicode|None): value to use if the parameter is absent,
+ name (bytes|unicode): the name of the query parameter.
+ default (bytes|unicode|None): value to use if the parameter is absent,
defaults to None. Must be bytes if encoding is None.
required (bool): whether to raise a 400 SynapseError if the
parameter is absent, defaults to False.
- allowed_values (list[bytes/unicode]): List of allowed values for the
+ allowed_values (list[bytes|unicode]): List of allowed values for the
string, or None if any value is allowed, defaults to None. Must be
the same type as name, if given.
- encoding: The encoding to decode the name to, and decode the string
- content with.
+ encoding (str|None): The encoding to decode the string content with.
Returns:
bytes/unicode|None: A string value or the default. Unicode if encoding
diff --git a/synapse/rest/consent/consent_resource.py b/synapse/rest/consent/consent_resource.py
index e0f7de5d5c..8009b7ff1c 100644
--- a/synapse/rest/consent/consent_resource.py
+++ b/synapse/rest/consent/consent_resource.py
@@ -160,7 +160,9 @@ class ConsentResource(Resource):
try:
self._render_template(
request, "%s.html" % (version,),
- user=username, userhmac=userhmac, version=version,
+ user=username,
+ userhmac=userhmac.decode('ascii'),
+ version=version,
has_consented=has_consented, public_version=public_version,
)
except TemplateNotFound:
diff --git a/synapse/storage/end_to_end_keys.py b/synapse/storage/end_to_end_keys.py
index 1f1721e820..2a0f6cfca9 100644
--- a/synapse/storage/end_to_end_keys.py
+++ b/synapse/storage/end_to_end_keys.py
@@ -40,7 +40,10 @@ class EndToEndKeyStore(SQLBaseStore):
allow_none=True,
)
- new_key_json = encode_canonical_json(device_keys)
+ # In py3 we need old_key_json to match new_key_json type. The DB
+ # returns unicode while encode_canonical_json returns bytes.
+ new_key_json = encode_canonical_json(device_keys).decode("utf-8")
+
if old_key_json == new_key_json:
return False
diff --git a/tests/storage/test_end_to_end_keys.py b/tests/storage/test_end_to_end_keys.py
index 8f0aaece40..b83f7336d3 100644
--- a/tests/storage/test_end_to_end_keys.py
+++ b/tests/storage/test_end_to_end_keys.py
@@ -45,6 +45,21 @@ class EndToEndKeyStoreTestCase(tests.unittest.TestCase):
self.assertDictContainsSubset({"keys": json, "device_display_name": None}, dev)
@defer.inlineCallbacks
+ def test_reupload_key(self):
+ now = 1470174257070
+ json = {"key": "value"}
+
+ yield self.store.store_device("user", "device", None)
+
+ changed = yield self.store.set_e2e_device_keys("user", "device", now, json)
+ self.assertTrue(changed)
+
+ # If we try to upload the same key then we should be told nothing
+ # changed
+ changed = yield self.store.set_e2e_device_keys("user", "device", now, json)
+ self.assertFalse(changed)
+
+ @defer.inlineCallbacks
def test_get_key_with_device_name(self):
now = 1470174257070
json = {"key": "value"}
|