Compare commits

...

5 Commits

Author SHA1 Message Date
fiatjaf
8df7c9d773 NewRelayWithContext() and Close(). 2024-02-19 06:33:49 -03:00
fiatjaf
e174dd6a95 support 1, 11 and 70 on NIP-11 list. 2024-02-13 12:24:06 -03:00
fiatjaf
cd4c25c845 implement NIP-70 ["-"] tag support. 2024-02-13 12:22:15 -03:00
fiatjaf
9b43da0b17 use stdlib "slices". 2024-02-08 16:35:35 -03:00
fiatjaf
e9bcad8614 policies that remove elements from the query should just cancel the query if they remove everything. 2024-02-07 08:38:42 -03:00
10 changed files with 101 additions and 38 deletions

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"net/http"
"github.com/fiatjaf/khatru"
"github.com/fiatjaf/eventstore/elasticsearch"
"github.com/fiatjaf/khatru"
)
func main() {

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"net/http"
"github.com/fiatjaf/khatru"
"github.com/fiatjaf/eventstore/postgresql"
"github.com/fiatjaf/khatru"
)
func main() {

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"net/http"
"github.com/fiatjaf/khatru"
"github.com/fiatjaf/eventstore/sqlite3"
"github.com/fiatjaf/khatru"
)
func main() {

2
go.mod
View File

@@ -9,7 +9,6 @@ require (
github.com/puzpuzpuz/xsync/v3 v3.0.2
github.com/rs/cors v1.7.0
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
)
require (
@@ -51,6 +50,7 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/net v0.18.0 // indirect
golang.org/x/sys v0.14.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect

View File

@@ -134,6 +134,31 @@ func (rl *Relay) HandleWebsocket(w http.ResponseWriter, r *http.Request) {
return
}
// check NIP-70 protected
for _, v := range env.Event.Tags {
if len(v) == 1 && v[0] == "-" {
msg := "must be published by event author"
authed := GetAuthed(ctx)
if authed == "" {
RequestAuth(ctx)
ws.WriteJSON(nostr.OKEnvelope{
EventID: env.Event.ID,
OK: false,
Reason: "auth-required: " + msg,
})
return
}
if authed != env.Event.PubKey {
ws.WriteJSON(nostr.OKEnvelope{
EventID: env.Event.ID,
OK: false,
Reason: "blocked: " + msg,
})
return
}
}
}
var ok bool
var writeErr error
if env.Event.Kind == 5 {
@@ -247,6 +272,7 @@ func (rl *Relay) HandleNIP11(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/nostr+json")
info := *rl.Info
for _, ovw := range rl.OverwriteRelayInformation {
info = ovw(r.Context(), r, info)
}

View File

@@ -3,8 +3,9 @@ package policies
import (
"context"
"slices"
"github.com/nbd-wtf/go-nostr"
"golang.org/x/exp/slices"
)
// PreventTooManyIndexableTags returns a function that can be used as a RejectFilter that will reject

View File

@@ -3,8 +3,9 @@ package policies
import (
"context"
"slices"
"github.com/nbd-wtf/go-nostr"
"golang.org/x/exp/slices"
)
// NoComplexFilters disallows filters with more than 2 tags.
@@ -45,7 +46,10 @@ func NoSearchQueries(ctx context.Context, filter nostr.Filter) (reject bool, msg
}
func RemoveSearchQueries(ctx context.Context, filter *nostr.Filter) {
filter.Search = ""
if filter.Search != "" {
filter.Search = ""
filter.Limit = -1 // signals that this query should be just skipped
}
}
func RemoveAllButKinds(kinds ...uint16) func(context.Context, *nostr.Filter) {
@@ -58,15 +62,23 @@ 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
}
}
}
}
func RemoveAllButTags(tagNames ...string) func(context.Context, *nostr.Filter) {
return func(ctx context.Context, filter *nostr.Filter) {
for tagName := range filter.Tags {
if !slices.Contains(tagNames, tagName) {
delete(filter.Tags, tagName)
if n := len(filter.Tags); n > 0 {
for tagName := range filter.Tags {
if !slices.Contains(tagNames, tagName) {
delete(filter.Tags, tagName)
}
}
if len(filter.Tags) == 0 {
filter.Limit = -1 // signals that this query should be just skipped
}
}
}

View File

@@ -3,9 +3,10 @@ package policies
import (
"context"
"slices"
"github.com/fiatjaf/khatru"
"github.com/nbd-wtf/go-nostr"
"golang.org/x/exp/slices"
)
// RejectKind04Snoopers prevents reading NIP-04 messages from people not involved in the conversation.

View File

@@ -2,6 +2,7 @@ package khatru
import (
"context"
"fmt"
"log"
"net/http"
"os"
@@ -13,32 +14,6 @@ import (
"github.com/puzpuzpuz/xsync/v3"
)
func NewRelay() *Relay {
return &Relay{
Log: log.New(os.Stderr, "[khatru-relay] ", log.LstdFlags),
Info: &nip11.RelayInformationDocument{
Software: "https://github.com/fiatjaf/khatru",
Version: "n/a",
SupportedNIPs: make([]int, 0),
},
upgrader: websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
},
clients: xsync.NewMapOf[*websocket.Conn, struct{}](),
serveMux: &http.ServeMux{},
WriteWait: 10 * time.Second,
PongWait: 60 * time.Second,
PingPeriod: 30 * time.Second,
MaxMessageSize: 512000,
}
}
type Relay struct {
ServiceURL string
@@ -59,7 +34,7 @@ type Relay struct {
OnEventSaved []func(ctx context.Context, event *nostr.Event)
OnEphemeralEvent []func(ctx context.Context, event *nostr.Event)
// editing info will affect
// editing info will affect the responses to the NIP-11 endpoint
Info *nip11.RelayInformationDocument
// Default logger, as set by NewServer, is a stdlib logger prefixed with "[khatru-relay] ",
@@ -82,4 +57,49 @@ type Relay struct {
PongWait time.Duration // Time allowed to read the next pong message from the peer.
PingPeriod time.Duration // Send pings to peer with this period. Must be less than pongWait.
MaxMessageSize int64 // Maximum message size allowed from peer.
// this context is used for all things inside the relay
Context context.Context
cancel context.CancelCauseFunc
}
func NewRelay() *Relay {
return NewRelayWithContext(context.Background())
}
func NewRelayWithContext(ctx context.Context) *Relay {
ctx, cancel := context.WithCancelCause(ctx)
rl := &Relay{
Log: log.New(os.Stderr, "[khatru-relay] ", log.LstdFlags),
Info: &nip11.RelayInformationDocument{
Software: "https://github.com/fiatjaf/khatru",
Version: "n/a",
SupportedNIPs: []int{1, 11, 70},
},
upgrader: websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
},
clients: xsync.NewMapOf[*websocket.Conn, struct{}](),
serveMux: &http.ServeMux{},
WriteWait: 10 * time.Second,
PongWait: 60 * time.Second,
PingPeriod: 30 * time.Second,
MaxMessageSize: 512000,
Context: ctx,
cancel: cancel,
}
return rl
}
func (rl *Relay) Close() {
rl.cancel(fmt.Errorf("Close called"))
}

View File

@@ -2,6 +2,7 @@ package khatru
import (
"context"
"fmt"
"net"
"net/http"
"strconv"
@@ -48,6 +49,8 @@ func (rl *Relay) Start(host string, port int, started ...chan bool) error {
// Shutdown sends a websocket close control message to all connected clients.
func (rl *Relay) Shutdown(ctx context.Context) {
rl.cancel(fmt.Errorf("Shutdown called"))
rl.httpServer.Shutdown(ctx)
rl.clients.Range(func(conn *websocket.Conn, _ struct{}) bool {