From 805003b39b5d226cfe0ac2c29a977447d4e1d1c4 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Mon, 15 Sep 2025 08:27:29 -0300 Subject: [PATCH] khatru: fix policy that requires nostr-prefix references. --- go.mod | 5 +---- go.sum | 4 ---- khatru/policies/events.go | 43 +++++++++++++++++++++++---------------- sdk/utils.go | 25 +++++++++++++++++++++++ 4 files changed, 51 insertions(+), 26 deletions(-) diff --git a/go.mod b/go.mod index b62f3d3..ac7e771 100644 --- a/go.mod +++ b/go.mod @@ -40,7 +40,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 ) -require github.com/dgraph-io/ristretto v0.2.0 +require github.com/dgraph-io/ristretto/v2 v2.3.0 require ( github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect @@ -64,8 +64,6 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/crypto/blake256 v1.1.0 // indirect - github.com/dgraph-io/ristretto/v2 v2.3.0 // indirect - github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect @@ -80,7 +78,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mschoch/smat v0.2.0 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect diff --git a/go.sum b/go.sum index 03ff56d..bbffb96 100644 --- a/go.sum +++ b/go.sum @@ -110,8 +110,6 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeC github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= -github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE= -github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU= github.com/dgraph-io/ristretto/v2 v2.3.0 h1:qTQ38m7oIyd4GAed/QkUZyPFNMnvVWyazGXRwvOt5zk= github.com/dgraph-io/ristretto/v2 v2.3.0/go.mod h1:gpoRV3VzrEY1a9dWAYV6T1U7YzfgttXdd/ZzL1s9OZM= github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= @@ -311,8 +309,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/khatru/policies/events.go b/khatru/policies/events.go index e3b67a4..a42f448 100644 --- a/khatru/policies/events.go +++ b/khatru/policies/events.go @@ -10,7 +10,9 @@ import ( "fiatjaf.com/nostr" "fiatjaf.com/nostr/nip19" + "fiatjaf.com/nostr/nip27" "fiatjaf.com/nostr/nip70" + "fiatjaf.com/nostr/sdk" ) // PreventTooManyIndexableTags returns a function that can be used as a RejectFilter that will reject @@ -114,26 +116,31 @@ func OnlyAllowNIP70ProtectedEvents(ctx context.Context, event nostr.Event) (reje return true, "blocked: we only accept events protected with the nip70 \"-\" tag" } +var nostrReferencesPrefix = regexp.MustCompile(`\b(nevent1|npub1|nprofile1|note1)\w*\b`) + func RejectUnprefixedNostrReferences(ctx context.Context, event nostr.Event) (bool, string) { - pattern := `\b(nevent1|npub1|nprofile1|note1)\w*\b` - re, err := regexp.Compile(pattern) - if err != nil { - // if regex error, allow - return false, "" - } - matches := re.FindAllStringIndex(event.Content, -1) - for _, match := range matches { - start := match[0] - end := match[1] - ref := event.Content[start:end] - _, _, err := nip19.Decode(ref) - if err != nil { - // invalid reference, ignore and allow - continue - } - if start < 6 || event.Content[start-6:start] != "nostr:" { - return true, "references must be prefixed with \"nostr:\"" + content := sdk.GetMainContent(event) + + // only do it for stuff that wasn't parsed as blocks already + // (since those are already good references or URLs) + for block := range nip27.Parse(content) { + if block.Pointer == nil { + matches := nostrReferencesPrefix.FindAllStringIndex(block.Text, -1) + for _, match := range matches { + start := match[0] + end := match[1] + ref := block.Text[start:end] + _, _, err := nip19.Decode(ref) + if err != nil { + // invalid reference, ignore and allow + // (it's probably someone saying something like "oh, write something like npub1foo...") + continue + } + + return true, "references must be prefixed with \"nostr:\"" + } } } + return false, "" } diff --git a/sdk/utils.go b/sdk/utils.go index 8bb3d05..838d53f 100644 --- a/sdk/utils.go +++ b/sdk/utils.go @@ -4,6 +4,9 @@ import ( "math" "strings" "testing" + + "fiatjaf.com/nostr" + "github.com/tidwall/gjson" ) // IsVirtualRelay returns true if the given normalized relay URL shouldn't be considered for outbox-model calculations. @@ -44,3 +47,25 @@ func PerQueryLimitInBatch(totalFilterLimit int, numberOfQueries int) int { ), ) } + +// GetMainContent returns the user-provided text of the event. This is often the "content", but sometimes, +// like on kind:9802 highlights' "comment" tag, it's on a tag. +// for many other events it is nowhere, as the event doesn't contain any user-provided free text. +// (incomplete) +func GetMainContent(event nostr.Event) string { + switch event.Kind { + case 9802: + // for highlights, check if the comment is in the desired language + // only check the quote language if there is no comment + if tag := event.Tags.Find("comment"); tag != nil && len(tag[1]) > 0 { + return tag[1] + } + return "" + case 0: + return gjson.Get(event.Content, "about").Str + case 443, 27235, 22242, 1059, 13: + return "" + default: + return event.Content + } +}