Compare commits

...

8 Commits

Author SHA1 Message Date
fiatjaf
255f7bc827 delete all previous replaceable events by default. 2024-04-10 21:34:23 -03:00
fiatjaf
3214dac302 fix pre-search on policies. 2024-03-30 14:23:17 -03:00
fiatjaf
5efadf6256 do not give away so much. 2024-03-29 18:25:47 -03:00
fiatjaf
27d6769009 format last commit. 2024-03-29 18:24:44 -03:00
Sebastix
44baacac42 * sort kinds before the binary search is run
* optimized return messages with more context why the policy blocks an event
2024-03-29 18:24:21 -03:00
fiatjaf
35053f6215 when LimitZero don't do any database queries. 2024-03-29 08:12:39 -03:00
fiatjaf
8854ad7a95 don't send a NOTICE when REQs are rejected anymore, just the CLOSED. 2024-03-25 10:55:59 -03:00
fiatjaf
c5c17029ba basic kind validation policy. 2024-03-13 12:40:54 -03:00
9 changed files with 77 additions and 19 deletions

View File

@@ -69,6 +69,11 @@ func main() {
// there are many other configurable things you can set
relay.RejectEvent = append(relay.RejectEvent,
// built-in policies
policies.ValidateKind,
// define your own policies
policies.PreventLargeTags(80),
func(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
if event.PubKey == "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52" {
return true, "we don't allow this person to write here"
@@ -79,6 +84,10 @@ func main() {
// you can request auth by rejecting an event or a request with the prefix "auth-required: "
relay.RejectFilter = append(relay.RejectFilter,
// built-in policies
policies.NoComplexFilters,
// define your own policies
func(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
if pubkey := khatru.GetAuthed(ctx); pubkey != "" {
log.Printf("request from %s\n", pubkey)

View File

@@ -38,9 +38,11 @@ func (rl *Relay) AddEvent(ctx context.Context, evt *nostr.Event) error {
if err != nil {
continue
}
if previous := <-ch; previous != nil && isOlder(previous, evt) {
for _, del := range rl.DeleteEvent {
del(ctx, previous)
for previous := range ch {
if isOlder(previous, evt) {
for _, del := range rl.DeleteEvent {
del(ctx, previous)
}
}
}
}
@@ -53,9 +55,11 @@ func (rl *Relay) AddEvent(ctx context.Context, evt *nostr.Event) error {
if err != nil {
continue
}
if previous := <-ch; previous != nil && isOlder(previous, evt) {
for _, del := range rl.DeleteEvent {
del(ctx, previous)
for previous := range ch {
if isOlder(previous, evt) {
for _, del := range rl.DeleteEvent {
del(ctx, previous)
}
}
}
}

View File

@@ -7,6 +7,7 @@ import (
"net/http"
"github.com/fiatjaf/khatru"
"github.com/fiatjaf/khatru/policies"
"github.com/nbd-wtf/go-nostr"
)
@@ -53,6 +54,11 @@ func main() {
// there are many other configurable things you can set
relay.RejectEvent = append(relay.RejectEvent,
// built-in policies
policies.ValidateKind,
// define your own policies
policies.PreventLargeTags(80),
func(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
if event.PubKey == "fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52" {
return true, "we don't allow this person to write here"
@@ -63,6 +69,10 @@ func main() {
// you can request auth by rejecting an event or a request with the prefix "auth-required: "
relay.RejectFilter = append(relay.RejectFilter,
// built-in policies
policies.NoComplexFilters,
// define your own policies
func(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
if pubkey := khatru.GetAuthed(ctx); pubkey != "" {
log.Printf("request from %s\n", pubkey)

2
go.mod
View File

@@ -5,7 +5,7 @@ go 1.21.4
require (
github.com/fasthttp/websocket v1.5.7
github.com/fiatjaf/eventstore v0.3.8
github.com/nbd-wtf/go-nostr v0.28.1
github.com/nbd-wtf/go-nostr v0.30.0
github.com/puzpuzpuz/xsync/v3 v3.0.2
github.com/rs/cors v1.7.0
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a

2
go.sum
View File

@@ -115,6 +115,8 @@ github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+
github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/nbd-wtf/go-nostr v0.28.1 h1:XQi/lBsigBXHRm7IDBJE7SR9citCh9srgf8sA5iVW3A=
github.com/nbd-wtf/go-nostr v0.28.1/go.mod h1:OQ8sNLFJnsj17BdqZiLSmjJBIFTfDqckEYC3utS4qoY=
github.com/nbd-wtf/go-nostr v0.30.0 h1:rN085pe4IxmSBVht8LChZbWLggonjA8hPIk8l4/+Hjk=
github.com/nbd-wtf/go-nostr v0.30.0/go.mod h1:tiKJY6fWYSujbTQb201Y+IQ3l4szqYVt+fsTnsm7FCk=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

View File

@@ -2,7 +2,7 @@ package policies
import (
"context"
"fmt"
"slices"
"github.com/nbd-wtf/go-nostr"
@@ -14,6 +14,9 @@ import (
// If ignoreKinds is given this restriction will not apply to these kinds (useful for allowing a bigger).
// If onlyKinds is given then all other kinds will be ignored.
func PreventTooManyIndexableTags(max int, ignoreKinds []int, onlyKinds []int) func(context.Context, *nostr.Event) (bool, string) {
slices.Sort(ignoreKinds)
slices.Sort(onlyKinds)
ignore := func(kind int) bool { return false }
if len(ignoreKinds) > 0 {
ignore = func(kind int) bool {
@@ -74,21 +77,25 @@ func RestrictToSpecifiedKinds(kinds ...uint16) func(context.Context, *nostr.Even
}
}
// sort the kinds in increasing order
slices.Sort(kinds)
return func(ctx context.Context, event *nostr.Event) (reject bool, msg string) {
// these are cheap and very questionable optimizations, but they exist for a reason:
// we would have to ensure that the kind number is within the bounds of a uint16 anyway
if event.Kind > max {
return true, "event kind not allowed"
return true, fmt.Sprintf("event kind not allowed (it should be lower than %d)", max)
}
if event.Kind < min {
return true, "event kind not allowed"
return true, fmt.Sprintf("event kind not allowed (it should be higher than %d)", min)
}
// hopefully this map of uint16s is very fast
if _, allowed := slices.BinarySearch(kinds, uint16(event.Kind)); allowed {
return false, ""
}
return true, "event kind not allowed"
return true, fmt.Sprintf("received event kind %d not allowed", event.Kind)
}
}

View File

@@ -2,7 +2,6 @@ package policies
import (
"context"
"slices"
"github.com/nbd-wtf/go-nostr"
@@ -48,7 +47,7 @@ func NoSearchQueries(ctx context.Context, filter nostr.Filter) (reject bool, msg
func RemoveSearchQueries(ctx context.Context, filter *nostr.Filter) {
if filter.Search != "" {
filter.Search = ""
filter.Limit = -1 // signals that this query should be just skipped
filter.LimitZero = true // signals that this query should be just skipped
}
}
@@ -63,7 +62,7 @@ func RemoveAllButKinds(kinds ...uint16) func(context.Context, *nostr.Filter) {
}
filter.Kinds = newKinds
if len(filter.Kinds) == 0 {
filter.Limit = -1 // signals that this query should be just skipped
filter.LimitZero = true // signals that this query should be just skipped
}
}
}
@@ -78,7 +77,7 @@ func RemoveAllButTags(tagNames ...string) func(context.Context, *nostr.Filter) {
}
}
if len(filter.Tags) == 0 {
filter.Limit = -1 // signals that this query should be just skipped
filter.LimitZero = true // signals that this query should be just skipped
}
}
}

View File

@@ -0,0 +1,29 @@
package policies
import (
"context"
"encoding/json"
"github.com/nbd-wtf/go-nostr"
)
func ValidateKind(ctx context.Context, evt *nostr.Event) (bool, string) {
switch evt.Kind {
case 0:
var m struct {
Name string `json:"name"`
}
json.Unmarshal([]byte(evt.Content), &m)
if m.Name == "" {
return true, "missing json name in kind 0"
}
case 1:
return false, ""
case 2:
return true, "this kind has been deprecated"
}
// TODO: all other kinds
return false, ""
}

View File

@@ -17,9 +17,8 @@ func (rl *Relay) handleRequest(ctx context.Context, id string, eose *sync.WaitGr
ovw(ctx, &filter)
}
if filter.Limit < 0 {
// this is a special situation through which the implementor signals to us that it doesn't want
// to event perform any queries whatsoever
if filter.LimitZero {
// don't do any queries, just subscribe to future events
return nil
}
@@ -29,7 +28,6 @@ func (rl *Relay) handleRequest(ctx context.Context, id string, eose *sync.WaitGr
// filter we can just reject it)
for _, reject := range rl.RejectFilter {
if reject, msg := reject(ctx, filter); reject {
ws.WriteJSON(nostr.NoticeEnvelope(msg))
return errors.New(nostr.NormalizeOKMessage(msg, "blocked"))
}
}