From a5993abc0407c7df8fe405f81d76f76f37b34f91 Mon Sep 17 00:00:00 2001 From: anoa's Codex Agent Date: Wed, 4 Jun 2025 12:36:12 +0100 Subject: [PATCH 1/2] Create AGENTS.md A basic AGENTS.md to get us started --- AGENTS.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..9227acd97bb --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,14 @@ +# Contributor Guide + +Synapse is a Python application that has Rust modules via pyo3 for performance. + +## Dev Environment Tips +- Source code is primarily in `synapse/`, tests are in `tests/`. +- Run `poetry install --dev` to install development python dependencies. This will also build and install the Synapse rust code. +- Use `./scripts-dev/lint.sh` to lint the codebase (this attempts to fix issues as well). This should be run and produce no errors before every commit. + +## Testing Instructions +- Find the CI plan in the .github/workflows folder. +- Use `poetry run trial tests` to run all unit tests, or `poetry run trial tests.metrics.test_phone_home_stats.PhoneHomeStatsTestCase` (for example) to run a single test case. The commit should pass all tests before you merge. +- Some typing warnings are expected currently. Fix any test or type *errors* until the whole suite is green. +- Add or update relevant tests for the code you change, even if nobody asked. From 72f84a61ae7c379bee0df33f7f2f5391246c3651 Mon Sep 17 00:00:00 2001 From: anoa's Codex Agent Date: Wed, 4 Jun 2025 12:59:49 +0100 Subject: [PATCH 2/2] Disallow device key changes --- .../storage/databases/main/end_to_end_keys.py | 14 +++++-- tests/handlers/test_e2e_keys.py | 42 +++++++++++++++++++ tests/storage/test_end_to_end_keys.py | 15 +++++++ 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/synapse/storage/databases/main/end_to_end_keys.py b/synapse/storage/databases/main/end_to_end_keys.py index 341e7014d69..7b4d1f98e54 100644 --- a/synapse/storage/databases/main/end_to_end_keys.py +++ b/synapse/storage/databases/main/end_to_end_keys.py @@ -42,6 +42,7 @@ from canonicaljson import encode_canonical_json from synapse.api.constants import DeviceKeyAlgorithms +from synapse.api.errors import Codes, StoreError from synapse.appservice import ( TransactionOneTimeKeysCount, TransactionUnusedFallbackKeys, @@ -1619,9 +1620,16 @@ def _set_e2e_device_keys_txn( # 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: - log_kv({"Message": "Device key already stored."}) - return False + if old_key_json is not None: + if old_key_json == new_key_json: + log_kv({"Message": "Device key already stored."}) + return False + + raise StoreError( + 400, + "Device keys for this device have already been uploaded", + Codes.INVALID_PARAM, + ) self.db_pool.simple_upsert_txn( txn, diff --git a/tests/handlers/test_e2e_keys.py b/tests/handlers/test_e2e_keys.py index 70fc4263e7a..cec30b98b25 100644 --- a/tests/handlers/test_e2e_keys.py +++ b/tests/handlers/test_e2e_keys.py @@ -149,6 +149,48 @@ def test_change_one_time_keys(self) -> None: SynapseError, ) + def test_change_device_keys(self) -> None: + """uploading different device keys should fail""" + + local_user = "@boris:" + self.hs.hostname + device_id = "xyz" + + keys1 = { + "user_id": local_user, + "device_id": device_id, + "algorithms": ["m.olm.curve25519-aes-sha2"], + "keys": {"ed25519:" + device_id: "key1"}, + } + + keys2 = { + "user_id": local_user, + "device_id": device_id, + "algorithms": ["m.olm.curve25519-aes-sha2"], + "keys": {"ed25519:" + device_id: "key2"}, + } + + # initial upload succeeds + self.get_success( + self.handler.upload_keys_for_user( + local_user, device_id, {"device_keys": keys1} + ) + ) + + # uploading the same keys again should be fine + self.get_success( + self.handler.upload_keys_for_user( + local_user, device_id, {"device_keys": keys1} + ) + ) + + # uploading different keys should fail + self.get_failure( + self.handler.upload_keys_for_user( + local_user, device_id, {"device_keys": keys2} + ), + SynapseError, + ) + def test_claim_one_time_key(self) -> None: local_user = "@boris:" + self.hs.hostname device_id = "xyz" diff --git a/tests/storage/test_end_to_end_keys.py b/tests/storage/test_end_to_end_keys.py index bd594d3c1fe..215778ea8fb 100644 --- a/tests/storage/test_end_to_end_keys.py +++ b/tests/storage/test_end_to_end_keys.py @@ -21,6 +21,7 @@ from twisted.test.proto_helpers import MemoryReactor +from synapse.api.errors import StoreError from synapse.server import HomeServer from synapse.util import Clock @@ -65,6 +66,20 @@ def test_reupload_key(self) -> None: ) self.assertFalse(changed) + def test_change_key_rejected(self) -> None: + now = 1470174257070 + json = {"key": "value"} + json2 = {"key": "other"} + + self.get_success(self.store.store_device("user", "device", None)) + + self.get_success(self.store.set_e2e_device_keys("user", "device", now, json)) + + self.get_failure( + self.store.set_e2e_device_keys("user", "device", now, json2), + StoreError, + ) + def test_get_key_with_device_name(self) -> None: now = 1470174257070 json = {"key": "value"}