Compare commits

..

1 Commits

Author SHA1 Message Date
fiatjaf
86d2fec964 add author tag.
fixes https://github.com/fiatjaf/khatru/issues/2
2023-11-18 23:20:41 -03:00
6 changed files with 20 additions and 32 deletions

View File

@@ -1,5 +1,7 @@
# khatru, a relay framework [![docs badge](https://img.shields.io/badge/docs-reference-blue)](https://pkg.go.dev/github.com/fiatjaf/khatru#Relay) # khatru, a relay framework [![docs badge](https://img.shields.io/badge/docs-reference-blue)](https://pkg.go.dev/github.com/fiatjaf/khatru#Relay)
`author: pablof7z`
[![Run Tests](https://github.com/fiatjaf/khatru/actions/workflows/test.yml/badge.svg)](https://github.com/fiatjaf/khatru/actions/workflows/test.yml) [![Run Tests](https://github.com/fiatjaf/khatru/actions/workflows/test.yml/badge.svg)](https://github.com/fiatjaf/khatru/actions/workflows/test.yml)
[![Go Reference](https://pkg.go.dev/badge/github.com/fiatjaf/khatru.svg)](https://pkg.go.dev/github.com/fiatjaf/khatru) [![Go Reference](https://pkg.go.dev/badge/github.com/fiatjaf/khatru.svg)](https://pkg.go.dev/github.com/fiatjaf/khatru)
[![Go Report Card](https://goreportcard.com/badge/github.com/fiatjaf/khatru)](https://goreportcard.com/report/github.com/fiatjaf/khatru) [![Go Report Card](https://goreportcard.com/badge/github.com/fiatjaf/khatru)](https://goreportcard.com/report/github.com/fiatjaf/khatru)
@@ -34,7 +36,7 @@ func main() {
relay.Info.Name = "my relay" relay.Info.Name = "my relay"
relay.Info.PubKey = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" relay.Info.PubKey = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
relay.Info.Description = "this is my custom relay" relay.Info.Description = "this is my custom relay"
relay.Info.Icon = "https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fliquipedia.net%2Fcommons%2Fimages%2F3%2F35%2FSCProbe.jpg&f=1&nofb=1&ipt=0cbbfef25bce41da63d910e86c3c343e6c3b9d63194ca9755351bb7c2efa3359&ipo=images" relay.Info.IconURL = "https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fliquipedia.net%2Fcommons%2Fimages%2F3%2F35%2FSCProbe.jpg&f=1&nofb=1&ipt=0cbbfef25bce41da63d910e86c3c343e6c3b9d63194ca9755351bb7c2efa3359&ipo=images"
// you must bring your own storage scheme -- if you want to have any // you must bring your own storage scheme -- if you want to have any
store := make(map[string]*nostr.Event, 120) store := make(map[string]*nostr.Event, 120)

View File

@@ -14,7 +14,6 @@ import (
"github.com/fasthttp/websocket" "github.com/fasthttp/websocket"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip42" "github.com/nbd-wtf/go-nostr/nip42"
"github.com/rs/cors"
) )
// ServeHTTP implements http.Handler interface. // ServeHTTP implements http.Handler interface.
@@ -22,7 +21,7 @@ func (rl *Relay) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Upgrade") == "websocket" { if r.Header.Get("Upgrade") == "websocket" {
rl.HandleWebsocket(w, r) rl.HandleWebsocket(w, r)
} else if r.Header.Get("Accept") == "application/nostr+json" { } else if r.Header.Get("Accept") == "application/nostr+json" {
cors.AllowAll().Handler(http.HandlerFunc(rl.HandleNIP11)).ServeHTTP(w, r) rl.HandleNIP11(w, r)
} else { } else {
rl.serveMux.ServeHTTP(w, r) rl.serveMux.ServeHTTP(w, r)
} }
@@ -49,8 +48,6 @@ func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
WaitingForAuth: make(chan struct{}), WaitingForAuth: make(chan struct{}),
} }
ctx = context.WithValue(ctx, WS_KEY, ws)
// reader // reader
go func() { go func() {
defer func() { defer func() {
@@ -78,7 +75,6 @@ func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
if err != nil { if err != nil {
if websocket.IsUnexpectedCloseError( if websocket.IsUnexpectedCloseError(
err, err,
websocket.CloseNormalClosure, // 1000
websocket.CloseGoingAway, // 1001 websocket.CloseGoingAway, // 1001
websocket.CloseNoStatusReceived, // 1005 websocket.CloseNoStatusReceived, // 1005
websocket.CloseAbnormalClosure, // 1006 websocket.CloseAbnormalClosure, // 1006
@@ -119,15 +115,14 @@ func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
return return
} }
// check id // check serialization
hash := sha256.Sum256(evt.Serialize()) serialized := evt.Serialize()
id := hex.EncodeToString(hash[:])
if id != evt.ID {
ws.WriteJSON(nostr.OKEnvelope{EventID: evt.ID, OK: false, Reason: "invalid: id is computed incorrectly"})
return
}
// check signature // assign ID
hash := sha256.Sum256(serialized)
evt.ID = hex.EncodeToString(hash[:])
// check signature (requires the ID to be set)
if ok, err := evt.CheckSignature(); err != nil { if ok, err := evt.CheckSignature(); err != nil {
ws.WriteJSON(nostr.OKEnvelope{EventID: evt.ID, OK: false, Reason: "error: failed to verify signature"}) ws.WriteJSON(nostr.OKEnvelope{EventID: evt.ID, OK: false, Reason: "error: failed to verify signature"})
return return

View File

@@ -1,4 +1,4 @@
package policies package plugins
import ( import (
"context" "context"
@@ -64,7 +64,9 @@ func PreventLargeTags(maxTagValueLen int) func(context.Context, *nostr.Event) (b
func RestrictToSpecifiedKinds(kinds ...uint16) func(context.Context, *nostr.Event) (bool, string) { func RestrictToSpecifiedKinds(kinds ...uint16) func(context.Context, *nostr.Event) (bool, string) {
max := 0 max := 0
min := 0 min := 0
allowed := make(map[uint16]struct{}, len(kinds))
for _, kind := range kinds { for _, kind := range kinds {
allowed[kind] = struct{}{}
if int(kind) > max { if int(kind) > max {
max = int(kind) max = int(kind)
} }
@@ -84,7 +86,7 @@ func RestrictToSpecifiedKinds(kinds ...uint16) func(context.Context, *nostr.Even
} }
// hopefully this map of uint16s is very fast // hopefully this map of uint16s is very fast
if _, allowed := slices.BinarySearch(kinds, uint16(event.Kind)); allowed { if _, allowed := allowed[uint16(event.Kind)]; allowed {
return false, "" return false, ""
} }
return true, "event kind not allowed" return true, "event kind not allowed"

View File

@@ -1,4 +1,4 @@
package policies package plugins
import ( import (
"context" "context"
@@ -7,7 +7,6 @@ import (
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
// NoComplexFilters disallows filters with more than 2 tags.
func NoComplexFilters(ctx context.Context, filter nostr.Filter) (reject bool, msg string) { func NoComplexFilters(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
items := len(filter.Tags) + len(filter.Kinds) items := len(filter.Tags) + len(filter.Kinds)
@@ -18,7 +17,6 @@ func NoComplexFilters(ctx context.Context, filter nostr.Filter) (reject bool, ms
return false, "" return false, ""
} }
// NoEmptyFilters disallows filters that don't have at least a tag, a kind, an author or an id.
func NoEmptyFilters(ctx context.Context, filter nostr.Filter) (reject bool, msg string) { func NoEmptyFilters(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
c := len(filter.Kinds) + len(filter.IDs) + len(filter.Authors) c := len(filter.Kinds) + len(filter.IDs) + len(filter.Authors)
for _, tagItems := range filter.Tags { for _, tagItems := range filter.Tags {
@@ -30,13 +28,6 @@ func NoEmptyFilters(ctx context.Context, filter nostr.Filter) (reject bool, msg
return false, "" return false, ""
} }
// AntiSyncBots tries to prevent people from syncing kind:1s from this relay to else by always
// requiring an author parameter at least.
func AntiSyncBots(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
return (len(filter.Kinds) == 0 || slices.Contains(filter.Kinds, 1)) &&
len(filter.Authors) == 0, "an author must be specified to get their kind:1 notes"
}
func NoSearchQueries(ctx context.Context, filter nostr.Filter) (reject bool, msg string) { func NoSearchQueries(ctx context.Context, filter nostr.Filter) (reject bool, msg string) {
if filter.Search != "" { if filter.Search != "" {
return true, "search is not supported" return true, "search is not supported"

View File

@@ -1,4 +1,4 @@
package policies package plugins
import ( import (
"context" "context"
@@ -8,8 +8,7 @@ import (
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
// RejectKind04Snoopers prevents reading NIP-04 messages from people not involved in the conversation. func rejectKind04Snoopers(ctx context.Context, filter nostr.Filter) (bool, string) {
func RejectKind04Snoopers(ctx context.Context, filter nostr.Filter) (bool, string) {
// prevent kind-4 events from being returned to unauthed users, // prevent kind-4 events from being returned to unauthed users,
// only when authentication is a thing // only when authentication is a thing
if !slices.Contains(filter.Kinds, 4) { if !slices.Contains(filter.Kinds, 4) {

View File

@@ -18,9 +18,8 @@ func NewRelay() *Relay {
Log: log.New(os.Stderr, "[khatru-relay] ", log.LstdFlags), Log: log.New(os.Stderr, "[khatru-relay] ", log.LstdFlags),
Info: &nip11.RelayInformationDocument{ Info: &nip11.RelayInformationDocument{
Software: "https://github.com/fiatjaf/khatru", Software: "https://github.com/fiatjaf/khatru",
Version: "n/a", Version: "n/a",
SupportedNIPs: make([]int, 0),
}, },
upgrader: websocket.Upgrader{ upgrader: websocket.Upgrader{