package backend import ( "context" "errors" "fmt" "github.com/h44z/wg-portal/internal/config" "github.com/h44z/wg-portal/internal/domain" ) type PeerServicePeerManagerRepo interface { GetPeer(ctx context.Context, id domain.PeerIdentifier) (*domain.Peer, error) GetUserPeers(ctx context.Context, id domain.UserIdentifier) ([]domain.Peer, error) GetInterfaceAndPeers(ctx context.Context, id domain.InterfaceIdentifier) (*domain.Interface, []domain.Peer, error) CreatePeer(ctx context.Context, peer *domain.Peer) (*domain.Peer, error) UpdatePeer(ctx context.Context, peer *domain.Peer) (*domain.Peer, error) DeletePeer(ctx context.Context, id domain.PeerIdentifier) error } type PeerServiceUserManagerRepo interface { GetUser(ctx context.Context, id domain.UserIdentifier) (*domain.User, error) } type PeerService struct { cfg *config.Config peers PeerServicePeerManagerRepo users PeerServiceUserManagerRepo } func NewPeerService( cfg *config.Config, peers PeerServicePeerManagerRepo, users PeerServiceUserManagerRepo, ) *PeerService { return &PeerService{ cfg: cfg, peers: peers, users: users, } } func (s PeerService) GetForInterface(ctx context.Context, id domain.InterfaceIdentifier) ([]domain.Peer, error) { if err := domain.ValidateAdminAccessRights(ctx); err != nil { return nil, err } _, interfacePeers, err := s.peers.GetInterfaceAndPeers(ctx, id) if err != nil { return nil, err } return interfacePeers, nil } func (s PeerService) GetForUser(ctx context.Context, id domain.UserIdentifier) ([]domain.Peer, error) { if err := domain.ValidateUserAccessRights(ctx, id); err != nil { return nil, err } if s.cfg.Advanced.ApiAdminOnly && !domain.GetUserInfo(ctx).IsAdmin { return nil, errors.Join(errors.New("only admins can access this endpoint"), domain.ErrNoPermission) } user, err := s.users.GetUser(ctx, id) if err != nil { return nil, err } userPeers, err := s.peers.GetUserPeers(ctx, user.Identifier) if err != nil { return nil, err } return userPeers, nil } func (s PeerService) GetById(ctx context.Context, id domain.PeerIdentifier) (*domain.Peer, error) { if s.cfg.Advanced.ApiAdminOnly && !domain.GetUserInfo(ctx).IsAdmin { return nil, errors.Join(errors.New("only admins can access this endpoint"), domain.ErrNoPermission) } peer, err := s.peers.GetPeer(ctx, id) if err != nil { return nil, err } // Check if the user has access rights to the requested peer. // If the peer is not linked to any user, access is granted only for admins. if err := domain.ValidateUserAccessRights(ctx, peer.UserIdentifier); err != nil { return nil, err } return peer, nil } func (s PeerService) Create(ctx context.Context, peer *domain.Peer) (*domain.Peer, error) { if err := domain.ValidateAdminAccessRights(ctx); err != nil { return nil, err } if peer.Identifier != domain.PeerIdentifier(peer.Interface.PublicKey) { return nil, fmt.Errorf("peer id mismatch: %s != %s: %w", peer.Identifier, peer.Interface.PublicKey, domain.ErrInvalidData) } createdPeer, err := s.peers.CreatePeer(ctx, peer) if err != nil { return nil, err } return createdPeer, nil } func (s PeerService) Update(ctx context.Context, _ domain.PeerIdentifier, peer *domain.Peer) ( *domain.Peer, error, ) { if err := domain.ValidateAdminAccessRights(ctx); err != nil { return nil, err } updatedPeer, err := s.peers.UpdatePeer(ctx, peer) if err != nil { return nil, err } return updatedPeer, nil } func (s PeerService) Delete(ctx context.Context, id domain.PeerIdentifier) error { if err := domain.ValidateAdminAccessRights(ctx); err != nil { return err } err := s.peers.DeletePeer(ctx, id) if err != nil { return err } return nil }