blob: 800798249349e1fbd6dd9458beadc8fbf8304a95 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package principal
import (
"fmt"
"reflect"
"sync"
"v.io/v23/security"
)
type refToBlessings struct {
blessings security.Blessings
refCount int
}
// JSBlessingsHandles is a store for Blessings in use by JS code.
//
// We don't pass the full Blessings object to avoid serializing
// and deserializing a potentially huge forest of blessings.
// Instead we pass to JS a handle to a Blessings object and have
// all operations involving cryptographic operations call into go.
type JSBlessingsHandles struct {
mu sync.Mutex
lastHandle BlessingsHandle
store map[BlessingsHandle]*refToBlessings
}
// NewJSBlessingsHandles returns a newly initialized JSBlessingsHandles
func NewJSBlessingsHandles() *JSBlessingsHandles {
return &JSBlessingsHandles{
store: map[BlessingsHandle]*refToBlessings{},
}
}
// GetOrAddHandle looks for a corresponding blessing handle and adds one if not found.
func (s *JSBlessingsHandles) GetOrAddHandle(blessings security.Blessings) BlessingsHandle {
s.mu.Lock()
defer s.mu.Unlock()
// Look for an existing blessing.
for handle, ref := range s.store {
if reflect.DeepEqual(blessings, ref.blessings) {
ref.refCount++
return handle
}
}
// Otherwise add it
s.lastHandle++
handle := s.lastHandle
s.store[handle] = &refToBlessings{
blessings: blessings,
refCount: 1,
}
return handle
}
// RemoveReference indicates the removal of a reference to
// the Blessings associated with the handle.
func (s *JSBlessingsHandles) RemoveReference(handle BlessingsHandle) error {
s.mu.Lock()
defer s.mu.Unlock()
ref, ok := s.store[handle]
if !ok {
return fmt.Errorf("Could not find reference to handle being removed: %v", handle)
}
ref.refCount--
if ref.refCount == 0 {
delete(s.store, handle)
}
if ref.refCount < 0 {
return fmt.Errorf("Unexpected negative ref count")
}
return nil
}
// GetBlessings returns the Blessings represented by the handle. Returns nil
// if no Blessings exists for the handle.
func (s *JSBlessingsHandles) GetBlessings(handle BlessingsHandle) security.Blessings {
s.mu.Lock()
defer s.mu.Unlock()
ref, ok := s.store[handle]
if !ok {
return security.Blessings{}
}
return ref.blessings
}