Authorize a new stream once more after it subscribed

A revoke whose re-check ran between a request's authorization and its stream subscribing missed the stream for good: later reloads find no difference. With the access cache on, the subscribe handlers now authorize once more right after subscribing (an in-memory lookup); the re-check runs after the cache swap, so one of the two always sees the other. Found by a Codex review.
This commit is contained in:
binwiederhier committed 2026-10-24 15:51:31 +00:00
1 parent 70f35dc33d
commit bc88121f80
3 files changed
+65

No files matched your search

+17
View File
@@ -406,6 +406,11 @@ func createAttachmentStore(conf *Config, messageCache *message.Cache) (*attachme
return nil, nil
}
// testHookBeforeSubscribe, if non-nil, is called by the subscribe handlers after the request was
// authorized and before its stream subscribes. Tests use it to land an access change in between;
// it is always nil in production.
var testHookBeforeSubscribe func()
// Run executes the main server. It listens on HTTP (+ HTTPS, if configured), and starts
// a manager go routine to print stats and prune messages.
func (s *Server) Run() error {
@@ -1633,6 +1638,9 @@ func (s *Server) handleSubscribeHTTP(w http.ResponseWriter, r *http.Request, v *
w.Header().Set("Incremental", "?1") // Ask proxies to forward the stream without buffering (RFC 10036)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if testHookBeforeSubscribe != nil {
testHookBeforeSubscribe()
}
subscriberIDs := make([]int, 0)
for _, t := range topics {
subscriberIDs = append(subscriberIDs, t.Subscribe(sub, v.User(), cancel))
@@ -1642,6 +1650,9 @@ func (s *Server) handleSubscribeHTTP(w http.ResponseWriter, r *http.Request, v *
topics[i].Unsubscribe(subscriberID) // Order!
}
}()
if err := s.authorizeSubscribed(v, topics); err != nil {
return err
}
if err := sub(v, model.NewOpenMessage(topicsStr)); err != nil { // Send out open message
return err
}
@@ -1782,6 +1793,9 @@ func (s *Server) handleSubscribeWS(w http.ResponseWriter, r *http.Request, v *vi
}
return s.sendOldMessages(w, topics, since, scheduled, v, sub)
}
if testHookBeforeSubscribe != nil {
testHookBeforeSubscribe()
}
subscriberIDs := make([]int, 0)
for _, t := range topics {
subscriberIDs = append(subscriberIDs, t.Subscribe(sub, v.User(), cancel))
@@ -1791,6 +1805,9 @@ func (s *Server) handleSubscribeWS(w http.ResponseWriter, r *http.Request, v *vi
topics[i].Unsubscribe(subscriberID) // Order!
}
}()
if err := s.authorizeSubscribed(v, topics); err != nil {
return err
}
if err := sub(v, model.NewOpenMessage(topicsStr)); err != nil { // Send out open message
return err
}