TBR wspr: Add put to blessing store

TBR because it is failing due to npm being down. A almost identical version passed recently.

MultiPart: 2/2
Change-Id: I59ba60fb0ed8e5b9731a675964cc5e93fe977847
diff --git a/services/wspr/internal/app/app.go b/services/wspr/internal/app/app.go
index 6c8b51c..24377e3 100644
--- a/services/wspr/internal/app/app.go
+++ b/services/wspr/internal/app/app.go
@@ -44,7 +44,7 @@
 	noResults              = verror.Register(pkgPath+".noResults", verror.NoRetry, "{1} {2} no results from call {_}")
 	badCaveatType          = verror.Register(pkgPath+".badCaveatType", verror.NoRetry, "{1} {2} bad caveat type {_}")
 	unknownBlessings       = verror.Register(pkgPath+".unknownBlessings", verror.NoRetry, "{1} {2} unknown public id {_}")
-	invalidBlessingsHandle = verror.Register(pkgPath+".invalidBlessingsHandle", verror.NoRetry, "{1} {2} invalid blessings handle {_}")
+	invalidBlessingsHandle = verror.Register(pkgPath+".invalidBlessingsHandle", verror.NoRetry, "{1} {2} invalid blessings handle {3} {_}")
 )
 
 type outstandingRequest struct {
@@ -268,12 +268,12 @@
 	return c.ctx
 }
 
