flatten relay interface

This commit is contained in:
2025-04-22 17:54:09 -01:06
parent fda2f638fb
commit 399e166927
13 changed files with 114 additions and 256 deletions

View File

@@ -18,7 +18,6 @@ import (
"realy.mleku.dev/kind" "realy.mleku.dev/kind"
"realy.mleku.dev/log" "realy.mleku.dev/log"
"realy.mleku.dev/realy/helpers" "realy.mleku.dev/realy/helpers"
"realy.mleku.dev/relay"
"realy.mleku.dev/sha256" "realy.mleku.dev/sha256"
"realy.mleku.dev/tag" "realy.mleku.dev/tag"
) )
@@ -32,7 +31,7 @@ type EventInput struct {
// EventOutput is the return parameters for the HTTP API Event method. // EventOutput is the return parameters for the HTTP API Event method.
type EventOutput struct{ Body string } type EventOutput struct{ Body string }
// RegisterEvent is the implementatino of the HTTP API Event method. // RegisterEvent is the implementation of the HTTP API Event method.
func (x *Operations) RegisterEvent(api huma.API) { func (x *Operations) RegisterEvent(api huma.API) {
name := "Event" name := "Event"
description := "Submit an event" description := "Submit an event"
@@ -61,7 +60,6 @@ func (x *Operations) RegisterEvent(api huma.API) {
if sto == nil { if sto == nil {
panic("no event store has been set to store event") panic("no event store has been set to store event")
} }
advancedDeleter, _ := sto.(relay.AdvancedDeleter)
var valid bool var valid bool
var pubkey []byte var pubkey []byte
valid, pubkey, err = httpauth.CheckAuth(r) valid, pubkey, err = httpauth.CheckAuth(r)
@@ -189,16 +187,10 @@ func (x *Operations) RegisterEvent(api huma.API) {
err = huma.Error403Forbidden("only author can delete event") err = huma.Error403Forbidden("only author can delete event")
return return
} }
if advancedDeleter != nil {
advancedDeleter.BeforeDelete(ctx, t.Value(), ev.Pubkey)
}
if err = sto.DeleteEvent(ctx, target.EventId()); chk.T(err) { if err = sto.DeleteEvent(ctx, target.EventId()); chk.T(err) {
err = huma.Error500InternalServerError(err.Error()) err = huma.Error500InternalServerError(err.Error())
return return
} }
if advancedDeleter != nil {
advancedDeleter.AfterDelete(t.Value(), ev.Pubkey)
}
} }
res = nil res = nil
} }

View File

@@ -20,7 +20,6 @@ import (
"realy.mleku.dev/kinds" "realy.mleku.dev/kinds"
"realy.mleku.dev/log" "realy.mleku.dev/log"
"realy.mleku.dev/realy/helpers" "realy.mleku.dev/realy/helpers"
"realy.mleku.dev/relay"
"realy.mleku.dev/store" "realy.mleku.dev/store"
"realy.mleku.dev/tag" "realy.mleku.dev/tag"
"realy.mleku.dev/tags" "realy.mleku.dev/tags"
@@ -128,23 +127,21 @@ func (x *Operations) RegisterFilter(api huma.API) {
return return
} }
allowed := filters.New(f) allowed := filters.New(f)
if accepter, ok := x.Relay().(relay.ReqAcceptor); ok { var accepted, modified bool
var accepted, modified bool allowed, accepted, modified = x.Relay().AcceptReq(x.Context(), r, nil,
allowed, accepted, modified = accepter.AcceptReq(x.Context(), r, nil, filters.New(f), pubkey)
filters.New(f), pubkey) if !accepted {
if !accepted { err = huma.Error401Unauthorized("auth to get access for this filter")
err = huma.Error401Unauthorized("auth to get access for this filter") return
return } else if modified {
} else if modified { log.D.F("filter modified %s", allowed.F[0])
log.D.F("filter modified %s", allowed.F[0])
}
} }
if len(allowed.F) == 0 { if len(allowed.F) == 0 {
err = huma.Error401Unauthorized("all kinds in event restricted; auth to get access for this filter") err = huma.Error401Unauthorized("all kinds in event restricted; auth to get access for this filter")
return return
} }
if f.Kinds.IsPrivileged() { if f.Kinds.IsPrivileged() {
if auther, ok := x.Relay().(relay.Authenticator); ok && auther.AuthRequired() { if x.Relay().AuthRequired() {
log.T.F("privileged request\n%s", f.Serialize()) log.T.F("privileged request\n%s", f.Serialize())
senders := f.Authors senders := f.Authors
receivers := f.Tags.GetAll(tag.New("#p")) receivers := f.Tags.GetAll(tag.New("#p"))

View File

@@ -13,7 +13,6 @@ import (
"realy.mleku.dev/httpauth" "realy.mleku.dev/httpauth"
"realy.mleku.dev/log" "realy.mleku.dev/log"
"realy.mleku.dev/realy/helpers" "realy.mleku.dev/realy/helpers"
"realy.mleku.dev/relay"
) )
// RelayInput is the parameters for the Event HTTP API method. // RelayInput is the parameters for the Event HTTP API method.
@@ -83,12 +82,7 @@ func (x *Operations) RegisterRelay(api huma.API) {
err = huma.Error400BadRequest("signature is invalid") err = huma.Error400BadRequest("signature is invalid")
return return
} }
var authRequired bool x.Publisher().Deliver(x.Relay().AuthRequired(), x.PublicReadable(), ev)
var ar relay.Authenticator
if ar, ok = x.Relay().(relay.Authenticator); ok {
authRequired = ar.AuthRequired()
}
x.Publisher().Deliver(authRequired, x.PublicReadable(), ev)
return return
}) })
} }

