summaryrefslogtreecommitdiffstats
path: root/internal/nostr/event.go
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-13 17:35:32 -0800
committerbndw <ben@bdw.to>2026-02-13 17:35:32 -0800
commit581ceecbf046f99b39885c74e2780a5320e5b15e (patch)
treec82dcaddb4f555d5051684221881e36f7fe3f718 /internal/nostr/event.go
parent06b9b13274825f797523935494a1b5225f0e0862 (diff)
feat: add Nostr protocol implementation (internal/nostr, internal/websocket)
Diffstat (limited to 'internal/nostr/event.go')
-rw-r--r--internal/nostr/event.go72
1 files changed, 72 insertions, 0 deletions
diff --git a/internal/nostr/event.go b/internal/nostr/event.go
new file mode 100644
index 0000000..a8156bb
--- /dev/null
+++ b/internal/nostr/event.go
@@ -0,0 +1,72 @@
1package nostr
2
3import (
4 "crypto/sha256"
5 "encoding/hex"
6 "encoding/json"
7 "fmt"
8)
9
10// Event represents a Nostr event as defined in NIP-01.
11type Event struct {
12 ID string `json:"id"`
13 PubKey string `json:"pubkey"`
14 CreatedAt int64 `json:"created_at"`
15 Kind int `json:"kind"`
16 Tags Tags `json:"tags"`
17 Content string `json:"content"`
18 Sig string `json:"sig"`
19}
20
21// Serialize returns the canonical JSON serialization of the event for ID computation.
22// Format: [0, "pubkey", created_at, kind, tags, "content"]
23func (e *Event) Serialize() []byte {
24 // Use json.Marshal for proper escaping of content and tags
25 arr := []interface{}{
26 0,
27 e.PubKey,
28 e.CreatedAt,
29 e.Kind,
30 e.Tags,
31 e.Content,
32 }
33 data, _ := json.Marshal(arr)
34 return data
35}
36
37// ComputeID calculates the SHA256 hash of the serialized event.
38// Returns the 64-character hex-encoded ID.
39func (e *Event) ComputeID() string {
40 serialized := e.Serialize()
41 hash := sha256.Sum256(serialized)
42 return hex.EncodeToString(hash[:])
43}
44
45// SetID computes and sets the event ID.
46func (e *Event) SetID() {
47 e.ID = e.ComputeID()
48}
49
50// CheckID verifies that the event ID matches the computed ID.
51func (e *Event) CheckID() bool {
52 return e.ID == e.ComputeID()
53}
54
55// MarshalJSON implements json.Marshaler with empty tags as [] instead of null.
56func (e Event) MarshalJSON() ([]byte, error) {
57 type eventAlias Event
58 ea := eventAlias(e)
59 if ea.Tags == nil {
60 ea.Tags = Tags{}
61 }
62 return json.Marshal(ea)
63}
64
65// String returns a JSON representation of the event for debugging.
66func (e *Event) String() string {
67 data, err := json.MarshalIndent(e, "", " ")
68 if err != nil {
69 return fmt.Sprintf("<Event error: %v>", err)
70 }
71 return string(data)
72}