mute.mx raw
1 // Package mute manages the relay's mute blacklist. The admin nominates one
2 // pubkey whose kind-10000 mute list is treated as the authoritative blocklist.
3 // Any event from a muted pubkey is rejected at dispatch time.
4 package mute
5
6 import (
7 "encoding/hex"
8 "fmt"
9
10 "smesh.lol/pkg/nostr/filter"
11 "smesh.lol/pkg/nostr/kind"
12 "smesh.lol/pkg/nostr/tag"
13 "smesh.lol/pkg/store"
14 )
15
16 // Blacklist holds the mute blacklist state for one configured admin pubkey.
17 type Blacklist struct {
18 adminPK []byte
19 pubkeys map[string]bool
20 }
21
22 // New creates a Blacklist for the given admin pubkey (hex-encoded).
23 // Returns nil if adminHexPK is empty or invalid.
24 func New(adminHexPK string) *Blacklist {
25 if adminHexPK == "" {
26 return nil
27 }
28 pk, err := hex.DecodeString(adminHexPK)
29 if err != nil || len(pk) != 32 {
30 return nil
31 }
32 return &Blacklist{adminPK: pk, pubkeys: map[string]bool{}}
33 }
34
35 // Check returns true if pubkey (hex string) is on the mute list.
36 func (b *Blacklist) Check(pubkeyHex string) bool {
37 return b.pubkeys[pubkeyHex]
38 }
39
40 // AdminPK returns the raw 32-byte admin pubkey.
41 func (b *Blacklist) AdminPK() []byte { return b.adminPK }
42
43 // Load reads the admin's latest kind-10000 event from the store and refreshes
44 // the in-memory mute set.
45 func (b *Blacklist) Load(eng *store.Engine) {
46 one := uint(1)
47 filt := &filter.F{
48 Authors: tag.NewFromBytesSlice(b.adminPK),
49 Kinds: kind.NewS(kind.MuteList),
50 Limit: &one,
51 }
52 events, err := eng.QueryEvents(filt)
53 if err != nil || len(events) == 0 {
54 return
55 }
56 m := map[string]bool{}
57 ev := events[0]
58 if ev.Tags != nil {
59 for _, t := range ev.Tags.GetAll([]byte("p")) {
60 if t.Len() < 2 {
61 continue
62 }
63 v := t.Value()
64 if len(v) == 32 {
65 m[hex.EncodeToString(v)] = true
66 } else if len(v) == 64 {
67 m[string(v)] = true
68 }
69 }
70 }
71 b.pubkeys = m
72 fmt.Printf("mute blacklist: loaded %d pubkeys from %s\n", len(m), hex.EncodeToString(b.adminPK))
73 }
74
75 // Purge deletes all events in the store authored by muted pubkeys.
76 func (b *Blacklist) Purge(eng *store.Engine) {
77 total := 0
78 for pkHex := range b.pubkeys {
79 pk, _ := hex.DecodeString(pkHex)
80 if len(pk) != 32 {
81 continue
82 }
83 filt := &filter.F{Authors: tag.NewFromBytesSlice(pk)}
84 events, err := eng.QueryEvents(filt)
85 if err != nil {
86 continue
87 }
88 for _, ev := range events {
89 eng.DeleteEvent(ev.ID)
90 total++
91 }
92 }
93 if total > 0 {
94 fmt.Printf("mute blacklist: purged %d events from blacklisted authors\n", total)
95 }
96 }
97