Skip to content

Commit 41dc14c

Browse files
committed
feat: Add verify_hash function for events.
1 parent 1726a70 commit 41dc14c

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

eventsourcingdb/event/event.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from dataclasses import dataclass
22
from datetime import datetime
3+
import json
4+
from hashlib import sha256
35
from typing import Any, TypeVar
46

57
from ..errors.internal_error import InternalError
@@ -94,6 +96,32 @@ def parse(unknown_object: dict) -> "Event":
9496
trace_state=trace_state,
9597
)
9698

99+
def verify_hash(self) -> None:
100+
metadata = "|".join([
101+
self.spec_version,
102+
self.event_id,
103+
self.predecessor_hash,
104+
self.time.isoformat(sep="T"),
105+
self.source,
106+
self.subject,
107+
self.type,
108+
self.data_content_type,
109+
])
110+
111+
metadata_bytes = metadata.encode("utf-8")
112+
data_bytes = json.dumps(self.data).encode("utf-8")
113+
114+
metadata_hash = sha256(metadata_bytes).hexdigest()
115+
data_hash = sha256(data_bytes).hexdigest()
116+
117+
final_hash = sha256()
118+
final_hash.update(metadata_hash.encode("utf-8"))
119+
final_hash.update(data_hash.encode("utf-8"))
120+
final_hash_hex = final_hash.hexdigest()
121+
122+
if final_hash_hex != self.hash:
123+
raise ValidationError("Failed to verify hash.")
124+
97125
def to_json(self) -> dict[str, Any]:
98126
json = {
99127
"specversion": self.spec_version,

tests/event/test_verify_hash.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import pytest
2+
3+
from eventsourcingdb import EventCandidate
4+
5+
from ..conftest import TestData
6+
from ..shared.database import Database
7+
8+
9+
class TestVerifyHash:
10+
@staticmethod
11+
@pytest.mark.asyncio
12+
async def test_verifies_the_event_hash(
13+
database: Database,
14+
test_data: TestData,
15+
) -> None:
16+
client = database.get_client()
17+
18+
written_events = await client.write_events(
19+
[
20+
EventCandidate(
21+
source=test_data.TEST_SOURCE_STRING, subject="/test", type="io.eventsourcingdb.test", data={"value": 23}
22+
)
23+
],
24+
)
25+
26+
assert len(written_events) == 1
27+
28+
written_event = written_events[0]
29+
written_event.verify_hash()

0 commit comments

Comments
 (0)