View File

@@ -19,7 +19,6 @@ import (
"realy.mleku.dev/kinds" "realy.mleku.dev/kinds"
"realy.mleku.dev/log" "realy.mleku.dev/log"
"realy.mleku.dev/realy/helpers" "realy.mleku.dev/realy/helpers"
"realy.mleku.dev/relay"
"realy.mleku.dev/tag" "realy.mleku.dev/tag"
"realy.mleku.dev/tags" "realy.mleku.dev/tags"
) )
@@ -99,24 +98,22 @@ func (x *Operations) RegisterSubscribe(api huma.API) {
return return
} }
allowed := filters.New(f) allowed := filters.New(f)
if accepter, ok := x.Relay().(relay.ReqAcceptor); ok { var accepted, modified bool
var accepted, modified bool allowed, accepted, modified = x.Relay().AcceptReq(x.Context(), r, nil,
allowed, accepted, modified = accepter.AcceptReq(x.Context(), r, nil, filters.New(f),
filters.New(f), pubkey)
pubkey) if !accepted {
if !accepted { err = huma.Error401Unauthorized("auth to get access for this filter")
err = huma.Error401Unauthorized("auth to get access for this filter") return
return } else if modified {
} else if modified { log.D.F("filter modified %s", allowed.F[0])
log.D.F("filter modified %s", allowed.F[0])
}
} }
if len(allowed.F) == 0 { if len(allowed.F) == 0 {
err = huma.Error401Unauthorized("all kinds in event restricted; auth to get access for this filter") err = huma.Error401Unauthorized("all kinds in event restricted; auth to get access for this filter")
return return
} }
if f.Kinds.IsPrivileged() { if f.Kinds.IsPrivileged() {
if auther, ok := x.Relay().(relay.Authenticator); ok && auther.AuthRequired() { if x.Relay().AuthRequired() {
log.T.F("privileged request\n%s", f.Serialize()) log.T.F("privileged request\n%s", f.Serialize())
senders := f.Authors senders := f.Authors
receivers := f.Tags.GetAll(tag.New("#p")) receivers := f.Tags.GetAll(tag.New("#p"))

View File

@@ -23,8 +23,6 @@ func (s *Server) addEvent(c context.T, rl relay.I, ev *event.T,
if ev == nil { if ev == nil {
return false, normalize.Invalid.F("empty event") return false, normalize.Invalid.F("empty event")
} }
sto := rl.Storage()
advancedSaver, _ := sto.(relay.AdvancedSaver)
// don't allow storing event with protected marker as per nip-70 with auth enabled. // don't allow storing event with protected marker as per nip-70 with auth enabled.
if (s.authRequired || !s.publicReadable) && ev.Tags.ContainsProtectedMarker() { if (s.authRequired || !s.publicReadable) && ev.Tags.ContainsProtectedMarker() {
if len(authedPubkey) == 0 || !bytes.Equal(ev.Pubkey, authedPubkey) { if len(authedPubkey) == 0 || !bytes.Equal(ev.Pubkey, authedPubkey) {
@@ -36,9 +34,6 @@ func (s *Server) addEvent(c context.T, rl relay.I, ev *event.T,
} }
if ev.Kind.IsEphemeral() { if ev.Kind.IsEphemeral() {
} else { } else {
if advancedSaver != nil {
advancedSaver.BeforeSave(c, ev)
}
if saveErr := s.Publish(c, ev); saveErr != nil { if saveErr := s.Publish(c, ev); saveErr != nil {
if errors.Is(saveErr, store.ErrDupEvent) { if errors.Is(saveErr, store.ErrDupEvent) {
return false, normalize.Error.F(saveErr.Error()) return false, normalize.Error.F(saveErr.Error())
@@ -56,16 +51,10 @@ func (s *Server) addEvent(c context.T, rl relay.I, ev *event.T,
return false, normalize.Error.F("failed to save (%s)", errmsg) return false, normalize.Error.F("failed to save (%s)", errmsg)
} }
} }
if advancedSaver != nil {
advancedSaver.AfterSave(ev)
}
}
var authRequired bool
if ar, ok := rl.(relay.Authenticator); ok {
authRequired = ar.AuthRequired()
} }
rl.AuthRequired()
// notify subscribers // notify subscribers
s.listeners.Deliver(authRequired, s.publicReadable, ev) s.listeners.Deliver(rl.AuthRequired(), s.publicReadable, ev)
accepted = true accepted = true
log.I.F("event id %0x stored", ev.Id) log.I.F("event id %0x stored", ev.Id)
return return

View File

@@ -8,54 +8,41 @@ import (
"realy.mleku.dev" "realy.mleku.dev"
"realy.mleku.dev/chk" "realy.mleku.dev/chk"
"realy.mleku.dev/log" "realy.mleku.dev/log"
"realy.mleku.dev/relay"
"realy.mleku.dev/relayinfo" "realy.mleku.dev/relayinfo"
"realy.mleku.dev/store"
) )
func (s *Server) handleRelayInfo(w http.ResponseWriter, r *http.Request) { func (s *Server) handleRelayInfo(w http.ResponseWriter, r *http.Request) {
r.Header.Set("Content-Type", "application/json") r.Header.Set("Content-Type", "application/json")
log.I.Ln("handling relay information document") log.I.Ln("handling relay information document")
var info *relayinfo.T var info *relayinfo.T
if informationer, ok := s.relay.(relay.Informationer); ok { supportedNIPs := relayinfo.GetList(
info = informationer.GetNIP11InformationDocument() relayinfo.BasicProtocol,
} else { relayinfo.EncryptedDirectMessage,
supportedNIPs := relayinfo.GetList( relayinfo.EventDeletion,
relayinfo.BasicProtocol, relayinfo.RelayInformationDocument,
relayinfo.EncryptedDirectMessage, relayinfo.GenericTagQueries,
relayinfo.EventDeletion, relayinfo.NostrMarketplace,
relayinfo.RelayInformationDocument, relayinfo.EventTreatment,
relayinfo.GenericTagQueries, relayinfo.CommandResults,
relayinfo.NostrMarketplace, relayinfo.ParameterizedReplaceableEvents,
relayinfo.EventTreatment, relayinfo.ExpirationTimestamp,
relayinfo.CommandResults, relayinfo.ProtectedEvents,
relayinfo.ParameterizedReplaceableEvents, relayinfo.RelayListMetadata,
relayinfo.ExpirationTimestamp, )
relayinfo.ProtectedEvents, if s.relay.ServiceUrl(r) != "" {
relayinfo.RelayListMetadata, supportedNIPs = append(supportedNIPs, relayinfo.Authentication.N())
)
var auther relay.Authenticator
if auther, ok = s.relay.(relay.Authenticator); ok && auther.ServiceUrl(r) != "" {
supportedNIPs = append(supportedNIPs, relayinfo.Authentication.N())
}
var storage store.I
if storage = s.relay.Storage(); storage != nil {
if _, ok = storage.(relay.EventCounter); ok {
supportedNIPs = append(supportedNIPs, relayinfo.CountingResults.N())
}
}
sort.Sort(supportedNIPs)
log.T.Ln("supported NIPs", supportedNIPs)
info = &relayinfo.T{Name: s.relay.Name(),
Description: realy_lol.Description,
Nips: supportedNIPs, Software: realy_lol.URL, Version: realy_lol.Version,
Limitation: relayinfo.Limits{
MaxLimit: s.maxLimit,
AuthRequired: s.authRequired,
RestrictedWrites: !s.publicReadable || s.authRequired || len(s.owners) > 0,
},
Icon: "https://cdn.satellite.earth/ac9778868fbf23b63c47c769a74e163377e6ea94d3f0f31711931663d035c4f6.png"}
} }
sort.Sort(supportedNIPs)
log.T.Ln("supported NIPs", supportedNIPs)
info = &relayinfo.T{Name: s.relay.Name(),
Description: realy_lol.Description,
Nips: supportedNIPs, Software: realy_lol.URL, Version: realy_lol.Version,
Limitation: relayinfo.Limits{
MaxLimit: s.maxLimit,
AuthRequired: s.authRequired,
RestrictedWrites: !s.publicReadable || s.authRequired || len(s.owners) > 0,
},
Icon: "https://cdn.satellite.earth/ac9778868fbf23b63c47c769a74e163377e6ea94d3f0f31711931663d035c4f6.png"}
if err := json.NewEncoder(w).Encode(info); chk.E(err) { if err := json.NewEncoder(w).Encode(info); chk.E(err) {
} }
} }

View File

@@ -66,10 +66,6 @@ func NewServer(sp *ServerParams, opts ...options.O) (s *Server, err error) {
for _, opt := range opts { for _, opt := range opts {
opt(op) opt(op)
} }
var authRequired bool
if ar, ok := sp.Rl.(relay.Authenticator); ok {
authRequired = ar.AuthRequired()
}
if storage := sp.Rl.Storage(); storage != nil { if storage := sp.Rl.Storage(); storage != nil {
if err := storage.Init(sp.DbPath); chk.T(err) { if err := storage.Init(sp.DbPath); chk.T(err) {
return nil, fmt.Errorf("storage init: %w", err) return nil, fmt.Errorf("storage init: %w", err)
@@ -83,7 +79,7 @@ func NewServer(sp *ServerParams, opts ...options.O) (s *Server, err error) {
clients: make(map[*websocket.Conn]struct{}), clients: make(map[*websocket.Conn]struct{}),
mux: serveMux, mux: serveMux,
options: op, options: op,
authRequired: authRequired, authRequired: sp.Rl.AuthRequired(),
publicReadable: sp.PublicReadable, publicReadable: sp.PublicReadable,
maxLimit: sp.MaxLimit, maxLimit: sp.MaxLimit,
admins: sp.Admins, admins: sp.Admins,
@@ -108,13 +104,6 @@ func NewServer(sp *ServerParams, opts ...options.O) (s *Server, err error) {
s.Shutdown() s.Shutdown()
} }
}() }()
if inj, ok := s.relay.(relay.Injector); ok {
go func() {
for ev := range inj.InjectEvents() {
s.listeners.Deliver(s.authRequired, s.publicReadable, ev)
}
}()
}
return s, nil return s, nil
} }
@@ -173,9 +162,6 @@ func (s *Server) Shutdown() {
chk.E(s.relay.Storage().Close()) chk.E(s.relay.Storage().Close())
log.W.Ln("shutting down relay listener") log.W.Ln("shutting down relay listener")
chk.E(s.httpServer.Shutdown(s.Ctx)) chk.E(s.httpServer.Shutdown(s.Ctx))
if f, ok := s.relay.(relay.ShutdownAware); ok {
f.OnShutdown(s.Ctx)
}
} }
// Router returns the servemux that handles paths on the HTTP server of the relay. // Router returns the servemux that handles paths on the HTTP server of the relay.

View File

@@ -9,6 +9,7 @@ import (
"realy.mleku.dev/event" "realy.mleku.dev/event"
"realy.mleku.dev/eventid" "realy.mleku.dev/eventid"
"realy.mleku.dev/filter" "realy.mleku.dev/filter"
"realy.mleku.dev/filters"
"realy.mleku.dev/store" "realy.mleku.dev/store"
"realy.mleku.dev/units" "realy.mleku.dev/units"
) )
@@ -68,6 +69,25 @@ func (tr *testRelay) AcceptEvent(c context.T, evt *event.T, hr *http.Request, or
return true, "", nil return true, "", nil
} }
func (tr *testRelay) AcceptReq(c context.T, hr *http.Request, id []byte,
ff *filters.T, authedPubkey []byte) (allowed *filters.T, ok bool, modified bool) {
// TODO implement me
panic("implement me")
}
func (tr *testRelay) AcceptFilter(c context.T, hr *http.Request, f *filter.S,
authedPubkey []byte) (allowed *filter.S, ok bool, modified bool) {
// TODO implement me
panic("implement me")
}
func (tr *testRelay) AuthRequired() bool {
// TODO implement me
panic("implement me")
}
func (tr *testRelay) ServiceUrl(req *http.Request) (s string) {
// TODO implement me
panic("implement me")
}
type testStorage struct { type testStorage struct {
init func() error init func() error
close func() close func()
@@ -136,10 +156,3 @@ func (string *testStorage) SaveEvent(c context.T, e *event.T) error {
} }
return nil return nil
} }
func (string *testStorage) CountEvents(c context.T, f *filter.T) (int, bool, error) {
if fn := string.countEvents; fn != nil {
return fn(c, f)
}
return 0, false, nil
}

View File

@@ -9,9 +9,7 @@ import (
"realy.mleku.dev/event" "realy.mleku.dev/event"
"realy.mleku.dev/filter" "realy.mleku.dev/filter"
"realy.mleku.dev/filters" "realy.mleku.dev/filters"
"realy.mleku.dev/relayinfo"
"realy.mleku.dev/store" "realy.mleku.dev/store"
"realy.mleku.dev/ws"
) )
// I is the main interface for implementing a nostr relay. // I is the main interface for implementing a nostr relay.
@@ -41,10 +39,6 @@ type I interface {
Storage() store.I Storage() store.I
// Owners returns the list of pubkeys designated as owners of the relay. // Owners returns the list of pubkeys designated as owners of the relay.
Owners() [][]byte Owners() [][]byte
}
// ReqAcceptor is the main interface for implementing a nostr
type ReqAcceptor interface {
// AcceptReq is called for every nostr request filters received by the // AcceptReq is called for every nostr request filters received by the
// server. If the returned value is true, the filters is passed on to // server. If the returned value is true, the filters is passed on to
// [Storage.QueryEvent]. // [Storage.QueryEvent].
@@ -58,70 +52,13 @@ type ReqAcceptor interface {
// request is for a message that contains their npub in a `p` tag that are // request is for a message that contains their npub in a `p` tag that are
// direct or group chat messages they also can be accepted, enabling full // direct or group chat messages they also can be accepted, enabling full
// support for in/outbox access. // support for in/outbox access.
//
// In order to support the ability to respond to
AcceptReq(c context.T, hr *http.Request, id []byte, ff *filters.T, AcceptReq(c context.T, hr *http.Request, id []byte, ff *filters.T,
authedPubkey []byte) (allowed *filters.T, authedPubkey []byte) (allowed *filters.T,
ok bool, modified bool) ok bool, modified bool)
}
type FilterAcceptor interface {
// AcceptFilter is basically the same as AcceptReq except it is additional to // AcceptFilter is basically the same as AcceptReq except it is additional to
// enable the simplified filter query type. // enable the simplified filter query type.
AcceptFilter(c context.T, hr *http.Request, f *filter.S, AcceptFilter(c context.T, hr *http.Request, f *filter.S,
authedPubkey []byte) (allowed *filter.S, ok bool, modified bool) authedPubkey []byte) (allowed *filter.S, ok bool, modified bool)
}
// Authenticator is the interface for implementing NIP-42.
// ServiceURL() returns the URL used to verify the "AUTH" event from clients.
type Authenticator interface {
AuthRequired() bool AuthRequired() bool
ServiceUrl(r *http.Request) string ServiceUrl(r *http.Request) string
} }
type Injector interface {
InjectEvents() event.C
}
// Informationer is called to compose NIP-11 response to an HTTP request
// with application/nostr+json mime type.
// See also [I.Name].
type Informationer interface {
GetNIP11InformationDocument() *relayinfo.T
}
// WebSocketHandler is passed nostr message types unrecognized by the
// server. The server handles "EVENT", "REQ" and "CLOSE" messages, as described in NIP-01.
type WebSocketHandler interface {
HandleUnknownType(ws *ws.Listener, t string, request []byte)
}
// ShutdownAware is called during the server shutdown.
// See [Server.Shutdown] for details.
type ShutdownAware interface {
OnShutdown(context.T)
}
// Logger is what [Server] uses to log messages.
type Logger interface {
Infof(format string, v ...any)
Warningf(format string, v ...any)
Errorf(format string, v ...any)
}
// AdvancedDeleter methods are called before and after [Storage.DeleteEvent].
type AdvancedDeleter interface {
BeforeDelete(ctx context.T, id, pubkey []byte)
AfterDelete(id, pubkey []byte)
}
// AdvancedSaver methods are called before and after [Storage.SaveEvent].
type AdvancedSaver interface {
BeforeSave(context.T, *event.T)
AfterSave(*event.T)
}
// EventCounter implements the NIP-45 count API.
type EventCounter interface {
CountEvents(c context.T, f *filter.T) (count int, approx bool, err error)
}

View File

@@ -8,14 +8,13 @@ import (
"realy.mleku.dev/log" "realy.mleku.dev/log"
"realy.mleku.dev/normalize" "realy.mleku.dev/normalize"
"realy.mleku.dev/realy/interfaces" "realy.mleku.dev/realy/interfaces"
"realy.mleku.dev/relay"
) )
func (a *A) HandleAuth(req []byte, func (a *A) HandleAuth(req []byte,
srv interfaces.Server) (msg []byte) { srv interfaces.Server) (msg []byte) {
if auther, ok := srv.Relay().(relay.Authenticator); ok && auther.AuthRequired() { if srv.Relay().AuthRequired() {
svcUrl := auther.ServiceUrl(a.Req()) svcUrl := srv.Relay().ServiceUrl(a.Req())
if svcUrl == "" { if svcUrl == "" {
return return
} }

View File

@@ -17,7 +17,6 @@ import (
"realy.mleku.dev/log" "realy.mleku.dev/log"
"realy.mleku.dev/normalize" "realy.mleku.dev/normalize"
"realy.mleku.dev/realy/interfaces" "realy.mleku.dev/realy/interfaces"
"realy.mleku.dev/relay"
"realy.mleku.dev/sha256" "realy.mleku.dev/sha256"
"realy.mleku.dev/tag" "realy.mleku.dev/tag"
) )
@@ -32,11 +31,7 @@ func (a *A) HandleEvent(c context.T, req []byte, srv interfaces.Server) (msg []b
if sto == nil { if sto == nil {
panic("no event store has been set to store event") panic("no event store has been set to store event")
} }
var auther relay.Authenticator
if auther, ok = srv.Relay().(relay.Authenticator); ok {
}
rl := srv.Relay() rl := srv.Relay()
advancedDeleter, _ := sto.(relay.AdvancedDeleter)
env := eventenvelope.NewSubmission() env := eventenvelope.NewSubmission()
if rem, err = env.Unmarshal(req); chk.E(err) { if rem, err = env.Unmarshal(req); chk.E(err) {
return return
@@ -52,7 +47,7 @@ func (a *A) HandleEvent(c context.T, req []byte, srv interfaces.Server) (msg []b
normalize.Blocked.F(notice)).Write(a.Listener); chk.T(err) { normalize.Blocked.F(notice)).Write(a.Listener); chk.T(err) {
} }
} else { } else {
if auther != nil && auther.AuthRequired() { if rl.AuthRequired() {
if !a.AuthRequested() { if !a.AuthRequested() {
a.RequestAuth() a.RequestAuth()
log.I.F("requesting auth from client %s", a.RealRemote()) log.I.F("requesting auth from client %s", a.RealRemote())
@@ -230,9 +225,6 @@ func (a *A) HandleEvent(c context.T, req []byte, srv interfaces.Server) (msg []b
} }
return return
} }
if advancedDeleter != nil {
advancedDeleter.BeforeDelete(c, t.Value(), env.Pubkey)
}
if err = sto.DeleteEvent(c, target.EventId()); chk.T(err) { if err = sto.DeleteEvent(c, target.EventId()); chk.T(err) {
if err = okenvelope.NewFrom(env.Id, false, if err = okenvelope.NewFrom(env.Id, false,
normalize.Error.F(err.Error())).Write(a.Listener); chk.E(err) { normalize.Error.F(err.Error())).Write(a.Listener); chk.E(err) {
@@ -240,9 +232,6 @@ func (a *A) HandleEvent(c context.T, req []byte, srv interfaces.Server) (msg []b
} }
return return
} }
if advancedDeleter != nil {
advancedDeleter.AfterDelete(t.Value(), env.Pubkey)
}
} }
res = nil res = nil
} }

View File

@@ -11,7 +11,6 @@ import (
"realy.mleku.dev/envelopes/noticeenvelope" "realy.mleku.dev/envelopes/noticeenvelope"
"realy.mleku.dev/envelopes/reqenvelope" "realy.mleku.dev/envelopes/reqenvelope"
"realy.mleku.dev/log" "realy.mleku.dev/log"
"realy.mleku.dev/relay"
) )
func (a *A) HandleMessage(msg []byte) { func (a *A) HandleMessage(msg []byte) {
@@ -22,7 +21,6 @@ func (a *A) HandleMessage(msg []byte) {
if t, rem = envelopes.Identify(msg); chk.E(err) { if t, rem = envelopes.Identify(msg); chk.E(err) {
notice = []byte(err.Error()) notice = []byte(err.Error())
} }
rl := a.Relay()
switch t { switch t {
case eventenvelope.L: case eventenvelope.L:
notice = a.HandleEvent(a.Context(), rem, a.Server) notice = a.HandleEvent(a.Context(), rem, a.Server)
@@ -33,11 +31,7 @@ func (a *A) HandleMessage(msg []byte) {
case authenvelope.L: case authenvelope.L:
notice = a.HandleAuth(rem, a.Server) notice = a.HandleAuth(rem, a.Server)
default: default:
if wsh, ok := rl.(relay.WebSocketHandler); ok { notice = []byte(fmt.Sprintf("unknown envelope type %s\n%s", t, rem))
wsh.HandleUnknownType(a.Listener, t, rem)
} else {
notice = []byte(fmt.Sprintf("unknown envelope type %s\n%s", t, rem))
}
} }
if len(notice) > 0 { if len(notice) > 0 {
log.D.F("notice->%s %s", a.RealRemote(), notice) log.D.F("notice->%s %s", a.RealRemote(), notice)

View File

@@ -23,7 +23,6 @@ import (
"realy.mleku.dev/realy/interfaces" "realy.mleku.dev/realy/interfaces"
"realy.mleku.dev/realy/options" "realy.mleku.dev/realy/options"
"realy.mleku.dev/realy/pointers" "realy.mleku.dev/realy/pointers"
"realy.mleku.dev/relay"
"realy.mleku.dev/tag" "realy.mleku.dev/tag"
) )
@@ -31,13 +30,6 @@ func (a *A) HandleReq(
c context.T, req []byte, c context.T, req []byte,
skipEventFunc options.SkipEventFunc, srv interfaces.Server) (r []byte) { skipEventFunc options.SkipEventFunc, srv interfaces.Server) (r []byte) {
var ok bool
var accepter relay.ReqAcceptor
if accepter, ok = srv.Relay().(relay.ReqAcceptor); ok {
}
var auther relay.Authenticator
if auther, ok = srv.Relay().(relay.Authenticator); ok {
}
sto := srv.Storage() sto := srv.Storage()
var err error var err error
var rem []byte var rem []byte
@@ -49,32 +41,30 @@ func (a *A) HandleReq(
log.I.F("extra '%s'", rem) log.I.F("extra '%s'", rem)
} }
allowed := env.Filters allowed := env.Filters
if accepter != nil { var accepted, modified bool
var accepted, modified bool allowed, accepted, modified = srv.Relay().AcceptReq(c, a.Req(), env.Subscription.T,
allowed, accepted, modified = accepter.AcceptReq(c, a.Req(), env.Subscription.T, env.Filters,
env.Filters, []byte(a.Authed()))
[]byte(a.Authed())) if !accepted || allowed == nil || modified {
if !accepted || allowed == nil || modified { if srv.Relay().AuthRequired() && !a.AuthRequested() {
if auther != nil && auther.AuthRequired() && !a.AuthRequested() { a.RequestAuth()
a.RequestAuth() if err = closedenvelope.NewFrom(env.Subscription,
if err = closedenvelope.NewFrom(env.Subscription, normalize.AuthRequired.F("auth required for request processing")).Write(a.Listener); chk.E(err) {
normalize.AuthRequired.F("auth required for request processing")).Write(a.Listener); chk.E(err) { }
} log.T.F("requesting auth from client from %s, challenge '%s'",
log.T.F("requesting auth from client from %s, challenge '%s'", a.RealRemote(), a.Challenge())
a.RealRemote(), a.Challenge()) if err = authenvelope.NewChallengeWith(a.Challenge()).Write(a.Listener); chk.E(err) {
if err = authenvelope.NewChallengeWith(a.Challenge()).Write(a.Listener); chk.E(err) { return
return }
} if !modified {
if !modified { return
return
}
} }
} }
} }
// log.I.ToSliceOfBytes("handling %s", env.Marshal(nil)) // log.I.ToSliceOfBytes("handling %s", env.Marshal(nil))
if allowed != env.Filters { if allowed != env.Filters {
defer func() { defer func() {
if auther != nil && auther.AuthRequired() && if srv.Relay().AuthRequired() &&
!a.AuthRequested() { !a.AuthRequested() {
a.RequestAuth() a.RequestAuth()
if err = closedenvelope.NewFrom(env.Subscription, if err = closedenvelope.NewFrom(env.Subscription,
@@ -101,7 +91,7 @@ func (a *A) HandleReq(
} }
i = *f.Limit i = *f.Limit
} }
if auther != nil && auther.AuthRequired() { if srv.Relay().AuthRequired() {
if f.Kinds.IsPrivileged() { if f.Kinds.IsPrivileged() {
log.T.F("privileged request\n%s", f.Serialize()) log.T.F("privileged request\n%s", f.Serialize())
senders := f.Authors senders := f.Authors
@@ -177,40 +167,34 @@ func (a *A) HandleReq(
// if auth is required, kind is privileged and there is no authed pubkey, skip // if auth is required, kind is privileged and there is no authed pubkey, skip
if srv.AuthRequired() && ev.Kind.IsPrivileged() && len(aut) == 0 { if srv.AuthRequired() && ev.Kind.IsPrivileged() && len(aut) == 0 {
// log.I.ToSliceOfBytes("skipping event because event kind is %d and no auth", ev.Kind.K) // log.I.ToSliceOfBytes("skipping event because event kind is %d and no auth", ev.Kind.K)
if auther != nil { if err = closedenvelope.NewFrom(env.Subscription,
if err = closedenvelope.NewFrom(env.Subscription, normalize.AuthRequired.F("auth required for processing request due to presence of privileged kinds (DMs, app specific data)")).Write(a.Listener); chk.E(err) {
normalize.AuthRequired.F("auth required for processing request due to presence of privileged kinds (DMs, app specific data)")).Write(a.Listener); chk.E(err) {
}
log.I.F("requesting auth from client from %s", a.RealRemote())
if err = authenvelope.NewChallengeWith(a.Challenge()).Write(a.Listener); chk.E(err) {
return
}
notice := normalize.Restricted.F("this realy does not serve DMs or Application Specific Data " +
"to unauthenticated users or to npubs not found in the event tags or author fields, does your " +
"client implement NIP-42?")
return notice
} }
continue log.I.F("requesting auth from client from %s", a.RealRemote())
if err = authenvelope.NewChallengeWith(a.Challenge()).Write(a.Listener); chk.E(err) {
return
}
notice := normalize.Restricted.F("this realy does not serve DMs or Application Specific Data " +
"to unauthenticated users or to npubs not found in the event tags or author fields, does your " +
"client implement NIP-42?")
return notice
} }
// if the authed pubkey is not present in the pubkey or p tags, skip // if the authed pubkey is not present in the pubkey or p tags, skip
if ev.Kind.IsPrivileged() && (!bytes.Equal(ev.Pubkey, aut) || if ev.Kind.IsPrivileged() && (!bytes.Equal(ev.Pubkey, aut) ||
!receivers.ContainsAny([]byte("#p"), tag.New(a.AuthedBytes()))) { !receivers.ContainsAny([]byte("#p"), tag.New(a.AuthedBytes()))) {
// log.I.ToSliceOfBytes("skipping event %0x because authed key %0x is in neither pubkey or p tag", // log.I.ToSliceOfBytes("skipping event %0x because authed key %0x is in neither pubkey or p tag",
// ev.Id, aut) // ev.Id, aut)
if auther != nil { if err = closedenvelope.NewFrom(env.Subscription,
if err = closedenvelope.NewFrom(env.Subscription, normalize.AuthRequired.F("auth required for processing request due to presence of privileged kinds (DMs, app specific data)")).Write(a.Listener); chk.E(err) {
normalize.AuthRequired.F("auth required for processing request due to presence of privileged kinds (DMs, app specific data)")).Write(a.Listener); chk.E(err) {
}
log.I.F("requesting auth from client from %s", a.RealRemote())
if err = authenvelope.NewChallengeWith(a.Challenge()).Write(a.Listener); chk.E(err) {
return
}
notice := normalize.Restricted.F("this realy does not serve DMs or Application Specific Data " +
"to unauthenticated users or to npubs not found in the event tags or author fields, does your " +
"client implement NIP-42?")
return notice
} }
continue log.I.F("requesting auth from client from %s", a.RealRemote())
if err = authenvelope.NewChallengeWith(a.Challenge()).Write(a.Listener); chk.E(err) {
return
}
notice := normalize.Restricted.F("this realy does not serve DMs or Application Specific Data " +
"to unauthenticated users or to npubs not found in the event tags or author fields, does your " +
"client implement NIP-42?")
return notice
} }
tmp = append(tmp, ev) tmp = append(tmp, ev)
} }