Files
summercms/modules/lighthouse/centrifugo/driver.go
Jakub Zych 79fd705680 feat(11-03): re-authorize every Centrifugo subscribe through a namespace registry
- lighthouse: Registry of namespace authorizers (Result, Allowed, Denied),
  ParseChannel, ChannelID with PHP (int)-cast semantics (PHPInt, pinned by
  a php -r table test), FormatChannels, WithClientID/ClientID
- centrifugo: ProxyHandler (constant-time X-Centrifugo-Secret, HTTP 200
  generic deny, info [] on allow, presence allow/override merge, 64 KiB
  body cap) mounted as the ServerToServer subscribe route
- README: proxy contract, registry and channel rules
2026-09-30 12:29:09 +02:00

80 lines
2.4 KiB
Go

package centrifugo
import (
"context"
"encoding/json"
"net/http"
"git.golem15.com/golem15/summercms/modules/backpack"
"git.golem15.com/golem15/summercms/modules/lighthouse"
)
// DriverName is the realtime.driver value of this driver.
const DriverName = "centrifugo"
func init() {
lighthouse.RegisterDriver(DriverName, func(app *backpack.App, svc *lighthouse.Service) (lighthouse.Driver, error) {
var cfg Config
if app != nil {
cfg = LoadConfig(app.Config)
} else {
cfg = LoadConfig(nil)
}
return NewDriver(svc, cfg, nil), nil
})
}
// Driver is the Centrifugo lighthouse.Driver: it publishes through Client
// and declares the token route (UserAuth) and the subscribe proxy route
// (ServerToServer).
type Driver struct {
svc *lighthouse.Service
cfg Config
client *Client
issuer *TokenIssuer
}
// NewDriver builds the driver for svc from cfg. hc may be nil (see
// NewClient).
func NewDriver(svc *lighthouse.Service, cfg Config, hc *http.Client) *Driver {
c := NewClient(cfg, hc)
c.log = svc.Logger()
return &Driver{
svc: svc,
cfg: cfg,
client: c,
issuer: NewTokenIssuer(cfg.TokenSecret, cfg.TokenTTL),
}
}
// Name returns "centrifugo".
func (d *Driver) Name() string { return DriverName }
// Config returns the driver's configuration.
func (d *Driver) Config() Config { return d.cfg }
// Client returns the HTTP API client.
func (d *Driver) Client() *Client { return d.client }
// Issuer returns the token issuer.
func (d *Driver) Issuer() *TokenIssuer { return d.issuer }
// Publish sends event to one channel through Client.Publish.
func (d *Driver) Publish(ctx context.Context, channel, event string, payload json.RawMessage) error {
return d.client.Publish(ctx, channel, event, payload)
}
// Broadcast sends event to several channels through Client.Broadcast.
func (d *Driver) Broadcast(ctx context.Context, channels []string, event string, payload json.RawMessage) error {
return d.client.Broadcast(ctx, channels, event, payload)
}
// Routes returns GET token_path (UserAuth, TokenHandler) and POST
// subscribe_path (ServerToServer, ProxyHandler).
func (d *Driver) Routes() []lighthouse.Route {
return []lighthouse.Route{
{Name: "token", Method: http.MethodGet, Path: d.cfg.TokenPath, Surface: lighthouse.UserAuth, Handler: TokenHandler(d.svc, d.issuer)},
{Name: "subscribe", Method: http.MethodPost, Path: d.cfg.SubscribePath, Surface: lighthouse.ServerToServer, Handler: ProxyHandler(d.svc, d.cfg)},
}
}