|
27 | 27 |
|
28 | 28 | from canonicaljson import encode_canonical_json |
29 | 29 | from signedjson.sign import sign_json |
30 | | -from signedjson.types import SigningKey |
| 30 | +from signedjson.types import SigningKey, VerifyKey |
31 | 31 | from unpaddedbase64 import decode_base64, encode_base64 |
32 | 32 |
|
33 | 33 | from synapse.api.errors import Codes, SynapseError |
34 | 34 | from synapse.api.room_versions import RoomVersion |
35 | 35 | from synapse.events import EventBase |
36 | 36 | from synapse.events.utils import prune_event, prune_event_dict |
37 | 37 | from synapse.logging.opentracing import trace |
38 | | -from synapse.types import JsonDict |
| 38 | +from synapse.types import JsonDict, UserID |
39 | 39 |
|
40 | 40 | logger = logging.getLogger(__name__) |
41 | 41 |
|
@@ -192,3 +192,54 @@ def add_hashes_and_signatures( |
192 | 192 | event_dict["signatures"] = compute_event_signature( |
193 | 193 | room_version, event_dict, signature_name=signature_name, signing_key=signing_key |
194 | 194 | ) |
| 195 | + |
| 196 | + |
| 197 | +def resign_event( |
| 198 | + ev: EventBase, |
| 199 | + server_name: str, |
| 200 | + signing_key: SigningKey, |
| 201 | + time_now: int | None = None, |
| 202 | +) -> JsonDict: |
| 203 | + """Re-sign the provided event with the given signing key. Any existing signatures on the event |
| 204 | + for this server_name are removed. |
| 205 | +
|
| 206 | + If there has been no signature for this event by this server_name, the event is still re-signed. |
| 207 | + If there have been signatures on this event by this server_name, the event is not re-checked for |
| 208 | + validity. As such, only events that have valid signatures should be passed into this function |
| 209 | + e.g. from the event_json table in the database. |
| 210 | + """ |
| 211 | + event_dict = ev.get_pdu_json(time_now=time_now) |
| 212 | + event_dict["signatures"].pop( |
| 213 | + server_name, None |
| 214 | + ) # remove existing signatures for this server_name |
| 215 | + event_dict["signatures"].update( |
| 216 | + compute_event_signature( |
| 217 | + ev.room_version, |
| 218 | + event_dict, |
| 219 | + server_name, |
| 220 | + signing_key, |
| 221 | + ) |
| 222 | + ) |
| 223 | + return event_dict |
| 224 | + |
| 225 | + |
| 226 | +def event_needs_resigning( |
| 227 | + ev: EventBase, server_name: str, verify_key: VerifyKey |
| 228 | +) -> bool: |
| 229 | + """Check if this event needs re-signing. |
| 230 | +
|
| 231 | + This returns True if all of the following are True: |
| 232 | + - the event `sender` domain matches the `server_name` provided. |
| 233 | + - the event has not been already signed with this `verify_key`. |
| 234 | + """ |
| 235 | + sender = UserID.from_string(ev.sender) |
| 236 | + if sender.domain != server_name: |
| 237 | + return False |
| 238 | + want_key_id = verify_key.alg + ":" + verify_key.version |
| 239 | + signed_with_current_key_id = ev.signatures.get(server_name, {}).get( |
| 240 | + want_key_id, None |
| 241 | + ) |
| 242 | + if signed_with_current_key_id: |
| 243 | + return False |
| 244 | + |
| 245 | + return True |
0 commit comments