Files
llink/go/internal/pusher/authorizer.go
T
Arjun PatelandGitHub 3d8fa79657 add real-time infrastructure (#137)
* setup infra for pusher service

* setup client sdk for pusher service

* fix: ping parse failure

* fix: send pong back to client

avoid disconnections every 2.5 minutes

* increase replicas

* feat: show presence and compose indicator
2026-04-09 12:08:18 -07:00

67 lines
1.6 KiB
Go

package pusher
import (
"context"
"errors"
"strings"
"github.com/flowy-live/llink/internal/network"
)
var ErrUnauthorized = errors.New("unauthorized")
// Authorizer validates whether a user can access a given channel.
type Authorizer struct {
networkSvc network.Service
}
// NewAuthorizer creates a new channel authorizer.
func NewAuthorizer(networkSvc network.Service) *Authorizer {
return &Authorizer{networkSvc: networkSvc}
}
// Authorize checks if the given humanID is allowed to subscribe to the channel.
// Channel formats:
// - network:{networkId}
// - stream:{networkId}:{streamId}
func (a *Authorizer) Authorize(ctx context.Context, channelID, humanID string) error {
parts := strings.SplitN(channelID, ":", 2)
if len(parts) < 2 {
return ErrUnauthorized
}
channelType := parts[0]
rest := parts[1]
switch channelType {
case "network":
return a.authorizeNetwork(ctx, rest, humanID)
case "stream":
return a.authorizeStream(ctx, rest, humanID)
default:
return ErrUnauthorized
}
}
func (a *Authorizer) authorizeNetwork(ctx context.Context, networkID, humanID string) error {
isMember, err := a.networkSvc.IsMember(ctx, networkID, humanID)
if err != nil {
return err
}
if !isMember {
return ErrUnauthorized
}
return nil
}
// authorizeStream expects rest to be "{networkId}:{streamId}".
// We only check network membership — stream visibility is handled by network access.
func (a *Authorizer) authorizeStream(ctx context.Context, rest, humanID string) error {
parts := strings.SplitN(rest, ":", 2)
if len(parts) < 2 {
return ErrUnauthorized
}
networkID := parts[0]
return a.authorizeNetwork(ctx, networkID, humanID)
}