1 package access
2 3 import (
4 "testing"
5 6 "git.smesh.lol/nostr/pkg/event"
7 "git.smesh.lol/nostr/pkg/kind"
8 "git.smesh.lol/nostr/pkg/tag"
9 )
10 11 // accEvent builds a bare event: CanSee only reads Kind, Pubkey and the tag
12 // list, so no signature is needed.
13 func accEvent(k uint16, pub []byte, tags *tag.S) (ev *event.E) {
14 return &event.E{Kind: k, Pubkey: pub, Tags: tags}
15 }
16 17 func accDash() (s *tag.S) {
18 return tag.NewS(tag.NewFromBytesSlice([]byte("-")))
19 }
20 21 // TestIsMLS pins exactly which kinds the relay treats as MLS: the three MLS
22 // kinds plus the gift-wrap that can carry a Welcome. GiftWrapWithKind4 is a
23 // separate kind and must not be swept in.
24 func TestIsMLS(t *testing.T) {
25 // IsMLS compares against kind package pointers; they are nil until
26 // ensureKinds runs. Production callers reach here after Ensure.
27 kind.Ensure()
28 if !IsMLS(443) {
29 t.Fatal("MLSKeyPackage (443) must be MLS")
30 }
31 if !IsMLS(444) {
32 t.Fatal("MLSWelcome (444) must be MLS")
33 }
34 if !IsMLS(445) {
35 t.Fatal("MLSGroupEvent (445) must be MLS")
36 }
37 if !IsMLS(1059) {
38 t.Fatal("GiftWrap (1059) must be MLS")
39 }
40 if IsMLS(1060) {
41 t.Fatal("GiftWrapWithKind4 (1060) must not be MLS")
42 }
43 if IsMLS(1) {
44 t.Fatal("kind 1 must not be MLS")
45 }
46 if IsMLS(0) {
47 t.Fatal("kind 0 must not be MLS")
48 }
49 }
50 51 // TestCanSeePrivilege covers the privileged-kind gate with every combination of
52 // auth and marmotOpen. Only MLS kinds are exempted by marmotOpen; a privileged
53 // non-MLS kind still requires auth.
54 func TestCanSeePrivilege(t *testing.T) {
55 // Force the kind table before any package pointer is read.
56 kind.Ensure()
57 pk := []byte("authed-pubkey-32-bytes-long-000")
58 evPlain := accEvent(1, pk, nil)
59 evPriv := accEvent(4, pk, nil) // EncryptedDirectMessage
60 evMLS := accEvent(443, pk, nil) // MLSKeyPackage
61 evMLS2 := accEvent(1059, pk, nil) // GiftWrap
62 63 if !CanSee(false, nil, evPlain, false, false) {
64 t.Fatal("non-privileged event must be visible unauthenticated")
65 }
66 if CanSee(false, nil, evPriv, false, false) {
67 t.Fatal("privileged event must be hidden from an unauthenticated reader")
68 }
69 if !CanSee(true, pk, evPriv, false, false) {
70 t.Fatal("privileged event must be visible to an authenticated reader")
71 }
72 if !CanSee(false, nil, evMLS, false, true) {
73 t.Fatal("MLS kind must pass with marmotOpen")
74 }
75 if CanSee(false, nil, evMLS, false, false) {
76 t.Fatal("MLS kind must be gated when marmotOpen is off")
77 }
78 if !CanSee(false, nil, evMLS2, false, true) {
79 t.Fatal("GiftWrap must pass with marmotOpen")
80 }
81 if CanSee(false, nil, evPriv, false, true) {
82 t.Fatal("marmotOpen must not exempt a non-MLS privileged kind")
83 }
84 }
85 86 // TestCanSeeNIP70 covers the "-" protected tag: the event reaches only its own
87 // author, and only when authenticated. Every other combination is denied.
88 func TestCanSeeNIP70(t *testing.T) {
89 kind.Ensure()
90 author := []byte("author-pubkey-32-bytes-long-0000")
91 other := []byte("other-pubkey-32-bytes-long-00000")
92 ev := accEvent(1, author, accDash())
93 evBare := accEvent(1, author, tag.NewS(tag.NewFromBytesSlice([]byte("t"), []byte("x"))))
94 95 if !CanSee(false, nil, ev, false, false) {
96 t.Fatal("nip70 off must not filter the protected tag")
97 }
98 if CanSee(false, nil, ev, true, false) {
99 t.Fatal("protected event must be hidden from an unauthenticated reader")
100 }
101 if !CanSee(true, author, ev, true, false) {
102 t.Fatal("protected event must reach its authenticated author")
103 }
104 if CanSee(true, other, ev, true, false) {
105 t.Fatal("protected event must not reach a different authenticated pubkey")
106 }
107 if CanSee(true, nil, ev, true, false) {
108 t.Fatal("protected event must not reach an auth with no pubkey")
109 }
110 if !CanSee(false, nil, evBare, true, false) {
111 t.Fatal("a tagless event must pass nip70 filtering")
112 }
113 114 // Tags present but no "-" tag: still delivered.
115 evNoDash := accEvent(1, author, tag.NewS(tag.NewFromBytesSlice([]byte("e"), []byte("x"))))
116 if !CanSee(false, nil, evNoDash, true, false) {
117 t.Fatal("an event without the '-' tag must pass nip70 filtering")
118 }
119 if !CanSee(false, nil, accEvent(1, author, nil), true, false) {
120 t.Fatal("nil tags must pass nip70 filtering")
121 }
122 }
123 124 // TestWriteExempt pins the write-auth exemptions: NIP-46 connect only when the
125 // bypass flag is set, and MLS kinds only when marmotOpen.
126 func TestWriteExempt(t *testing.T) {
127 kind.Ensure()
128 if !WriteExempt(24133, true, false) {
129 t.Fatal("NostrConnect must be exempt when nip46BypassAuth is on")
130 }
131 if WriteExempt(24133, false, false) {
132 t.Fatal("NostrConnect must not be exempt when the bypass is off")
133 }
134 if WriteExempt(1, true, false) {
135 t.Fatal("kind 1 must not be exempt via the NIP-46 bypass")
136 }
137 if !WriteExempt(443, false, true) {
138 t.Fatal("MLSKeyPackage must be exempt when marmotOpen")
139 }
140 if !WriteExempt(444, false, true) {
141 t.Fatal("MLSWelcome must be exempt when marmotOpen")
142 }
143 if !WriteExempt(445, false, true) {
144 t.Fatal("MLSGroupEvent must be exempt when marmotOpen")
145 }
146 if !WriteExempt(1059, false, true) {
147 t.Fatal("GiftWrap must be exempt when marmotOpen")
148 }
149 if WriteExempt(443, false, false) {
150 t.Fatal("MLS must not be exempt when marmotOpen is off")
151 }
152 if WriteExempt(1060, false, true) {
153 t.Fatal("GiftWrapWithKind4 must not be exempt")
154 }
155 if WriteExempt(1, true, true) {
156 t.Fatal("kind 1 must never be write-exempt")
157 }
158 }
159