-// AddBlessings adds the Blessings to the local blessings store and returns
-// the handle to it.  This function exists because JS only has
-// a handle to the blessings to avoid shipping the certificate forest
-// to JS and back.
-func (c *Controller) AddBlessings(blessings security.Blessings) principal.BlessingsHandle {
-	return c.blessingsCache.Add(blessings)
+// GetOrAddBlessingsHandle adds the Blessings to the local blessings store if they
+// don't already existand returns the handle to it.  This function exists
+// because JS only has a handle to the blessings to avoid shipping the
+// certificate forest to JS and back.
+func (c *Controller) GetOrAddBlessingsHandle(blessings security.Blessings) principal.BlessingsHandle {
+	return c.blessingsCache.GetOrAddHandle(blessings)
 }
 
 // Cleanup cleans up any outstanding rpcs.
@@ -687,8 +687,7 @@
 
 // UnlinkBlessings removes the given blessings from the blessings store.
 func (c *Controller) UnlinkBlessings(_ rpc.ServerCall, handle principal.BlessingsHandle) error {
-	c.blessingsCache.Remove(handle)
-	return nil
+	return c.blessingsCache.RemoveReference(handle)
 }
 
 // Bless binds extensions of blessings held by this principal to
@@ -699,8 +698,8 @@
 	extension string,
 	caveats []security.Caveat) (string, principal.BlessingsHandle, error) {
 	var inputBlessing security.Blessings
-	if inputBlessing = c.blessingsCache.Get(blessingHandle); inputBlessing.IsZero() {
-		return "", principal.ZeroHandle, verror.New(invalidBlessingsHandle, nil)
+	if inputBlessing = c.blessingsCache.GetBlessings(blessingHandle); inputBlessing.IsZero() {
+		return "", principal.ZeroHandle, verror.New(invalidBlessingsHandle, nil, blessingHandle)
 	}
 
 	key, err := principal.DecodePublicKey(publicKey)
@@ -717,12 +716,12 @@
 	if err != nil {
 		return "", principal.ZeroHandle, err
 	}
-	handle := c.blessingsCache.Add(blessings)
+	handle := c.blessingsCache.GetOrAddHandle(blessings)
 	return publicKey, handle, nil
 }
 
 // BlessSelf creates a blessing with the provided name for this principal.
-func (c *Controller) BlessSelf(call rpc.ServerCall,
+func (c *Controller) BlessSelf(_ rpc.ServerCall,
 	extension string, caveats []security.Caveat) (string, principal.BlessingsHandle, error) {
 	p := v23.GetPrincipal(c.ctx)
 	blessings, err := p.BlessSelf(extension)
@@ -730,12 +729,34 @@
 		return "", principal.ZeroHandle, verror.Convert(verror.ErrInternal, nil, err)
 	}
 
-	handle := c.blessingsCache.Add(blessings)
+	handle := c.blessingsCache.GetOrAddHandle(blessings)
 
 	encKey, err := principal.EncodePublicKey(p.PublicKey())
 	return encKey, handle, err
 }
 
+// PutToBlessingStore puts a blessing with the provided name to the blessing store
+// with the specified blessing pattern.
+func (c *Controller) PutToBlessingStore(_ rpc.ServerCall, handle principal.BlessingsHandle, pattern security.BlessingPattern) (*principal.JsBlessings, error) {
+	var inputBlessing security.Blessings
+	if inputBlessing = c.blessingsCache.GetBlessings(handle); inputBlessing.IsZero() {
+		return nil, verror.New(invalidBlessingsHandle, nil, handle)
+	}
+
+	p := v23.GetPrincipal(c.ctx)
+	outBlessing, err := p.BlessingStore().Set(inputBlessing, security.BlessingPattern(pattern))
+	if err != nil {
+		return nil, err
+	}
+
+	if outBlessing.IsZero() {
+		return nil, nil
+	}
+
+	jsBlessing := principal.ConvertBlessingsToHandle(outBlessing, c.blessingsCache.GetOrAddHandle(outBlessing))
+	return jsBlessing, nil
+}
+
 func (c *Controller) RemoteBlessings(call rpc.ServerCall, name, method string) ([]string, error) {
 	vlog.VI(2).Infof("requesting remote blessings for %q", name)
 
diff --git a/services/wspr/internal/app/controller.vdl b/services/wspr/internal/app/controller.vdl
index 5e7e498..7522f8f 100644
--- a/services/wspr/internal/app/controller.vdl
+++ b/services/wspr/internal/app/controller.vdl
@@ -30,6 +30,8 @@
 	Bless(publicKey string, blessingHandle principal.BlessingsHandle, extension string, caveat []security.Caveat) (string, principal.BlessingsHandle | error)
 	// BlessSelf creates a blessing with the provided name for this principal.
 	BlessSelf(name string, caveats []security.Caveat) (string, principal.BlessingsHandle | error)
+	// PutToBlessingStore puts the specified blessing to the blessing store under the provided pattern.
+	PutToBlessingStore(blessingHandle principal.BlessingsHandle, pattern security.BlessingPattern) (?principal.JsBlessings | error)
 
 	// RemoteBlessings fetches the remote blessings for a given name and method.
 	RemoteBlessings(name, method string) ([]string | error)
diff --git a/services/wspr/internal/app/controller.vdl.go b/services/wspr/internal/app/controller.vdl.go
index 4004b80..098a38a 100644
--- a/services/wspr/internal/app/controller.vdl.go
+++ b/services/wspr/internal/app/controller.vdl.go
@@ -39,6 +39,8 @@
 	Bless(ctx *context.T, publicKey string, blessingHandle principal.BlessingsHandle, extension string, caveat []security.Caveat, opts ...rpc.CallOpt) (string, principal.BlessingsHandle, error)
 	// BlessSelf creates a blessing with the provided name for this principal.
 	BlessSelf(ctx *context.T, name string, caveats []security.Caveat, opts ...rpc.CallOpt) (string, principal.BlessingsHandle, error)
+	// PutToBlessingStore puts the specified blessing to the blessing store under the provided pattern.
+	PutToBlessingStore(ctx *context.T, blessingHandle principal.BlessingsHandle, pattern security.BlessingPattern, opts ...rpc.CallOpt) (*principal.JsBlessings, error)
 	// RemoteBlessings fetches the remote blessings for a given name and method.
 	RemoteBlessings(ctx *context.T, name string, method string, opts ...rpc.CallOpt) ([]string, error)
 	// Signature fetches the signature for a given name.
@@ -95,6 +97,11 @@
 	return
 }
 
+func (c implControllerClientStub) PutToBlessingStore(ctx *context.T, i0 principal.BlessingsHandle, i1 security.BlessingPattern, opts ...rpc.CallOpt) (o0 *principal.JsBlessings, err error) {
+	err = v23.GetClient(ctx).Call(ctx, c.name, "PutToBlessingStore", []interface{}{i0, i1}, []interface{}{&o0}, opts...)
+	return
+}
+
 func (c implControllerClientStub) RemoteBlessings(ctx *context.T, i0 string, i1 string, opts ...rpc.CallOpt) (o0 []string, err error) {
 	err = v23.GetClient(ctx).Call(ctx, c.name, "RemoteBlessings", []interface{}{i0, i1}, []interface{}{&o0}, opts...)
 	return
@@ -125,6 +132,8 @@
 	Bless(call rpc.ServerCall, publicKey string, blessingHandle principal.BlessingsHandle, extension string, caveat []security.Caveat) (string, principal.BlessingsHandle, error)
 	// BlessSelf creates a blessing with the provided name for this principal.
 	BlessSelf(call rpc.ServerCall, name string, caveats []security.Caveat) (string, principal.BlessingsHandle, error)
+	// PutToBlessingStore puts the specified blessing to the blessing store under the provided pattern.
+	PutToBlessingStore(call rpc.ServerCall, blessingHandle principal.BlessingsHandle, pattern security.BlessingPattern) (*principal.JsBlessings, error)
 	// RemoteBlessings fetches the remote blessings for a given name and method.
 	RemoteBlessings(call rpc.ServerCall, name string, method string) ([]string, error)
 	// Signature fetches the signature for a given name.
@@ -194,6 +203,10 @@
 	return s.impl.BlessSelf(call, i0, i1)
 }
 
+func (s implControllerServerStub) PutToBlessingStore(call rpc.ServerCall, i0 principal.BlessingsHandle, i1 security.BlessingPattern) (*principal.JsBlessings, error) {
+	return s.impl.PutToBlessingStore(call, i0, i1)
+}
+
 func (s implControllerServerStub) RemoteBlessings(call rpc.ServerCall, i0 string, i1 string) ([]string, error) {
 	return s.impl.RemoteBlessings(call, i0, i1)
 }
@@ -283,6 +296,17 @@
 			},
 		},
 		{
+			Name: "PutToBlessingStore",
+			Doc:  "// PutToBlessingStore puts the specified blessing to the blessing store under the provided pattern.",
+			InArgs: []rpc.ArgDesc{
+				{"blessingHandle", ``}, // principal.BlessingsHandle
+				{"pattern", ``},        // security.BlessingPattern
+			},
+			OutArgs: []rpc.ArgDesc{
+				{"", ``}, // *principal.JsBlessings
+			},
+		},
+		{
 			Name: "RemoteBlessings",
 			Doc:  "// RemoteBlessings fetches the remote blessings for a given name and method.",
 			InArgs: []rpc.ArgDesc{
diff --git a/services/wspr/internal/principal/js_blessings_store.go b/services/wspr/internal/principal/js_blessings_store.go
index f660c50..8007982 100644
--- a/services/wspr/internal/principal/js_blessings_store.go
+++ b/services/wspr/internal/principal/js_blessings_store.go
@@ -5,11 +5,18 @@
 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
@@ -19,37 +26,65 @@
 type JSBlessingsHandles struct {
 	mu         sync.Mutex
 	lastHandle BlessingsHandle
-	store      map[BlessingsHandle]security.Blessings
+	store      map[BlessingsHandle]*refToBlessings
 }
 
 // NewJSBlessingsHandles returns a newly initialized JSBlessingsHandles
 func NewJSBlessingsHandles() *JSBlessingsHandles {
 	return &JSBlessingsHandles{
-		store: map[BlessingsHandle]security.Blessings{},
+		store: map[BlessingsHandle]*refToBlessings{},
 	}
 }
 
-// Add adds a Blessings to the store and returns the handle to it.
-func (s *JSBlessingsHandles) Add(blessings security.Blessings) BlessingsHandle {
+// 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] = blessings
+	s.store[handle] = &refToBlessings{
+		blessings: blessings,
+		refCount:  1,
+	}
 	return handle
 }
 
-// Remove removes the Blessings associated with the handle.
-func (s *JSBlessingsHandles) Remove(handle BlessingsHandle) {
+// 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()
-	delete(s.store, handle)
+	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
 }
 
-// Get returns the Blessings represented by the handle. Returns nil
+// GetBlessings returns the Blessings represented by the handle. Returns nil
 // if no Blessings exists for the handle.
-func (s *JSBlessingsHandles) Get(handle BlessingsHandle) security.Blessings {
+func (s *JSBlessingsHandles) GetBlessings(handle BlessingsHandle) security.Blessings {
 	s.mu.Lock()
 	defer s.mu.Unlock()
-	return s.store[handle]
+	ref, ok := s.store[handle]
+	if !ok {
+		return security.Blessings{}
+	}
+	return ref.blessings
 }
diff --git a/services/wspr/internal/principal/js_blessings_store_test.go b/services/wspr/internal/principal/js_blessings_store_test.go
index 0433504..1f79c6e 100644
--- a/services/wspr/internal/principal/js_blessings_store_test.go
+++ b/services/wspr/internal/principal/js_blessings_store_test.go
@@ -15,13 +15,41 @@
 	s := NewJSBlessingsHandles()
 	b := blessSelf(testutil.NewPrincipal(), "irrelevant")
 
-	h := s.Add(b)
-	if got := s.Get(h); !reflect.DeepEqual(got, b) {
+	h := s.GetOrAddHandle(b)
+	if got := s.GetBlessings(h); !reflect.DeepEqual(got, b) {
 		t.Fatalf("Get after adding: got: %v, want: %v", got, b)
 	}
 
-	s.Remove(h)
-	if got := s.Get(h); !got.IsZero() {
+	hGetOrAdd := s.GetOrAddHandle(b)
+	if h != hGetOrAdd {
+		t.Fatalf("Expected same handle from get or add. got: %v, want: %v", hGetOrAdd, h)
+	}
+	if len(s.store) != 1 {
+		t.Fatalf("Expected single entry to exist")
+	}
+
+	b2 := blessSelf(testutil.NewPrincipal(), "secondBlessing")
+	hNewFromGetOrAdd := s.GetOrAddHandle(b2)
+	if hNewFromGetOrAdd == h {
+		t.Fatalf("Expected to get new handle on new name. got: %v, want: %v", hGetOrAdd, h)
+	}
+
+	s.RemoveReference(h)
+	if got := s.GetBlessings(h); !reflect.DeepEqual(got, b) {
+		t.Fatalf("Expected to still be able to find after first remove: got: %v, want %v", got, b)
+	}
+
+	s.RemoveReference(h)
+	if got := s.GetBlessings(h); !got.IsZero() {
+		t.Fatalf("Get after removing: got: %v, want nil", got)
+	}
+
+	if got := s.GetBlessings(hNewFromGetOrAdd); !reflect.DeepEqual(got, b2) {
+		t.Fatalf("Expected to still be able to get second blessing: got: %v, want %v", got, b2)
+	}
+
+	s.RemoveReference(hNewFromGetOrAdd)
+	if got := s.GetBlessings(h); !got.IsZero() {
 		t.Fatalf("Get after removing: got: %v, want nil", got)
 	}
 }
diff --git a/services/wspr/internal/rpc/server/server.go b/services/wspr/internal/rpc/server/server.go
index c9bf07c..7c8fe80 100644
--- a/services/wspr/internal/rpc/server/server.go
+++ b/services/wspr/internal/rpc/server/server.go
@@ -54,8 +54,8 @@
 }
 
 type HandleStore interface {
-	// Adds blessings to the store and returns handle to the blessings
-	AddBlessings(blessings security.Blessings) principal.BlessingsHandle
+	// Gets or adds blessings to the store and returns handle to the blessings
+	GetOrAddBlessingsHandle(blessings security.Blessings) principal.BlessingsHandle
 }
 
 type ServerHelper interface {
@@ -322,7 +322,7 @@
 }
 
 func (s *Server) convertBlessingsToHandle(blessings security.Blessings) principal.JsBlessings {
-	return *principal.ConvertBlessingsToHandle(blessings, s.helper.AddBlessings(blessings))
+	return *principal.ConvertBlessingsToHandle(blessings, s.helper.GetOrAddBlessingsHandle(blessings))
 }
 
 func makeListOfErrors(numErrors int, err error) []error {