Files
llink/go/internal/pusher/authorizer.go
T
Arjun Patel d262f734f0 Mobile notifications for iOS (#210)
* mobile: wire notification registration and listener

* implement backend components for push notifications

* refactor: agentic comment cleanup

* docs: use proper module name for particle processor

* set required env variables for push notifications

* bump version

* fix: always upsert push token on mobile start

* Revert "fix: always upsert push token on mobile start"

This reverts commit 90ff18a788.

* send push notifications regardless of online status
2026-05-18 12:44:31 -07:00

71 lines
1.6 KiB
Go

package pusher
import (
"context"
"errors"
"strings"
"github.com/flowy-live/llink/internal/network"
)
var ErrUnauthorized = errors.New("unauthorized")
type Authorizer struct {
networkReader network.Reader
}
func NewAuthorizer(networkReader network.Reader) *Authorizer {
return &Authorizer{networkReader: networkReader}
}
// Authorize accepts channel IDs of the form:
//
// network:{networkId}
// stream:{networkId}:{streamId}
// _presence:{humanId}
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)
case "_presence":
// Only the owning human may subscribe to their presence channel.
if rest != humanID {
return ErrUnauthorized
}
return nil
default:
return ErrUnauthorized
}
}
func (a *Authorizer) authorizeNetwork(ctx context.Context, networkID, humanID string) error {
isMember, err := a.networkReader.IsMember(ctx, networkID, humanID)
if err != nil {
return err
}
if !isMember {
return ErrUnauthorized
}
return nil
}
// rest is "{networkId}:{streamId}"; stream-level visibility is enforced 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)
}