permission.go

  1package permission
  2
  3import (
  4	"sync"
  5	"time"
  6
  7	"github.com/google/uuid"
  8	"github.com/kujtimiihoxha/termai/internal/pubsub"
  9)
 10
 11type CreatePermissionRequest struct {
 12	ToolName    string `json:"tool_name"`
 13	Description string `json:"description"`
 14	Action      string `json:"action"`
 15	Params      any    `json:"params"`
 16	Path        string `json:"path"`
 17}
 18type PermissionRequest struct {
 19	ID          string `json:"id"`
 20	SessionID   string `json:"session_id"`
 21	ToolName    string `json:"tool_name"`
 22	Description string `json:"description"`
 23	Action      string `json:"action"`
 24	Params      any    `json:"params"`
 25	Path        string `json:"path"`
 26}
 27
 28type Service interface {
 29	pubsub.Suscriber[PermissionRequest]
 30	GrantPersistant(permission PermissionRequest)
 31	Grant(permission PermissionRequest)
 32	Deny(permission PermissionRequest)
 33	Request(opts CreatePermissionRequest) bool
 34}
 35
 36type permissionService struct {
 37	*pubsub.Broker[PermissionRequest]
 38
 39	sessionPermissions []PermissionRequest
 40	pendingRequests    sync.Map
 41}
 42
 43func (s *permissionService) GrantPersistant(permission PermissionRequest) {
 44	respCh, ok := s.pendingRequests.Load(permission.ID)
 45	if ok {
 46		respCh.(chan bool) <- true
 47	}
 48	s.sessionPermissions = append(s.sessionPermissions, permission)
 49}
 50
 51func (s *permissionService) Grant(permission PermissionRequest) {
 52	respCh, ok := s.pendingRequests.Load(permission.ID)
 53	if ok {
 54		respCh.(chan bool) <- true
 55	}
 56}
 57
 58func (s *permissionService) Deny(permission PermissionRequest) {
 59	respCh, ok := s.pendingRequests.Load(permission.ID)
 60	if ok {
 61		respCh.(chan bool) <- false
 62	}
 63}
 64
 65func (s *permissionService) Request(opts CreatePermissionRequest) bool {
 66	permission := PermissionRequest{
 67		ID:          uuid.New().String(),
 68		Path:        opts.Path,
 69		ToolName:    opts.ToolName,
 70		Description: opts.Description,
 71		Action:      opts.Action,
 72		Params:      opts.Params,
 73	}
 74
 75	for _, p := range s.sessionPermissions {
 76		if p.ToolName == permission.ToolName && p.Action == permission.Action {
 77			return true
 78		}
 79	}
 80
 81	respCh := make(chan bool, 1)
 82
 83	s.pendingRequests.Store(permission.ID, respCh)
 84	defer s.pendingRequests.Delete(permission.ID)
 85
 86	s.Publish(pubsub.CreatedEvent, permission)
 87
 88	// Wait for the response with a timeout
 89	select {
 90	case resp := <-respCh:
 91		return resp
 92	case <-time.After(10 * time.Minute):
 93		return false
 94	}
 95}
 96
 97func NewPermissionService() Service {
 98	return &permissionService{
 99		Broker:             pubsub.NewBroker[PermissionRequest](),
100		sessionPermissions: make([]PermissionRequest, 0),
101	}
102}
103
104var Default Service = NewPermissionService()