90 lines
2.5 KiB
Go
90 lines
2.5 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/vaultdrop/backend/internal/db"
|
|
)
|
|
|
|
type RebacService struct {
|
|
queries *db.Queries
|
|
}
|
|
|
|
func NewRebacService(queries *db.Queries) *RebacService {
|
|
return &RebacService{queries: queries}
|
|
}
|
|
|
|
func (s *RebacService) ResolveEffectiveRole(userID, resourceID string) (string, error) {
|
|
userUUID, _ := uuid.Parse(userID)
|
|
resourceUUID, _ := uuid.Parse(resourceID)
|
|
role, err := s.queries.ResolveEffectiveRole(context.Background(), db.ResolveEffectiveRoleParams{
|
|
PUserID: userUUID,
|
|
PResourceID: resourceUUID,
|
|
})
|
|
if err != nil {
|
|
return "", fmt.Errorf("resolve effective role: %w", err)
|
|
}
|
|
return role, nil
|
|
}
|
|
|
|
func (s *RebacService) HasRole(userID, resourceID, requiredRole string) (bool, error) {
|
|
role, err := s.ResolveEffectiveRole(userID, resourceID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return role == requiredRole, nil
|
|
}
|
|
|
|
func (s *RebacService) canGrant(granterRole string) bool {
|
|
return granterRole == "owner" || granterRole == "admin"
|
|
}
|
|
|
|
func (s *RebacService) GrantRole(granterID, resourceID, subjectID, role string) error {
|
|
granterUUID, _ := uuid.Parse(granterID)
|
|
resourceUUID, _ := uuid.Parse(resourceID)
|
|
subjectUUID, _ := uuid.Parse(subjectID)
|
|
|
|
granterRole, err := s.ResolveEffectiveRole(granterID, resourceID)
|
|
if err != nil {
|
|
return fmt.Errorf("resolve granter role: %w", err)
|
|
}
|
|
if !s.canGrant(granterRole) {
|
|
return fmt.Errorf("granter does not have permission to grant roles")
|
|
}
|
|
|
|
_, err = s.queries.CreateRebacRelation(context.Background(), db.CreateRebacRelationParams{
|
|
ResourceID: resourceUUID,
|
|
SubjectUserID: subjectUUID,
|
|
Role: role,
|
|
GrantedBy: granterUUID,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("create rebac relation: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *RebacService) RevokeRole(granterID, resourceID, subjectID string) error {
|
|
granterRole, err := s.ResolveEffectiveRole(granterID, resourceID)
|
|
if err != nil {
|
|
return fmt.Errorf("resolve granter role: %w", err)
|
|
}
|
|
if !s.canGrant(granterRole) {
|
|
return fmt.Errorf("granter does not have permission to revoke roles")
|
|
}
|
|
|
|
resourceUUID, _ := uuid.Parse(resourceID)
|
|
subjectUUID, _ := uuid.Parse(subjectID)
|
|
return s.queries.DeleteRebacRelation(context.Background(), db.DeleteRebacRelationParams{
|
|
ResourceID: resourceUUID,
|
|
SubjectUserID: subjectUUID,
|
|
})
|
|
}
|
|
|
|
func (s *RebacService) ListShares(resourceID string) ([]db.RebacRelation, error) {
|
|
resourceUUID, _ := uuid.Parse(resourceID)
|
|
return s.queries.ListRebacRelationsByResource(context.Background(), resourceUUID)
|
|
}
|