"veyron/tools/principal": Part 3: dump

Added the 'dump' command that dumps the principal's public key
roots and store. The latter are dumped by invoking a "DebugString"
methods on the corresponding objects, also added by this CL.

Change-Id: Ib22e8427e9188283918516427343808ab1d27c20
diff --git a/security/blessingroots.go b/security/blessingroots.go
index 33bb145..5f314d8 100644
--- a/security/blessingroots.go
+++ b/security/blessingroots.go
@@ -1,8 +1,9 @@
 package security
 
 import (
-	"crypto/sha256"
+	"bytes"
 	"errors"
+	"fmt"
 	"sync"
 
 	"veyron.io/veyron/veyron/security/serialization"
@@ -28,8 +29,7 @@
 	if err != nil {
 		return "", err
 	}
-	rootBytesHash := sha256.Sum256(rootBytes)
-	return string(rootBytesHash[:]), nil
+	return string(rootBytes), nil
 }
 
 func (br *blessingRoots) Add(root security.PublicKey, pattern security.BlessingPattern) error {
@@ -71,6 +71,27 @@
 	return errors.New("PublicKey is not a recognized root for this blessing")
 }
 
+// DebugString return a human-readable string encoding of the roots
+// DebugString encodes all roots into a string in the following
+// format
+//
+// Public key   : Pattern
+// <public key> : <pattern>
+// ...
+// <public key> : <pattern>
+func (br *blessingRoots) DebugString() string {
+	const format = "%-47s : %s\n"
+	b := bytes.NewBufferString(fmt.Sprintf(format, "Public key", "Pattern"))
+	for keyBytes, pattern := range br.store {
+		key, err := security.UnmarshalPublicKey([]byte(keyBytes))
+		if err != nil {
+			return fmt.Sprintf("failed to decode public key: %v", err)
+		}
+		b.WriteString(fmt.Sprintf(format, key, pattern))
+	}
+	return b.String()
+}
+
 func (br *blessingRoots) save() error {
 	if (br.signer == nil) && (br.dir == "") {
 		return nil
diff --git a/security/blessingstore.go b/security/blessingstore.go
index 54b1b0b..b135580 100644
--- a/security/blessingstore.go
+++ b/security/blessingstore.go
@@ -1,6 +1,7 @@
 package security
 
 import (
+	"bytes"
 	"errors"
 	"fmt"
 	"reflect"
@@ -113,6 +114,25 @@
 	return fmt.Sprintf("{state: %v, publicKey: %v, dir: %v}", s.state, s.publicKey, s.dir)
 }
 
+// DebugString return a human-readable string encoding of the store
+// in the following format
+// Default blessing : <Default blessing of the store>
+//
+// Peer pattern : Blessings
+// <pattern>    : <blessings>
+// ...
+// <pattern>    : <blessings>
+func (br *blessingStore) DebugString() string {
+	const format = "%-30s : %s\n"
+	b := bytes.NewBufferString(fmt.Sprintf("Default blessings: %v\n", br.state.Default))
+
+	b.WriteString(fmt.Sprintf(format, "Peer pattern", "Blessings"))
+	for pattern, blessings := range br.state.Store {
+		b.WriteString(fmt.Sprintf(format, pattern, blessings))
+	}
+	return b.String()
+}
+
 func (s *blessingStore) save() error {
 	if (s.signer == nil) && (s.dir == "") {
 		return nil
diff --git a/tools/principal/main.go b/tools/principal/main.go
index 51a9181..305d985 100644
--- a/tools/principal/main.go
+++ b/tools/principal/main.go
@@ -21,6 +21,26 @@
 	flagBlessFor   time.Duration
 	flagAddForPeer string
 
+	cmdDump = &cmdline.Command{
+		Name:  "dump",
+		Short: "Dump out information about the principal",
+		Long: `
+Dumps out information about the principal specified by the environment
+(VEYRON_CREDENTIALS) that this tool is running in.
+`,
+		Run: func(cmd *cmdline.Command, args []string) error {
+			p := rt.R().Principal()
+			fmt.Printf("Public key : %v\n", p.PublicKey())
+			fmt.Println("")
+			fmt.Println("---------------- BlessingStore ----------------")
+			fmt.Printf("%v", p.BlessingStore().DebugString())
+			fmt.Println("")
+			fmt.Println("---------------- BlessingRoots ----------------")
+			fmt.Printf("%v", p.Roots().DebugString())
+			return nil
+		},
+	}
+
 	cmdPrint = &cmdline.Command{
 		Name:  "print",
 		Short: "Print out information about the provided blessing",
@@ -215,7 +235,7 @@
 
 All objects are printed using base64-VOM-encoding.
 `,
-		Children: []*cmdline.Command{cmdPrint, cmdBlessSelf, cmdDefault, cmdForPeer, cmdSetDefault, cmdSet},
+		Children: []*cmdline.Command{cmdDump, cmdPrint, cmdBlessSelf, cmdDefault, cmdForPeer, cmdSetDefault, cmdSet},
 	}).Main()
 }
 
diff --git a/tools/principal/test.sh b/tools/principal/test.sh
index 3041116..4335c66 100755
--- a/tools/principal/test.sh
+++ b/tools/principal/test.sh
@@ -23,10 +23,11 @@
   # Set VEYRON_CREDENTIALS.
   export VEYRON_CREDENTIALS="${WORKDIR}"
 
-  ./principal store.default >/dev/null || shell_test::fail "line ${LINENO}: store.default failed"
-  ./principal store.forpeer >/dev/null || shell_test::fail "line ${LINENO}: store.forpeer failed"
+  ./principal dump >/dev/null || shell_test::fail "line ${LINENO}: dump failed"
   ./principal blessself >/dev/null || shell_test::fail "line ${LINENO}: blessself failed"
   ./principal blessself alice >alice || shell_test::fail "line ${LINENO}: blessself alice failed"
+  ./principal store.default >/dev/null || shell_test::fail "line ${LINENO}: store.default failed"
+  ./principal store.forpeer >/dev/null || shell_test::fail "line ${LINENO}: store.forpeer failed"
 
   # Test print
   local GOT=$(./principal print alice | extractBlessings)