mirror of
https://github.com/fiatjaf/khatru.git
synced 2026-06-09 14:19:04 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33545587b6 | ||
|
|
214371f8bd | ||
|
|
fbb40f3b74 | ||
|
|
d97a2f1cf2 |
132
adding.go
132
adding.go
@@ -11,34 +11,46 @@ import (
|
|||||||
|
|
||||||
// AddEvent sends an event through then normal add pipeline, as if it was received from a websocket.
|
// AddEvent sends an event through then normal add pipeline, as if it was received from a websocket.
|
||||||
func (rl *Relay) AddEvent(ctx context.Context, evt *nostr.Event) (skipBroadcast bool, writeError error) {
|
func (rl *Relay) AddEvent(ctx context.Context, evt *nostr.Event) (skipBroadcast bool, writeError error) {
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
if evt == nil {
|
if evt == nil {
|
||||||
return false, errors.New("error: event is nil")
|
return false, errors.New("error: event is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if nostr.IsEphemeralKind(evt.Kind) {
|
||||||
|
return false, rl.handleEphemeral(ctx, evt)
|
||||||
|
} else {
|
||||||
|
return rl.handleNormal(ctx, evt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rl *Relay) handleNormal(ctx context.Context, evt *nostr.Event) (skipBroadcast bool, writeError error) {
|
||||||
for _, reject := range rl.RejectEvent {
|
for _, reject := range rl.RejectEvent {
|
||||||
if reject, msg := reject(ctx, evt); reject {
|
if reject, msg := reject(ctx, evt); reject {
|
||||||
if msg == "" {
|
if msg == "" {
|
||||||
return false, errors.New("blocked: no reason")
|
return true, errors.New("blocked: no reason")
|
||||||
} else {
|
} else {
|
||||||
return false, errors.New(nostr.NormalizeOKMessage(msg, "blocked"))
|
return true, errors.New(nostr.NormalizeOKMessage(msg, "blocked"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if 20000 <= evt.Kind && evt.Kind < 30000 {
|
// will store
|
||||||
// do not store ephemeral events
|
// regular kinds are just saved directly
|
||||||
for _, oee := range rl.OnEphemeralEvent {
|
if nostr.IsRegularKind(evt.Kind) {
|
||||||
oee(ctx, evt)
|
for _, store := range rl.StoreEvent {
|
||||||
|
if err := store(ctx, evt); err != nil {
|
||||||
|
switch err {
|
||||||
|
case eventstore.ErrDupEvent:
|
||||||
|
return true, nil
|
||||||
|
default:
|
||||||
|
return false, fmt.Errorf("%s", nostr.NormalizeOKMessage(err.Error(), "error"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// will store
|
// otherwise it's a replaceable -- so we'll use the replacer functions if we have any
|
||||||
// regular kinds are just saved directly
|
if len(rl.ReplaceEvent) > 0 {
|
||||||
if nostr.IsRegularKind(evt.Kind) {
|
for _, repl := range rl.ReplaceEvent {
|
||||||
for _, store := range rl.StoreEvent {
|
if err := repl(ctx, evt); err != nil {
|
||||||
if err := store(ctx, evt); err != nil {
|
|
||||||
switch err {
|
switch err {
|
||||||
case eventstore.ErrDupEvent:
|
case eventstore.ErrDupEvent:
|
||||||
return true, nil
|
return true, nil
|
||||||
@@ -48,68 +60,54 @@ func (rl *Relay) AddEvent(ctx context.Context, evt *nostr.Event) (skipBroadcast
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// otherwise it's a replaceable -- so we'll use the replacer functions if we have any
|
// otherwise do it the manual way
|
||||||
if len(rl.ReplaceEvent) > 0 {
|
filter := nostr.Filter{Limit: 1, Kinds: []int{evt.Kind}, Authors: []string{evt.PubKey}}
|
||||||
for _, repl := range rl.ReplaceEvent {
|
if nostr.IsAddressableKind(evt.Kind) {
|
||||||
if err := repl(ctx, evt); err != nil {
|
// when addressable, add the "d" tag to the filter
|
||||||
switch err {
|
filter.Tags = nostr.TagMap{"d": []string{evt.Tags.GetD()}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we fetch old events and delete them
|
||||||
|
shouldStore := true
|
||||||
|
for _, query := range rl.QueryEvents {
|
||||||
|
ch, err := query(ctx, filter)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for previous := range ch {
|
||||||
|
if isOlder(previous, evt) {
|
||||||
|
for _, del := range rl.DeleteEvent {
|
||||||
|
del(ctx, previous)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we found a more recent event, so we won't delete it and also will not store this new one
|
||||||
|
shouldStore = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// store
|
||||||
|
if shouldStore {
|
||||||
|
for _, store := range rl.StoreEvent {
|
||||||
|
if saveErr := store(ctx, evt); saveErr != nil {
|
||||||
|
switch saveErr {
|
||||||
case eventstore.ErrDupEvent:
|
case eventstore.ErrDupEvent:
|
||||||
return true, nil
|
return true, nil
|
||||||
default:
|
default:
|
||||||
return false, fmt.Errorf("%s", nostr.NormalizeOKMessage(err.Error(), "error"))
|
return false, fmt.Errorf("%s", nostr.NormalizeOKMessage(saveErr.Error(), "error"))
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// otherwise do it the manual way
|
|
||||||
filter := nostr.Filter{Limit: 1, Kinds: []int{evt.Kind}, Authors: []string{evt.PubKey}}
|
|
||||||
if nostr.IsAddressableKind(evt.Kind) {
|
|
||||||
// when addressable, add the "d" tag to the filter
|
|
||||||
filter.Tags = nostr.TagMap{"d": []string{evt.Tags.GetD()}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now we fetch old events and delete them
|
|
||||||
shouldStore := true
|
|
||||||
for _, query := range rl.QueryEvents {
|
|
||||||
ch, err := query(ctx, filter)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for previous := range ch {
|
|
||||||
if isOlder(previous, evt) {
|
|
||||||
for _, del := range rl.DeleteEvent {
|
|
||||||
del(ctx, previous)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we found a more recent event, so we won't delete it and also will not store this new one
|
|
||||||
shouldStore = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// store
|
|
||||||
if shouldStore {
|
|
||||||
for _, store := range rl.StoreEvent {
|
|
||||||
if saveErr := store(ctx, evt); saveErr != nil {
|
|
||||||
switch saveErr {
|
|
||||||
case eventstore.ErrDupEvent:
|
|
||||||
return true, nil
|
|
||||||
default:
|
|
||||||
return false, fmt.Errorf("%s", nostr.NormalizeOKMessage(saveErr.Error(), "error"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ons := range rl.OnEventSaved {
|
|
||||||
ons(ctx, evt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// track event expiration if applicable
|
|
||||||
rl.expirationManager.trackEvent(evt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, ons := range rl.OnEventSaved {
|
||||||
|
ons(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// track event expiration if applicable
|
||||||
|
rl.expirationManager.trackEvent(evt)
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ func (bs BlossomServer) handleUploadCheck(w http.ResponseWriter, r *http.Request
|
|||||||
blossomError(w, "missing \"Authorization\" header", 401)
|
blossomError(w, "missing \"Authorization\" header", 401)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if auth.Tags.GetFirst([]string{"t", "upload"}) == nil {
|
if auth.Tags.FindWithValue("t", "upload") == nil {
|
||||||
blossomError(w, "invalid \"Authorization\" event \"t\" tag", 403)
|
blossomError(w, "invalid \"Authorization\" event \"t\" tag", 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ func (bs BlossomServer) handleUpload(w http.ResponseWriter, r *http.Request) {
|
|||||||
blossomError(w, "missing \"Authorization\" header", 401)
|
blossomError(w, "missing \"Authorization\" header", 401)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if auth.Tags.GetFirst([]string{"t", "upload"}) == nil {
|
if auth.Tags.FindWithValue("t", "upload") == nil {
|
||||||
blossomError(w, "invalid \"Authorization\" event \"t\" tag", 403)
|
blossomError(w, "invalid \"Authorization\" event \"t\" tag", 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -163,13 +163,13 @@ func (bs BlossomServer) handleGetBlob(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// if there is one, we check if it has the extra requirements
|
// if there is one, we check if it has the extra requirements
|
||||||
if auth != nil {
|
if auth != nil {
|
||||||
if auth.Tags.GetFirst([]string{"t", "get"}) == nil {
|
if auth.Tags.FindWithValue("t", "get") == nil {
|
||||||
blossomError(w, "invalid \"Authorization\" event \"t\" tag", 403)
|
blossomError(w, "invalid \"Authorization\" event \"t\" tag", 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if auth.Tags.GetFirst([]string{"x", hhash}) == nil &&
|
if auth.Tags.FindWithValue("x", hhash) == nil &&
|
||||||
auth.Tags.GetFirst([]string{"server", bs.ServiceURL}) == nil {
|
auth.Tags.FindWithValue("server", bs.ServiceURL) == nil {
|
||||||
blossomError(w, "invalid \"Authorization\" event \"x\" or \"server\" tag", 403)
|
blossomError(w, "invalid \"Authorization\" event \"x\" or \"server\" tag", 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -239,7 +239,7 @@ func (bs BlossomServer) handleList(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// if there is one, we check if it has the extra requirements
|
// if there is one, we check if it has the extra requirements
|
||||||
if auth != nil {
|
if auth != nil {
|
||||||
if auth.Tags.GetFirst([]string{"t", "list"}) == nil {
|
if auth.Tags.FindWithValue("t", "list") == nil {
|
||||||
blossomError(w, "invalid \"Authorization\" event \"t\" tag", 403)
|
blossomError(w, "invalid \"Authorization\" event \"t\" tag", 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -283,7 +283,7 @@ func (bs BlossomServer) handleDelete(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if auth != nil {
|
if auth != nil {
|
||||||
if auth.Tags.GetFirst([]string{"t", "delete"}) == nil {
|
if auth.Tags.FindWithValue("t", "delete") == nil {
|
||||||
blossomError(w, "invalid \"Authorization\" event \"t\" tag", 403)
|
blossomError(w, "invalid \"Authorization\" event \"t\" tag", 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -296,8 +296,8 @@ func (bs BlossomServer) handleDelete(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
hhash = hhash[1:]
|
hhash = hhash[1:]
|
||||||
if auth.Tags.GetFirst([]string{"x", hhash}) == nil &&
|
if auth.Tags.FindWithValue("x", hhash) == nil &&
|
||||||
auth.Tags.GetFirst([]string{"server", bs.ServiceURL}) == nil {
|
auth.Tags.FindWithValue("server", bs.ServiceURL) == nil {
|
||||||
blossomError(w, "invalid \"Authorization\" event \"x\" or \"server\" tag", 403)
|
blossomError(w, "invalid \"Authorization\" event \"x\" or \"server\" tag", 403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ import (
|
|||||||
|
|
||||||
// BroadcastEvent emits an event to all listeners whose filters' match, skipping all filters and actions
|
// BroadcastEvent emits an event to all listeners whose filters' match, skipping all filters and actions
|
||||||
// it also doesn't attempt to store the event or trigger any reactions or callbacks
|
// it also doesn't attempt to store the event or trigger any reactions or callbacks
|
||||||
func (rl *Relay) BroadcastEvent(evt *nostr.Event) {
|
func (rl *Relay) BroadcastEvent(evt *nostr.Event) int {
|
||||||
rl.notifyListeners(evt)
|
return rl.notifyListeners(evt)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ router.Route().
|
|||||||
return true
|
return true
|
||||||
case event.Kind <= 12 && event.Kind >= 9:
|
case event.Kind <= 12 && event.Kind >= 9:
|
||||||
return true
|
return true
|
||||||
case event.Tags.GetFirst([]string{"h", ""}) != nil:
|
case event.Tags.Find("h") != nil:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
|||||||
26
ephemeral.go
Normal file
26
ephemeral.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package khatru
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/nbd-wtf/go-nostr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (rl *Relay) handleEphemeral(ctx context.Context, evt *nostr.Event) error {
|
||||||
|
for _, reject := range rl.RejectEvent {
|
||||||
|
if reject, msg := reject(ctx, evt); reject {
|
||||||
|
if msg == "" {
|
||||||
|
return errors.New("blocked: no reason")
|
||||||
|
} else {
|
||||||
|
return errors.New(nostr.NormalizeOKMessage(msg, "blocked"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, oee := range rl.OnEphemeralEvent {
|
||||||
|
oee(ctx, evt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ func main() {
|
|||||||
relay := khatru.NewRelay()
|
relay := khatru.NewRelay()
|
||||||
|
|
||||||
db := lmdb.LMDBBackend{Path: "/tmp/khatru-lmdb-tmp"}
|
db := lmdb.LMDBBackend{Path: "/tmp/khatru-lmdb-tmp"}
|
||||||
os.MkdirAll(db.Path, 0755)
|
os.MkdirAll(db.Path, 0o755)
|
||||||
if err := db.Init(); err != nil {
|
if err := db.Init(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func main() {
|
|||||||
relay := khatru.NewRelay()
|
relay := khatru.NewRelay()
|
||||||
|
|
||||||
db := lmdb.LMDBBackend{Path: "/tmp/exclusive"}
|
db := lmdb.LMDBBackend{Path: "/tmp/exclusive"}
|
||||||
os.MkdirAll(db.Path, 0755)
|
os.MkdirAll(db.Path, 0o755)
|
||||||
if err := db.Init(); err != nil {
|
if err := db.Init(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func main() {
|
|||||||
return slices.Contains(filter.Kinds, 1) && slices.Contains(filter.Tags["t"], "spam")
|
return slices.Contains(filter.Kinds, 1) && slices.Contains(filter.Tags["t"], "spam")
|
||||||
}).
|
}).
|
||||||
Event(func(event *nostr.Event) bool {
|
Event(func(event *nostr.Event) bool {
|
||||||
return event.Kind == 1 && event.Tags.GetFirst([]string{"t", "spam"}) != nil
|
return event.Kind == 1 && event.Tags.FindWithValue("t", "spam") != nil
|
||||||
}).
|
}).
|
||||||
Relay(r2)
|
Relay(r2)
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ func (em *expirationManager) initialScan(ctx context.Context) {
|
|||||||
defer em.mu.Unlock()
|
defer em.mu.Unlock()
|
||||||
|
|
||||||
// query all events
|
// query all events
|
||||||
|
ctx = context.WithValue(ctx, internalCallKey, struct{}{})
|
||||||
for _, query := range em.relay.QueryEvents {
|
for _, query := range em.relay.QueryEvents {
|
||||||
ch, err := query(ctx, nostr.Filter{})
|
ch, err := query(ctx, nostr.Filter{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
23
handlers.go
23
handlers.go
@@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -141,6 +142,7 @@ func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is safe because ReadMessage() will always create a new slice
|
||||||
message := unsafe.String(unsafe.SliceData(msgb), len(msgb))
|
message := unsafe.String(unsafe.SliceData(msgb), len(msgb))
|
||||||
|
|
||||||
// parse messages sequentially otherwise sonic breaks
|
// parse messages sequentially otherwise sonic breaks
|
||||||
@@ -215,9 +217,12 @@ func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
if env.Event.Kind == 5 {
|
if env.Event.Kind == 5 {
|
||||||
// this always returns "blocked: " whenever it returns an error
|
// this always returns "blocked: " whenever it returns an error
|
||||||
writeErr = srl.handleDeleteRequest(ctx, &env.Event)
|
writeErr = srl.handleDeleteRequest(ctx, &env.Event)
|
||||||
|
} else if nostr.IsEphemeralKind(env.Event.Kind) {
|
||||||
|
// this will also always return a prefixed reason
|
||||||
|
writeErr = srl.handleEphemeral(ctx, &env.Event)
|
||||||
} else {
|
} else {
|
||||||
// this will also always return a prefixed reason
|
// this will also always return a prefixed reason
|
||||||
skipBroadcast, writeErr = srl.AddEvent(ctx, &env.Event)
|
skipBroadcast, writeErr = srl.handleNormal(ctx, &env.Event)
|
||||||
}
|
}
|
||||||
|
|
||||||
var reason string
|
var reason string
|
||||||
@@ -227,9 +232,20 @@ func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
ovw(ctx, &env.Event)
|
ovw(ctx, &env.Event)
|
||||||
}
|
}
|
||||||
if !skipBroadcast {
|
if !skipBroadcast {
|
||||||
srl.notifyListeners(&env.Event)
|
n := srl.notifyListeners(&env.Event)
|
||||||
|
|
||||||
|
// the number of notified listeners matters in ephemeral events
|
||||||
|
if nostr.IsEphemeralKind(env.Event.Kind) {
|
||||||
|
if n == 0 {
|
||||||
|
ok = false
|
||||||
|
reason = "mute: no one was listening for this"
|
||||||
|
} else {
|
||||||
|
reason = "broadcasted to " + strconv.Itoa(n) + " listeners"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
ok = false
|
||||||
reason = writeErr.Error()
|
reason = writeErr.Error()
|
||||||
if strings.HasPrefix(reason, "auth-required:") {
|
if strings.HasPrefix(reason, "auth-required:") {
|
||||||
RequestAuth(ctx)
|
RequestAuth(ctx)
|
||||||
@@ -244,14 +260,13 @@ func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
var total int64
|
var total int64
|
||||||
var hll *hyperloglog.HyperLogLog
|
var hll *hyperloglog.HyperLogLog
|
||||||
uneligibleForHLL := false
|
|
||||||
|
|
||||||
srl := rl
|
srl := rl
|
||||||
if rl.getSubRelayFromFilter != nil {
|
if rl.getSubRelayFromFilter != nil {
|
||||||
srl = rl.getSubRelayFromFilter(env.Filter)
|
srl = rl.getSubRelayFromFilter(env.Filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
if offset := nip45.HyperLogLogEventPubkeyOffsetForFilter(env.Filter); offset != -1 && !uneligibleForHLL {
|
if offset := nip45.HyperLogLogEventPubkeyOffsetForFilter(env.Filter); offset != -1 {
|
||||||
total, hll = srl.handleCountRequestWithHLL(ctx, ws, env.Filter, offset)
|
total, hll = srl.handleCountRequestWithHLL(ctx, ws, env.Filter, offset)
|
||||||
} else {
|
} else {
|
||||||
total = srl.handleCountRequest(ctx, ws, env.Filter)
|
total = srl.handleCountRequest(ctx, ws, env.Filter)
|
||||||
|
|||||||
@@ -132,15 +132,20 @@ func (rl *Relay) removeClientAndListeners(ws *WebSocket) {
|
|||||||
delete(rl.clients, ws)
|
delete(rl.clients, ws)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rl *Relay) notifyListeners(event *nostr.Event) {
|
// returns how many listeners were notified
|
||||||
|
func (rl *Relay) notifyListeners(event *nostr.Event) int {
|
||||||
|
count := 0
|
||||||
|
listenersloop:
|
||||||
for _, listener := range rl.listeners {
|
for _, listener := range rl.listeners {
|
||||||
if listener.filter.Matches(event) {
|
if listener.filter.Matches(event) {
|
||||||
for _, pb := range rl.PreventBroadcast {
|
for _, pb := range rl.PreventBroadcast {
|
||||||
if pb(listener.ws, event) {
|
if pb(listener.ws, event) {
|
||||||
return
|
continue listenersloop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
listener.ws.WriteJSON(nostr.EventEnvelope{SubscriptionID: &listener.id, Event: *event})
|
listener.ws.WriteJSON(nostr.EventEnvelope{SubscriptionID: &listener.id, Event: *event})
|
||||||
|
count++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return count
|
||||||
}
|
}
|
||||||
|
|||||||
4
nip86.go
4
nip86.go
@@ -86,10 +86,10 @@ func (rl *Relay) HandleNIP86(w http.ResponseWriter, r *http.Request) {
|
|||||||
goto respond
|
goto respond
|
||||||
}
|
}
|
||||||
|
|
||||||
if uTag := evt.Tags.GetFirst([]string{"u", ""}); uTag == nil || rl.getBaseURL(r) != (*uTag)[1] {
|
if uTag := evt.Tags.Find("u"); uTag == nil || rl.getBaseURL(r) != uTag[1] {
|
||||||
resp.Error = "invalid 'u' tag"
|
resp.Error = "invalid 'u' tag"
|
||||||
goto respond
|
goto respond
|
||||||
} else if pht := evt.Tags.GetFirst([]string{"payload", hex.EncodeToString(payloadHash[:])}); pht == nil {
|
} else if pht := evt.Tags.FindWithValue("payload", hex.EncodeToString(payloadHash[:])); pht == nil {
|
||||||
resp.Error = "invalid auth event payload hash"
|
resp.Error = "invalid auth event payload hash"
|
||||||
goto respond
|
goto respond
|
||||||
} else if evt.CreatedAt < nostr.Now()-30 {
|
} else if evt.CreatedAt < nostr.Now()-30 {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package policies
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"github.com/fiatjaf/khatru"
|
"github.com/fiatjaf/khatru"
|
||||||
|
|||||||
Reference in New Issue
Block a user