Skip to content

Commit

Permalink
fix scheduling of access list to update immediately after saving upda…
Browse files Browse the repository at this point in the history
…ted lists
  • Loading branch information
mleku committed Nov 29, 2024
1 parent 8e208c1 commit 311f5dc
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 47 deletions.
70 changes: 37 additions & 33 deletions cmd/realy/app/implementation.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,30 +65,29 @@ func (r *Relay) Init() (err E) {
}

func (r *Relay) AcceptEvent(c context.T, evt *event.T, hr *http.Request, origin S,
authedPubkey B) (accept bool, notice S) {
authedPubkey B) (accept bool, notice S, afterSave func()) {
// if the authenticator is enabled we require auth to accept events
if !r.AuthEnabled() {
return true, ""
return true, "", nil
}
if len(authedPubkey) != 32 {
return false, fmt.Sprintf("client not authed with auth required %s", origin)
return false, fmt.Sprintf("client not authed with auth required %s", origin), nil
}
if len(r.Owners) > 0 {
r.Lock()
defer r.Unlock()
if evt.Kind.Equal(kind.FollowList) || evt.Kind.Equal(kind.MuteList) {
for _, o := range r.Owners {
log.I.F("own %0x\npub %0x", o, evt.PubKey)
if equals(o, evt.PubKey) {
// owner has updated follows or mute list, so we zero those lists so they
// are regenerated for the next AcceptReq/AcceptEvent
r.Followed = make(map[S]struct{})
r.OwnersFollowLists = r.OwnersFollowLists[:0]
r.Muted = make(map[S]struct{})
r.OwnersMuteLists = r.OwnersMuteLists[:0]
log.I.F("clearing owner follow/mute lists because of update from %s %0x",
origin, evt.PubKey)
return true, ""
return true, "", func() {
// owner has updated follows or mute list, so we zero those lists so they
// are regenerated for the next AcceptReq/AcceptEvent
r.Followed = make(map[S]struct{})
r.OwnersFollowLists = r.OwnersFollowLists[:0]
r.Muted = make(map[S]struct{})
r.OwnersMuteLists = r.OwnersMuteLists[:0]
r.CheckOwnerLists(context.Bg())
}
}
}
}
Expand All @@ -102,7 +101,9 @@ func (r *Relay) AcceptEvent(c context.T, evt *event.T, hr *http.Request, origin
// potential for a malicious action causing this, first check for the list:
tt := tag.New(append(r.OwnersFollowLists, r.OwnersMuteLists...)...)
if evt.Tags.ContainsAny(B("e"), tt) {
return false, "cannot delete owner's follow, owners's follows follow or mute events"
return false,
"cannot delete owner's follow, owners's follows follow or mute events",
nil
}
// next, check all a tags present are not follow/mute lists of the owners
aTags := evt.Tags.GetAll(tag.New("a"))
Expand All @@ -118,13 +119,13 @@ func (r *Relay) AcceptEvent(c context.T, evt *event.T, hr *http.Request, origin
kk := kind.New(kin.Uint16())
if kk.Equal(kind.Deletion) {
// we don't delete delete events, period
return false, "delete event kind may not be deleted"
return false, "delete event kind may not be deleted", nil
}
// if the kind is not parameterised replaceable, the tag is invalid and the
// delete event will not be saved.
if !kk.IsParameterizedReplaceable() {
return false, "delete tags with a tags containing " +
"non-parameterized-replaceable events cannot be processed"
"non-parameterized-replaceable events cannot be processed", nil
}
for _, own := range r.Owners {
// don't allow owners to delete their mute or follow lists because
Expand All @@ -134,20 +135,20 @@ func (r *Relay) AcceptEvent(c context.T, evt *event.T, hr *http.Request, origin
kk.Equal(kind.MuteList) ||
kk.Equal(kind.FollowList) {
return false, "owners may not delete their own " +
"mute or follow lists, they can be replaced"
"mute or follow lists, they can be replaced", nil
}
}
}
log.W.Ln("event is from owner")
return true, ""
return true, "", nil
}
}
// check the mute list, and reject events authored by muted pubkeys, even if
// they come from a pubkey that is on the follow list.
for pk := range r.Muted {
if equals(evt.PubKey, B(pk)) {
return false, "rejecting event with pubkey " + S(evt.PubKey) +
" because on owner mute list"
" because on owner mute list", nil
}
}
// for all else, check the authed pubkey is in the follow list
Expand All @@ -156,7 +157,7 @@ func (r *Relay) AcceptEvent(c context.T, evt *event.T, hr *http.Request, origin
if equals(authedPubkey, B(pk)) {
log.I.F("accepting event %0x because %0x on owner follow list",
evt.ID, B(pk))
return true, ""
return true, "", nil
}
}
}
Expand Down Expand Up @@ -217,8 +218,6 @@ func (r *Relay) AcceptReq(c Ctx, hr *http.Request, idB, ff *filters.T,
// client is permitted, pass through the filter so request/count processing does
// not need logic and can just use the returned filter.
allowed = ff
// regenerate lists if they have been updated
r.CheckOwnerLists(c)
// check that the client is authed to a pubkey in the owner follow list
if len(r.Owners) > 0 {
for pk := range r.Followed {
Expand Down Expand Up @@ -247,6 +246,10 @@ func (r *Relay) CheckOwnerLists(c context.T) {
var evs []*event.T
// need to search DB for moderator npub follow lists, followed npubs are allowed access.
if len(r.Followed) < 1 {
// add the owners themselves of course
for i := range r.Owners {
r.Followed[S(r.Owners[i])] = struct{}{}
}
log.D.Ln("regenerating owners follow lists")
if evs, err = r.Store.QueryEvents(c,
&filter.T{Authors: tag.New(r.Owners...),
Expand Down Expand Up @@ -282,7 +285,7 @@ func (r *Relay) CheckOwnerLists(c context.T) {
for _, t := range ev.Tags.F() {
if equals(t.Key(), B("p")) {
var p B
if p, err = hex.Dec(S(t.Value())); chk.E(err) {
if p, err = hex.Dec(S(t.Value())); err != nil {
continue
}
r.Followed[S(p)] = struct{}{}
Expand Down Expand Up @@ -312,16 +315,17 @@ func (r *Relay) CheckOwnerLists(c context.T) {
}
evs = evs[:0]
}
// log this info
o := "followed:\n"
for pk := range r.Followed {
o += fmt.Sprintf("%0x,", pk)
}
o += "\nmuted:\n"
for pk := range r.Muted {
o += fmt.Sprintf("%0x,", pk)
}
log.T.F("%s\n", o)
log.T.F("%d allowed npubs, %d blocked", len(r.Followed), len(r.Muted))
// // log this info
// o := "followed:\n"
// for pk := range r.Followed {
// o += fmt.Sprintf("%0x,", pk)
// }
// o += "\nmuted:\n"
// for pk := range r.Muted {
// o += fmt.Sprintf("%0x,", pk)
// }
// log.T.F("%s\n", o)
}
}

Expand Down
4 changes: 2 additions & 2 deletions event/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ InVal:
return
}
if len(sig) != schnorr.SignatureSize {
err = errorf.E("invalid sig length, require %d got %d '%s'",
schnorr.SignatureSize, len(sig), r)
err = errorf.E("invalid sig length, require %d got %d '%s'\n%s",
schnorr.SignatureSize, len(sig), r, b)
return
}
ev.Sig = sig
Expand Down
10 changes: 5 additions & 5 deletions ratel/queryevents.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,10 @@ func (r *T) QueryEvents(c Ctx, f *filter.T) (evs event.Ts, err E) {
// pubkey and kind.
if equals(ev.PubKey, evc.PubKey) && ev.Kind.Equal(evc.Kind) {
if ev.CreatedAt.I64() > evc.CreatedAt.I64() {
log.T.F("event %0x,%s\nreplaces %0x,%s",
ev.ID, ev.Serialize(),
evc.ID, evc.Serialize(),
)
// log.T.F("event %0x,%s\nreplaces %0x,%s",
// ev.ID, ev.Serialize(),
// evc.ID, evc.Serialize(),
// )
// replace the event, it is newer
delete(evMap, i)
break
Expand Down Expand Up @@ -265,7 +265,7 @@ func (r *T) QueryEvents(c Ctx, f *filter.T) (evs event.Ts, err E) {
return
}
}
log.T.Ln("last access for", seri.Uint64(), now.U64())
// log.T.Ln("last access for", seri.Uint64(), now.U64())
return nil
})
}
Expand Down
8 changes: 7 additions & 1 deletion realy/add-event.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func AddEvent(c Ctx, rl relay.I, ev *event.T, hr *http.Request, origin S,
wrapper := &wrapper.RelayWrapper{I: sto}
advancedSaver, _ := sto.(relay.AdvancedSaver)

accept, notice := rl.AcceptEvent(c, ev, hr, origin, authedPubkey)
accept, notice, after := rl.AcceptEvent(c, ev, hr, origin, authedPubkey)
if !accept {
return false, normalize.Blocked.F(notice)
}
Expand Down Expand Up @@ -73,6 +73,12 @@ func AddEvent(c Ctx, rl relay.I, ev *event.T, hr *http.Request, origin S,
if ar, ok := rl.(relay.Authenticator); ok {
authRequired = ar.AuthEnabled()
}
// if the AcceptEvent function returned a closure we run it after the publish
// has been done because at least for now this means it is an updated follow
// list of an owner or their follows
if after != nil {
after()
}
notifyListeners(authRequired, ev)

accepted = true
Expand Down
1 change: 0 additions & 1 deletion realy/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
func (s *Server) HTTPAuth(r *http.Request) (authed bool) {
username, password, ok := r.BasicAuth()
if ok {
log.I.S(username, password)
// Calculate SHA-256 hashes for the provided and expected
// usernames and passwords.
usernameHash := sha256.Sum256(B(username))
Expand Down
7 changes: 6 additions & 1 deletion realy/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ func (s *Server) doEvent(c Ctx, ws *web.Socket, req B, sto store.I) (msg B) {
if len(rem) > 0 {
log.I.F("extra '%s'", rem)
}
accept, notice := s.relay.AcceptEvent(c, env.T, ws.Req(), ws.RealRemote(), B(ws.Authed()))
accept, notice, after := s.relay.AcceptEvent(c, env.T, ws.Req(), ws.RealRemote(),
B(ws.Authed()))
if !accept {
var auther relay.Authenticator
if auther, ok = s.relay.(relay.Authenticator); ok && auther.AuthEnabled() {
Expand Down Expand Up @@ -167,6 +168,7 @@ func (s *Server) doEvent(c Ctx, ws *web.Socket, req B, sto store.I) (msg B) {
}
return
}

// check id
if !equals(env.GetIDBytes(), env.ID) {
if err = okenvelope.NewFrom(env.ID, false,
Expand Down Expand Up @@ -350,6 +352,9 @@ func (s *Server) doEvent(c Ctx, ws *web.Socket, req B, sto store.I) (msg B) {
if err = okenvelope.NewFrom(env.ID, ok, reason).Write(ws); chk.E(err) {
return
}
if after != nil {
after()
}
return
}

Expand Down
2 changes: 1 addition & 1 deletion realy/version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1.2.22
v1.2.23
6 changes: 3 additions & 3 deletions relay/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type I interface {
// direct and group message events until there is three and thereafter will be restricted
// until the user adds them to their follow list.
AcceptEvent(c Ctx, ev *event.T, hr *http.Request, origin S, authedPubkey B) (accept bool,
notice string)
notice string, afterSave func())
// Storage returns the realy storage implementation.
Storage(Ctx) store.I
}
Expand All @@ -55,8 +55,8 @@ type ReqAcceptor interface {
// support for in/outbox access.
//
// In order to support the ability to respond to
AcceptReq(ctx Ctx, hr *http.Request, id B, ff *filters.T,
authedPubkey B) (allowed *filters.T, ok bool)
AcceptReq(c Ctx, hr *http.Request, id B, ff *filters.T, authedPubkey B) (allowed *filters.T,
ok bool)
}

// Authenticator is the interface for implementing NIP-42.
Expand Down

0 comments on commit 311f5dc

Please sign in to comment.