WSPR: Intercept publicKeyCaveat and handle in go

MultiPart: 2/2

Change-Id: I1cf73def98e6776179feab9ed1286d3a3a7c2d9c
diff --git a/services/wsprd/ipc/server/server.go b/services/wsprd/ipc/server/server.go
index f6cf9a4..3c3bcc8 100644
--- a/services/wsprd/ipc/server/server.go
+++ b/services/wsprd/ipc/server/server.go
@@ -331,7 +331,7 @@
 // It resolves each []security.Caveat in cavs to an error (or nil) and collects them in a slice.
 // TODO(ataly, ashankar, bprosnitz): Update this method so tha it also conveys the CallSide to
 // JavaScript.
-func (s *Server) wsprCaveatValidator(call security.Call, _ security.CallSide, cavs [][]security.Caveat) []error {
+func (s *Server) validateCavsInJavascript(call security.Call, _ security.CallSide, cavs [][]security.Caveat) []error {
 	flow := s.helper.CreateNewFlow(s, nil)
 	req := CaveatValidationRequest{
 		Call: s.convertSecurityCall(call, false),
@@ -374,6 +374,61 @@
 	}
 }
 
+// wsprCaveatValidator validates caveats for javascript.
+// Certain caveats (PublicKeyThirdPartyCaveatX) are intercepted and handled in go.
+// This call validateCavsInJavascript to process the remaining caveats in javascript.
+func (s *Server) wsprCaveatValidator(call security.Call, callSide security.CallSide, cavs [][]security.Caveat) []error {
+	type validationStatus struct {
+		err   error
+		isSet bool
+	}
+	valStatus := make([]validationStatus, len(cavs))
+
+	var caveatChainsToValidate [][]security.Caveat
+nextCav:
+	for i, chainCavs := range cavs {
+		var newChainCavs []security.Caveat
+		for _, cav := range chainCavs {
+			switch cav.Id {
+			case security.PublicKeyThirdPartyCaveatX.Id:
+				res := cav.Validate(call, callSide)
+				if res != nil {
+					valStatus[i] = validationStatus{
+						err:   res,
+						isSet: true,
+					}
+					continue nextCav
+				}
+			default:
+				newChainCavs = append(newChainCavs, cav)
+			}
+		}
+		if len(newChainCavs) == 0 {
+			valStatus[i] = validationStatus{
+				err:   nil,
+				isSet: true,
+			}
+		} else {
+			caveatChainsToValidate = append(caveatChainsToValidate, newChainCavs)
+		}
+	}
+
+	jsRes := s.validateCavsInJavascript(call, callSide, caveatChainsToValidate)
+
+	outResults := make([]error, len(cavs))
+	jsIndex := 0
+	for i, status := range valStatus {
+		if status.isSet {
+			outResults[i] = status.err
+		} else {
+			outResults[i] = jsRes[jsIndex]
+			jsIndex++
+		}
+	}
+
+	return outResults
+}
+
 func (s *Server) convertSecurityCall(call security.Call, includeBlessingStrings bool) SecurityCall {
 	// TODO(bprosnitz) Local/Remote Endpoint should always be non-nil, but isn't
 	// due to a TODO in vc/auth.go