TBR Browspr - WSPR for the browser

This is a version of WSPR that is build around postMessage rather than HTTP/Websocket requests.

A number of parts of WSPR have been refactored.

In the future, we may want WSPR to use the same interface as browspr (it can use the callbacks used for postmessage), just to consolidate code.

Change-Id: I338265a4305ba74c4c46e47051aeb850b2219582
diff --git a/services/wsprd/account/account.go b/services/wsprd/account/account.go
new file mode 100644
index 0000000..aeafd77
--- /dev/null
+++ b/services/wsprd/account/account.go
@@ -0,0 +1,99 @@
+// The account package contains logic for creating accounts and associating them with origins.
+package account
+
+import (
+	"fmt"
+	"strings"
+	"time"
+
+	"veyron.io/veyron/veyron2"
+	"veyron.io/veyron/veyron2/context"
+	"veyron.io/veyron/veyron2/ipc"
+	"veyron.io/veyron/veyron2/security"
+	"veyron.io/wspr/veyron/services/wsprd/principal"
+)
+
+type BlesserService interface {
+	BlessUsingAccessToken(ctx context.T, token string, opts ...ipc.CallOpt) (blessingObj security.WireBlessings, account string, err error)
+}
+
+type bs struct {
+	client ipc.Client
+	name   string
+}
+
+func (s *bs) BlessUsingAccessToken(ctx context.T, token string, opts ...ipc.CallOpt) (blessingObj security.WireBlessings, account string, err error) {
+	var call ipc.Call
+	if call, err = s.client.StartCall(ctx, s.name, "BlessUsingAccessToken", []interface{}{token}, opts...); err != nil {
+		return
+	}
+	var email string
+	if ierr := call.Finish(&blessingObj, &email, &err); ierr != nil {
+		err = ierr
+	}
+	serverBlessings, _ := call.RemoteBlessings()
+	return blessingObj, accountName(serverBlessings, email), nil
+}
+
+func accountName(serverBlessings []string, email string) string {
+	return strings.Join(serverBlessings, "#") + security.ChainSeparator + email
+}
+
+type AccountManager struct {
+	rt               veyron2.Runtime
+	blesser          BlesserService
+	principalManager *principal.PrincipalManager
+}
+
+func NewAccountManager(rt veyron2.Runtime, identitydEndpoint string, principalManager *principal.PrincipalManager) *AccountManager {
+	return &AccountManager{
+		rt:               rt,
+		blesser:          &bs{client: rt.Client(), name: identitydEndpoint},
+		principalManager: principalManager,
+	}
+}
+
+func (am *AccountManager) CreateAccount(accessToken string) (string, error) {
+	// Get a blessing for the access token from blessing server.
+	ctx, cancel := am.rt.NewContext().WithTimeout(time.Minute)
+	defer cancel()
+	blessings, account, err := am.blesser.BlessUsingAccessToken(ctx, accessToken)
+	if err != nil {
+		return "", fmt.Errorf("Error getting blessing for access token: %v", err)
+	}
+
+	accountBlessings, err := security.NewBlessings(blessings)
+	if err != nil {
+		return "", fmt.Errorf("Error creating blessings from wire data: %v", err)
+	}
+
+	// Add accountBlessings to principalManager under the provided
+	// account.
+	if err := am.principalManager.AddAccount(account, accountBlessings); err != nil {
+		return "", fmt.Errorf("Error adding account: %v", err)
+	}
+
+	return account, nil
+}
+
+func (am *AccountManager) AssociateAccount(origin, account string) error {
+	// Store the origin.
+	// TODO(nlacasse, bjornick): determine what the caveats should be.
+	if err := am.principalManager.AddOrigin(origin, account, nil); err != nil {
+		return fmt.Errorf("Error associating account: %v", err)
+	}
+	return nil
+}
+
+func (am *AccountManager) LookupPrincipal(origin string) (security.Principal, error) {
+	return am.principalManager.Principal(origin)
+}
+
+func (am *AccountManager) PrincipalManager() *principal.PrincipalManager {
+	return am.principalManager
+}
+
+// TODO(bprosnitz) Refactor WSPR to remove this.
+func (am *AccountManager) SetMockBlesser(blesser BlesserService) {
+	am.blesser = blesser
+}
diff --git a/services/wsprd/app/messaging.go b/services/wsprd/app/messaging.go
index f74034a..465cea8 100644
--- a/services/wsprd/app/messaging.go
+++ b/services/wsprd/app/messaging.go
@@ -1,8 +1,15 @@
 package app
 
 import (
+	"bytes"
+	"fmt"
+	"path/filepath"
+	"runtime"
+
 	"veyron.io/veyron/veyron2/context"
 	verror "veyron.io/veyron/veyron2/verror2"
+	"veyron.io/veyron/veyron2/vlog"
+	"veyron.io/veyron/veyron2/vom"
 	"veyron.io/wspr/veyron/services/wsprd/lib"
 )
 
@@ -14,108 +21,163 @@
 	errUnknownMessageType = verror.Register(verrorPkgPath+".unkownMessage", verror.NoRetry, "{1} {2} Unknown message type {_}")
 )
 
-// The type of message sent by the JS client to the wspr.
-type messageType int32
+// Incoming message from the javascript client to WSPR.
+type MessageType int32
 
 const (
 	// Making a veyron client request, streaming or otherwise
-	veyronRequestMessage messageType = 0
+	VeyronRequestMessage MessageType = 0
 
 	// Serving this  under an object name
-	serveMessage = 1
+	ServeMessage = 1
 
 	// A response from a service in javascript to a request
 	// from the proxy.
-	serverResponseMessage = 2
+	ServerResponseMessage = 2
 
 	// Sending streaming data, either from a JS client or JS service.
-	streamingValueMessage = 3
+	StreamingValueMessage = 3
 
 	// A response that means the stream is closed by the client.
-	streamCloseMessage = 4
+	StreamCloseMessage = 4
 
 	// A request to get signature of a remote server
-	signatureRequestMessage = 5
+	SignatureRequestMessage = 5
 
 	// A request to stop a server
-	stopServerMessage = 6
+	StopServerMessage = 6
 
 	// A request to bless a public key.
-	blessPublicKeyMessage = 7
+	BlessPublicKeyMessage = 7
 
 	// A request to unlink blessings.  This request means that
 	// we can remove the given handle from the handle store.
-	unlinkBlessingsMessage = 8
+	UnlinkBlessingsMessage = 8
 
 	// A request to create a new random blessings
-	createBlessingsMessage = 9
+	CreateBlessingsMessage = 9
 
 	// A request to run the lookup function on a dispatcher.
-	lookupResponseMessage = 11
+	LookupResponseMessage = 11
 
 	// A request to run the authorizer for an rpc.
-	authResponseMessage = 12
+	AuthResponseMessage = 12
 
 	// A request to run a namespace client method
-	namespaceRequestMessage = 13
+	NamespaceRequestMessage = 13
 
 	// A request to cancel an rpc initiated by the JS.
-	cancelMessage = 17
+	CancelMessage = 17
 
 	// A request to add a new name to server.
-	websocketAddName = 18
+	WebsocketAddName = 18
 
 	// A request to remove a name from server.
-	websocketRemoveName = 19
+	WebsocketRemoveName = 19
 )
 
+type Response struct {
+	Type    lib.ResponseType
+	Message interface{}
+}
+
 type Message struct {
 	Id int64
 	// This contains the json encoded payload.
 	Data string
 
 	// Whether it is an rpc request or a serve request.
-	Type messageType
+	Type MessageType
 }
 
+// HandleIncomingMessage handles most incoming messages from JS and calls the appropriate handler.
 func (c *Controller) HandleIncomingMessage(ctx context.T, msg Message, w lib.ClientWriter) {
 	switch msg.Type {
-	case veyronRequestMessage:
+	case VeyronRequestMessage:
 		c.HandleVeyronRequest(ctx, msg.Id, msg.Data, w)
-	case cancelMessage:
+	case CancelMessage:
 		go c.HandleVeyronCancellation(msg.Id)
-	case streamingValueMessage:
+	case StreamingValueMessage:
 		// SendOnStream queues up the message to be sent, but doesn't do the send
 		// on this goroutine.  We need to queue the messages synchronously so that
 		// the order is preserved.
 		c.SendOnStream(msg.Id, msg.Data, w)
-	case streamCloseMessage:
+	case StreamCloseMessage:
 		c.CloseStream(msg.Id)
-	case serveMessage:
+	case ServeMessage:
 		go c.HandleServeRequest(msg.Data, w)
-	case stopServerMessage:
+	case StopServerMessage:
 		go c.HandleStopRequest(msg.Data, w)
-	case websocketAddName:
+	case WebsocketAddName:
 		go c.HandleAddNameRequest(msg.Data, w)
-	case websocketRemoveName:
+	case WebsocketRemoveName:
 		go c.HandleRemoveNameRequest(msg.Data, w)
-	case serverResponseMessage:
+	case ServerResponseMessage:
 		go c.HandleServerResponse(msg.Id, msg.Data)
-	case signatureRequestMessage:
+	case SignatureRequestMessage:
 		go c.HandleSignatureRequest(ctx, msg.Data, w)
-	case lookupResponseMessage:
+	case LookupResponseMessage:
 		go c.HandleLookupResponse(msg.Id, msg.Data)
-	case blessPublicKeyMessage:
+	case BlessPublicKeyMessage:
 		go c.HandleBlessPublicKey(msg.Data, w)
-	case createBlessingsMessage:
+	case CreateBlessingsMessage:
 		go c.HandleCreateBlessings(msg.Data, w)
-	case unlinkBlessingsMessage:
+	case UnlinkBlessingsMessage:
 		go c.HandleUnlinkJSBlessings(msg.Data, w)
-	case authResponseMessage:
+	case AuthResponseMessage:
 		go c.HandleAuthResponse(msg.Id, msg.Data)
-	case namespaceRequestMessage:
+	case NamespaceRequestMessage:
 		go c.HandleNamespaceRequest(ctx, msg.Data, w)
 	default:
 		w.Error(verror.Make(errUnknownMessageType, ctx, msg.Type))
 	}
 }
+
+// ConstructOutgoingMessage constructs a message to send to javascript in a consistent format.
+// TODO(bprosnitz) Don't double-encode
+func ConstructOutgoingMessage(messageId int64, messageType lib.ResponseType, data interface{}) (string, error) {
+	var buf bytes.Buffer
+	if err := vom.ObjToJSON(&buf, vom.ValueOf(Response{Type: messageType, Message: data})); err != nil {
+		return "", err
+	}
+
+	var buf2 bytes.Buffer
+	if err := vom.ObjToJSON(&buf2, vom.ValueOf(Message{Id: messageId, Data: buf.String()})); err != nil {
+		return "", err
+	}
+
+	return buf2.String(), nil
+}
+
+// FormatAsVerror formats an error as a verror.
+// This also logs the error to the given logger.
+func FormatAsVerror(err error, logger vlog.Logger) error {
+	verr := verror.Convert(verror.Unknown, nil, err)
+
+	// Also log the error but write internal errors at a more severe log level
+	var logLevel vlog.Level = 2
+	logErr := fmt.Sprintf("%v", verr)
+
+	// Prefix the message with the code locations associated with verr,
+	// except the last, which is the Convert() above.  This does nothing if
+	// err was not a verror error.
+	verrStack := verror.Stack(verr)
+	for i := 0; i < len(verrStack)-1; i++ {
+		pc := verrStack[i]
+		fnc := runtime.FuncForPC(pc)
+		file, line := fnc.FileLine(pc)
+		logErr = fmt.Sprintf("%s:%d: %s", file, line)
+	}
+
+	// We want to look at the stack three frames up to find where the error actually
+	// occurred.  (caller -> websocketErrorResponse/sendError -> generateErrorMessage).
+	if _, file, line, ok := runtime.Caller(3); ok {
+		logErr = fmt.Sprintf("%s:%d: %s", filepath.Base(file), line, logErr)
+	}
+	if verror.Is(verr, verror.Internal.ID) {
+		logLevel = 2
+	}
+	logger.VI(logLevel).Info(logErr)
+
+	return verr
+}
diff --git a/services/wsprd/browspr/browspr.go b/services/wsprd/browspr/browspr.go
new file mode 100644
index 0000000..a45134b
--- /dev/null
+++ b/services/wsprd/browspr/browspr.go
@@ -0,0 +1,126 @@
+// Browspr is the browser version of WSPR, intended to communicate with javascript through postMessage.
+package browspr
+
+import (
+	"net"
+	"time"
+
+	"veyron.io/veyron/veyron2"
+	"veyron.io/veyron/veyron2/ipc"
+	"veyron.io/veyron/veyron2/rt"
+	"veyron.io/veyron/veyron2/vlog"
+	"veyron.io/wspr/veyron/services/wsprd/account"
+	"veyron.io/wspr/veyron/services/wsprd/principal"
+)
+
+// Browspr is an intermediary between our javascript code and the veyron network that allows our javascript library to use veyron.
+type Browspr struct {
+	rt             veyron2.Runtime
+	listenSpec     ipc.ListenSpec
+	identdEP       string
+	namespaceRoots []string
+	logger         vlog.Logger
+	accountManager *account.AccountManager
+	postMessage    func(instanceId int32, ty, msg string)
+
+	activeInstances map[int32]*pipe
+}
+
+// Create a new Browspr instance.
+func NewBrowspr(postMessage func(instanceId int32, ty, msg string), listenSpec ipc.ListenSpec, identdEP string, namespaceRoots []string, opts ...veyron2.ROpt) *Browspr {
+	if listenSpec.Proxy == "" {
+		vlog.Fatalf("a veyron proxy must be set")
+	}
+	if identdEP == "" {
+		vlog.Fatalf("an identd server must be set")
+	}
+
+	newrt, err := rt.New(opts...)
+	if err != nil {
+		vlog.Fatalf("rt.New failed: %s", err)
+	}
+	if namespaceRoots != nil {
+		newrt.Namespace().SetRoots(namespaceRoots...)
+	}
+
+	browspr := &Browspr{
+		listenSpec:      listenSpec,
+		identdEP:        identdEP,
+		namespaceRoots:  namespaceRoots,
+		postMessage:     postMessage,
+		rt:              newrt,
+		logger:          newrt.Logger(),
+		activeInstances: make(map[int32]*pipe),
+	}
+
+	// TODO(nlacasse, bjornick) use a serializer that can actually persist.
+	var principalManager *principal.PrincipalManager
+	if principalManager, err = principal.NewPrincipalManager(newrt.Principal(), &principal.InMemorySerializer{}); err != nil {
+		vlog.Fatalf("principal.NewPrincipalManager failed: %s", err)
+	}
+
+	browspr.accountManager = account.NewAccountManager(newrt, identdEP, principalManager)
+
+	return browspr
+}
+
+func (browspr *Browspr) Shutdown() {
+	browspr.rt.Cleanup()
+}
+
+// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted connections.
+// It's used by ListenAndServe and ListenAndServeTLS so dead TCP connections
+// (e.g. closing laptop mid-download) eventually go away.
+// Copied from http/server.go, since it's not exported.
+type tcpKeepAliveListener struct {
+	*net.TCPListener
+}
+
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+	tc, err := ln.AcceptTCP()
+	if err != nil {
+		return
+	}
+	tc.SetKeepAlive(true)
+	tc.SetKeepAlivePeriod(3 * time.Minute)
+	return tc, nil
+}
+
+// HandleMessage handles most messages from javascript and forwards them to a Controller.
+func (b *Browspr) HandleMessage(instanceId int32, msg string) error {
+	instance, ok := b.activeInstances[instanceId]
+	if !ok {
+		instance = newPipe(b, instanceId)
+		b.activeInstances[instanceId] = instance
+	}
+
+	return instance.handleMessage(msg)
+}
+
+// HandleCleanupMessage cleans up the specified instance state. (For instance, when a browser tab is closed)
+func (b *Browspr) HandleCleanupMessage(instanceId int32) {
+	if instance, ok := b.activeInstances[instanceId]; ok {
+		instance.cleanup()
+		delete(b.activeInstances, instanceId)
+	}
+}
+
+// HandleCreateAccountMessage creates an account for the specified instance.
+func (b *Browspr) HandleCreateAccountMessage(instanceId int32, accessToken string) error {
+	account, err := b.accountManager.CreateAccount(accessToken)
+	if err != nil {
+		b.postMessage(instanceId, "createAccountFailedResponse", err.Error())
+		return err
+	}
+
+	b.postMessage(instanceId, "createAccountResponse", account)
+	return nil
+}
+
+// HandleAssociateAccountMessage associates an account with the specified origin.
+func (b *Browspr) HandleAssociateAccountMessage(origin, account string) error {
+	if err := b.accountManager.AssociateAccount(origin, account); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/services/wsprd/browspr/browspr_account_test.go b/services/wsprd/browspr/browspr_account_test.go
new file mode 100644
index 0000000..00c12e8
--- /dev/null
+++ b/services/wsprd/browspr/browspr_account_test.go
@@ -0,0 +1,161 @@
+package browspr
+
+import (
+	"fmt"
+	"testing"
+
+	"veyron.io/veyron/veyron2/context"
+	"veyron.io/veyron/veyron2/ipc"
+	"veyron.io/veyron/veyron2/security"
+
+	"veyron.io/veyron/veyron/profiles"
+)
+
+const topLevelName = "mock-blesser"
+
+// BEGIN MOCK BLESSER SERVICE
+// TODO(nlacasse): Is there a better way to mock this?!
+type mockBlesserService struct {
+	p     security.Principal
+	count int
+}
+
+func newMockBlesserService(p security.Principal) *mockBlesserService {
+	return &mockBlesserService{
+		p:     p,
+		count: 0,
+	}
+}
+
+func (m *mockBlesserService) BlessUsingAccessToken(c context.T, accessToken string, co ...ipc.CallOpt) (security.WireBlessings, string, error) {
+	m.count++
+	name := fmt.Sprintf("%s%s%d", topLevelName, security.ChainSeparator, m.count)
+	blessing, err := m.p.BlessSelf(name)
+	if err != nil {
+		return security.WireBlessings{}, "", err
+	}
+	return security.MarshalBlessings(blessing), name, nil
+}
+
+// END MOCK BLESSER SERVICE
+
+func setup(t *testing.T, postMessageHandler func(instanceId int32, ty string, msg string)) (*Browspr, func()) {
+	spec := profiles.LocalListenSpec
+	spec.Proxy = "/mock/proxy"
+	browspr := NewBrowspr(postMessageHandler, spec, "/mock/identd", nil)
+	browspr.accountManager.SetMockBlesser(newMockBlesserService(browspr.rt.Principal()))
+	return browspr, func() {
+		browspr.Shutdown()
+	}
+}
+
+func TestHandleCreateAccount(t *testing.T) {
+	lastInstanceId := int32(0)
+	lastType := ""
+	lastResponse := ""
+	postMessageHandler := func(instanceId int32, ty string, response string) {
+		lastInstanceId = instanceId
+		lastType = ty
+		lastResponse = response
+	}
+
+	browspr, teardown := setup(t, postMessageHandler)
+	defer teardown()
+
+	instanceId := int32(11) // The id of the tab / background script.
+	if err := browspr.HandleCreateAccountMessage(instanceId, "mock-access-token-1"); err != nil {
+		t.Fatalf("Failed to create account: %v", err)
+	}
+	if lastInstanceId != instanceId {
+		t.Errorf("Received incorrect instance id on first account creation: %d", lastInstanceId)
+	}
+	if lastType != "createAccountResponse" {
+		t.Errorf("Unexpected response type: %s", lastType)
+	}
+	if lastResponse != "mock-blesser/1" {
+		t.Errorf("Unexpected response: %s", lastResponse)
+	}
+
+	// Verify that principalManager has the new account
+	expectedAccount := fmt.Sprintf("%s%s%d", topLevelName, security.ChainSeparator, 1)
+	if b, err := browspr.accountManager.PrincipalManager().BlessingsForAccount(expectedAccount); err != nil || b == nil {
+		t.Fatalf("Failed to get Blessings for account %v: got %v, %v", expectedAccount, b, err)
+	}
+
+	if err := browspr.HandleCreateAccountMessage(instanceId, "mock-access-token-2"); err != nil {
+		t.Fatalf("Failed to create account: %v", err)
+	}
+	if lastInstanceId != instanceId {
+		t.Errorf("Received incorrect instance id on second account creation: %d", lastInstanceId)
+	}
+	if lastType != "createAccountResponse" {
+		t.Errorf("Unexpected response type: %s", lastType)
+	}
+	if lastResponse != "mock-blesser/2" {
+		t.Errorf("Unexpected response: %s", lastResponse)
+	}
+
+	// Verify that principalManager has the new account
+	expectedAccount2 := fmt.Sprintf("%s%s%d", topLevelName, security.ChainSeparator, 1)
+	if b, err := browspr.accountManager.PrincipalManager().BlessingsForAccount(expectedAccount2); err != nil || b == nil {
+		t.Fatalf("Failed to get Blessings for account %v: got %v, %v", expectedAccount, b, err)
+	}
+
+	// Verify that principalManager has the first account
+	if b, err := browspr.accountManager.PrincipalManager().BlessingsForAccount(expectedAccount); err != nil || b == nil {
+		t.Fatalf("Failed to get Blessings for account %v: got %v, %v", expectedAccount, b, err)
+	}
+}
+
+func TestHandleAssocAccount(t *testing.T) {
+	browspr, teardown := setup(t, nil)
+	defer teardown()
+
+	// First create an account.
+	account := "mock-account"
+	blessing, err := browspr.rt.Principal().BlessSelf(account)
+	if err != nil {
+		t.Fatalf("browspr.rt.Principal.BlessSelf(%v) failed: %v", account, err)
+	}
+	if err := browspr.accountManager.PrincipalManager().AddAccount(account, blessing); err != nil {
+		t.Fatalf("browspr.principalManager.AddAccount(%v, %v) failed; %v", account, blessing, err)
+	}
+
+	origin := "https://my.webapp.com:443"
+
+	if err := browspr.HandleAssociateAccountMessage(origin, account); err != nil {
+		t.Fatalf("Failed to associate account: %v", err)
+	}
+
+	// Verify that principalManager has the correct principal for the origin
+	got, err := browspr.accountManager.PrincipalManager().Principal(origin)
+	if err != nil {
+		t.Fatalf("browspr.principalManager.Principal(%v) failed: %v", origin, err)
+	}
+
+	if got == nil {
+		t.Fatalf("Expected browspr.principalManager.Principal(%v) to return a valid principal, but got %v", origin, got)
+	}
+}
+
+func TestHandleAssocAccountWithMissingAccount(t *testing.T) {
+	browspr, teardown := setup(t, nil)
+	defer teardown()
+
+	account := "mock-account"
+	origin := "https://my.webapp.com:443"
+
+	if err := browspr.HandleAssociateAccountMessage(origin, account); err == nil {
+		t.Fatalf("Expected to receive error associating non-existant account.")
+	}
+
+	// Verify that principalManager creates no principal for the origin
+	got, err := browspr.accountManager.PrincipalManager().Principal(origin)
+	if err == nil {
+		t.Fatalf("Expected wspr.principalManager.Principal(%v) to fail, but got: %v", origin, got)
+	}
+
+	if got != nil {
+		t.Fatalf("Expected wspr.principalManager.Principal(%v) not to return a principal, but got %v", origin, got)
+	}
+}
diff --git a/services/wsprd/browspr/browspr_test.go b/services/wsprd/browspr/browspr_test.go
new file mode 100644
index 0000000..52fb83a
--- /dev/null
+++ b/services/wsprd/browspr/browspr_test.go
@@ -0,0 +1,227 @@
+package browspr
+
+import (
+	"encoding/json"
+	"testing"
+
+	"veyron.io/veyron/veyron/profiles"
+	"veyron.io/veyron/veyron/runtimes/google/ipc/stream/proxy"
+	mounttable "veyron.io/veyron/veyron/services/mounttable/lib"
+	"veyron.io/veyron/veyron2/ipc"
+	"veyron.io/veyron/veyron2/naming"
+	"veyron.io/veyron/veyron2/options"
+	"veyron.io/veyron/veyron2/rt"
+	"veyron.io/veyron/veyron2/vdl/vdlutil"
+	"veyron.io/veyron/veyron2/wiretype"
+	"veyron.io/wspr/veyron/services/wsprd/app"
+	"veyron.io/wspr/veyron/services/wsprd/lib"
+)
+
+var (
+	r = rt.Init()
+)
+
+func startProxy() (*proxy.Proxy, error) {
+	rid, err := naming.NewRoutingID()
+	if err != nil {
+		return nil, err
+	}
+	return proxy.New(rid, nil, "tcp", "127.0.0.1:0", "")
+}
+
+func startMounttable() (ipc.Server, naming.Endpoint, error) {
+	mt, err := mounttable.NewMountTable("")
+	if err != nil {
+		return nil, nil, err
+	}
+
+	s, err := r.NewServer(options.ServesMountTable(true))
+	if err != nil {
+		return nil, nil, err
+	}
+
+	endpoint, err := s.Listen(profiles.LocalListenSpec)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	if err := s.ServeDispatcher("", mt); err != nil {
+		return nil, nil, err
+	}
+
+	return s, endpoint, nil
+}
+
+type mockServer struct{}
+
+func (s mockServer) BasicCall(_ ipc.ServerCall, txt string) (string, error) {
+	return "[" + txt + "]", nil
+}
+
+func (s mockServer) Signature(call ipc.ServerCall) (ipc.ServiceSignature, error) {
+	result := ipc.ServiceSignature{Methods: make(map[string]ipc.MethodSignature)}
+	result.Methods["BasicCall"] = ipc.MethodSignature{
+		InArgs: []ipc.MethodArgument{
+			{Name: "Txt", Type: 3},
+		},
+		OutArgs: []ipc.MethodArgument{
+			{Name: "Value", Type: 3},
+			{Name: "Err", Type: 65},
+		},
+	}
+	result.TypeDefs = []vdlutil.Any{
+		wiretype.NamedPrimitiveType{Type: 0x1, Name: "error", Tags: []string(nil)}}
+
+	return result, nil
+}
+
+func startMockServer(desiredName string) (ipc.Server, naming.Endpoint, error) {
+	// Create a new server instance.
+	s, err := r.NewServer()
+	if err != nil {
+		return nil, nil, err
+	}
+
+	endpoint, err := s.Listen(profiles.LocalListenSpec)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	if err := s.ServeDispatcher(desiredName, ipc.LeafDispatcher(mockServer{}, nil)); err != nil {
+		return nil, nil, err
+	}
+
+	return s, endpoint, nil
+}
+
+type veyronTempRPC struct {
+	Name        string
+	Method      string
+	InArgs      []json.RawMessage
+	NumOutArgs  int32
+	IsStreaming bool
+	Timeout     int64
+}
+
+func TestBrowspr(t *testing.T) {
+	proxy, err := startProxy()
+	if err != nil {
+		t.Fatalf("Failed to start proxy: %v", err)
+	}
+	defer proxy.Shutdown()
+
+	mtServer, mtEndpoint, err := startMounttable()
+	if err != nil {
+		t.Fatalf("Failed to start mounttable server: %v", err)
+	}
+	defer mtServer.Stop()
+	if err := r.Namespace().SetRoots("/" + mtEndpoint.String()); err != nil {
+		t.Fatalf("Failed to set namespace roots: %v", err)
+	}
+
+	mockServerName := "mock/server"
+	mockServer, mockServerEndpoint, err := startMockServer(mockServerName)
+	if err != nil {
+		t.Fatalf("Failed to start mock server: %v", err)
+	}
+	defer mockServer.Stop()
+
+	names, err := mockServer.Published()
+	if err != nil {
+		t.Fatalf("Error fetching published names: %v", err)
+	}
+	if len(names) != 1 || names[0] != "/"+mtEndpoint.String()+"/"+mockServerName {
+		t.Fatalf("Incorrectly mounted server. Names: %v", names)
+	}
+	mountEntry, err := r.Namespace().ResolveX(nil, mockServerName)
+	if err != nil {
+		t.Fatalf("Error fetching published names from mounttable: %v", err)
+	}
+	if len(mountEntry.Servers) != 1 || mountEntry.Servers[0].Server != "/"+mockServerEndpoint.String() {
+		t.Fatalf("Incorrect names retrieved from mounttable: %v", mountEntry)
+	}
+
+	spec := profiles.LocalListenSpec
+	spec.Proxy = proxy.Endpoint().String()
+
+	receivedResponse := make(chan bool, 1)
+	var receivedInstanceId int32
+	var receivedType string
+	var receivedMsg string
+
+	var postMessageHandler = func(instanceId int32, ty, msg string) {
+		receivedInstanceId = instanceId
+		receivedType = ty
+		receivedMsg = msg
+		receivedResponse <- true
+	}
+
+	browspr := NewBrowspr(postMessageHandler, spec, "/mock/identd", []string{"/" + mtEndpoint.String()}, options.RuntimePrincipal{r.Principal()})
+
+	principal := browspr.rt.Principal()
+	browspr.accountManager.SetMockBlesser(newMockBlesserService(principal))
+
+	msgInstanceId := int32(11)
+
+	rpcMessage := veyronTempRPC{
+		Name:   mockServerName,
+		Method: "BasicCall",
+		InArgs: []json.RawMessage{
+			json.RawMessage([]byte("\"InputValue\"")),
+		},
+		NumOutArgs:  2,
+		IsStreaming: false,
+		Timeout:     (1 << 31) - 1,
+	}
+
+	jsonRpcMessage, err := json.Marshal(rpcMessage)
+	if err != nil {
+		t.Fatalf("Failed to marshall rpc message to json: %v", err)
+	}
+
+	msg, err := json.Marshal(app.Message{
+		Id:   1,
+		Data: string(jsonRpcMessage),
+		Type: app.VeyronRequestMessage,
+	})
+	if err != nil {
+		t.Fatalf("Failed to marshall app message to json: %v", err)
+	}
+
+	err = browspr.HandleMessage(msgInstanceId, string(msg))
+	if err != nil {
+		t.Fatalf("Error while handling message: %v", err)
+	}
+
+	<-receivedResponse
+
+	if receivedInstanceId != msgInstanceId {
+		t.Errorf("Received unexpected instance id: %d. Expected: %d", receivedInstanceId, msgInstanceId)
+	}
+	if receivedType != "msg" {
+		t.Errorf("Received unexpected response type. Expected: %q, but got %q", "msg", receivedType)
+	}
+
+	var outMsg app.Message
+	if err := json.Unmarshal([]byte(receivedMsg), &outMsg); err != nil {
+		t.Fatalf("Failed to unmarshall outgoing message: %v", err)
+	}
+	if outMsg.Id != int64(1) {
+		t.Errorf("Id was %v, expected %v", outMsg.Id, int64(1))
+	}
+	if outMsg.Type != app.VeyronRequestMessage {
+		t.Errorf("Message type was %v, expected %v", outMsg.Type, app.MessageType(0))
+	}
+
+	var responseMsg app.Response
+	if err := json.Unmarshal([]byte(outMsg.Data), &responseMsg); err != nil {
+		t.Fatalf("Failed to unmarshall outgoing response: %v", err)
+	}
+	if responseMsg.Type != lib.ResponseFinal {
+		t.Errorf("Data was %q, expected %q", outMsg.Data, `["[InputValue]"]`)
+	}
+	outArgs := responseMsg.Message.([]interface{})
+	if len(outArgs) != 1 || outArgs[0].(string) != "[InputValue]" {
+		t.Errorf("Got unexpected response message body: %v", responseMsg.Message)
+	}
+}
diff --git a/services/wsprd/browspr/main/main_nacl.go b/services/wsprd/browspr/main/main_nacl.go
new file mode 100644
index 0000000..eea6cb6
--- /dev/null
+++ b/services/wsprd/browspr/main/main_nacl.go
@@ -0,0 +1,258 @@
+package main
+
+import (
+	"bytes"
+	"crypto/ecdsa"
+	"fmt"
+	"runtime/ppapi"
+
+	"veyron.io/veyron/veyron2/ipc"
+	"veyron.io/veyron/veyron2/options"
+	"veyron.io/veyron/veyron2/rt"
+	"veyron.io/veyron/veyron2/security"
+	"veyron.io/veyron/veyron2/vlog"
+	"veyron.io/wspr/veyron/services/wsprd/browspr"
+
+	_ "veyron.io/veyron/veyron/profiles"
+	vsecurity "veyron.io/veyron/veyron/security"
+)
+
+func main() {
+	ppapi.Init(newBrowsprInstance)
+}
+
+// WSPR instance represents an instance of a PPAPI client and receives callbacks from PPAPI to handle events.
+type browsprInstance struct {
+	ppapi.Instance
+	browspr *browspr.Browspr
+}
+
+var _ ppapi.InstanceHandlers = (*browsprInstance)(nil)
+
+func newBrowsprInstance(inst ppapi.Instance) ppapi.InstanceHandlers {
+	return &browsprInstance{
+		Instance: inst,
+	}
+}
+
+// StartBrowspr handles starting browspr.
+func (inst *browsprInstance) StartBrowspr(message ppapi.Var) error {
+	// HACK!!
+	// TODO(ataly, ashankar, bprosnitz): The private key should be
+	// generated/retrieved by directly talking to some secure storage
+	// in Chrome, e.g. LocalStorage (and not from the config as below).
+	pemKey, err := message.LookupStringValuedKey("pemPrivateKey")
+	if err != nil {
+		return err
+	}
+
+	// TODO(ataly, ashankr, bprosnitz): Figure out whether we need
+	// passphrase protection here (most likely we do but how do we
+	// request the passphrase from the user?)
+	key, err := vsecurity.LoadPEMKey(bytes.NewBufferString(pemKey), nil)
+	if err != nil {
+		return err
+	}
+	ecdsaKey, ok := key.(*ecdsa.PrivateKey)
+	if !ok {
+		return fmt.Errorf("got key of type %T, want *ecdsa.PrivateKey", key)
+	}
+
+	principal, err := vsecurity.NewPrincipalFromSigner(security.NewInMemoryECDSASigner(ecdsaKey))
+	if err != nil {
+		return err
+	}
+
+	defaultBlessingName, err := message.LookupStringValuedKey("defaultBlessingName")
+	if err != nil {
+		return err
+	}
+
+	if err := vsecurity.InitDefaultBlessings(principal, defaultBlessingName); err != nil {
+		return err
+	}
+	runtime := rt.Init(options.RuntimePrincipal{principal})
+
+	veyronProxy, err := message.LookupStringValuedKey("proxyName")
+	if err != nil {
+		return err
+	}
+	if veyronProxy == "" {
+		return fmt.Errorf("proxyName field was empty")
+	}
+
+	mounttable, err := message.LookupStringValuedKey("namespaceRoot")
+	if err != nil {
+		return err
+	}
+	runtime.Namespace().SetRoots(mounttable)
+
+	identd, err := message.LookupStringValuedKey("identityd")
+	if err != nil {
+		return err
+	}
+
+	// TODO(cnicolaou,bprosnitz) Should we use the roaming profile?
+	// It uses flags. We should change that.
+	listenSpec := ipc.ListenSpec{
+		Proxy:    veyronProxy,
+		Protocol: "tcp",
+		Address:  ":0",
+	}
+
+	fmt.Printf("Starting browspr with config: proxy=%q mounttable=%q identityd=%q ", veyronProxy, mounttable, identd)
+	inst.browspr = browspr.NewBrowspr(inst.BrowsprOutgoingPostMessage, listenSpec, identd, []string{mounttable}, options.RuntimePrincipal{principal})
+}
+
+func (inst *browsprInstance) BrowsprOutgoingPostMessage(instanceId int32, ty string, message string) {
+	dict := ppapi.NewDictVar()
+	instVar := ppapi.VarFromInt(instanceId)
+	msgVar := ppapi.VarFromString(message)
+	tyVar := ppapi.VarFromString(ty)
+	dict.DictionarySet("instanceId", instVar)
+	dict.DictionarySet("type", tyVar)
+	dict.DictionarySet("msg", msgVar)
+	inst.PostMessage(dict)
+	instVar.Release()
+	msgVar.Release()
+	tyVar.Release()
+	dict.Release()
+}
+
+func (inst *browsprInstance) HandleBrowsprMessage(message ppapi.Var) error {
+	instanceId, err := message.LookupIntValuedKey("instanceId")
+	if err != nil {
+		return err
+	}
+
+	msg, err := message.LookupStringValuedKey("msg")
+	if err != nil {
+		return err
+	}
+
+	if err := inst.browspr.HandleMessage(int32(instanceId), msg); err != nil {
+		// TODO(bprosnitz) Remove. We shouldn't panic on user input.
+		return fmt.Errorf("Error while handling message in browspr: %v", err)
+	}
+}
+
+func (inst *browsprInstance) HandleBrowsprCleanup(message ppapi.Var) error {
+	instanceId, err := message.LookupIntValuedKey("instanceId")
+	if err != nil {
+		return err
+	}
+
+	inst.browspr.HandleCleanupMessage(int32(instanceId))
+	return nil
+}
+
+func (inst *browsprInstance) HandleBrowsprCreateAccount(message ppapi.Var) error {
+	instanceId, err := message.LookupIntValuedKey("instanceId")
+	if err != nil {
+		return err
+	}
+
+	accessToken, err := message.LookupStringValuedKey("accessToken")
+	if err != nil {
+		return err
+	}
+
+	err = inst.browspr.HandleCreateAccountMessage(instanceId, accessToken)
+	if err != nil {
+		// TODO(bprosnitz) Remove. We shouldn't panic on user input.
+		panic(fmt.Sprintf("Error creating account: %v", err))
+	}
+}
+
+func (inst *browsprInstance) HandleBrowsprAssociateAccount(message ppapi.Var) error {
+	origin, err := message.LookupStringValuedKey("origin")
+	if err != nil {
+		return err
+	}
+
+	account, err := message.LookupStringValuedKey("account")
+	if err != nil {
+		return err
+	}
+
+	err = inst.browspr.HandleAssociateAccountMessage(origin, account)
+	if err != nil {
+		// TODO(bprosnitz) Remove. We shouldn't panic on user input.
+		return fmt.Errorf("Error associating account: %v", err)
+	}
+}
+
+// handleGoError handles error returned by go code.
+func (inst *browsprInstance) handleGoError(err error) {
+	vlog.V(2).Error(err)
+	inst.LogString(fmt.Sprintf("Error in go code: %v", err.Error()))
+}
+
+type handlerType func(ppapi.Var)
+
+var messageHandlers = map[string]handlerType{
+	"start":                   inst.StartBrowspr,
+	"browsprMsg":              inst.HandleBrowsprMessage,
+	"browpsrClose":            inst.HandleBrowsprCleanup,
+	"browsprCreateAccount":    inst.HandleBrowsprCreateAccount,
+	"browsprAssociateAccount": inst.HandleBrowsprAssociateAccount,
+}
+
+// HandleMessage receives messages from Javascript and uses them to perform actions.
+// A message is of the form {"type": "typeName", "body": { stuff here }},
+// where the body is passed to the message handler.
+func (inst *browsprInstance) HandleMessage(message ppapi.Var) {
+	fmt.Printf("Entered HandleMessage")
+	ty, err := message.LookupStringValuedKey("type")
+	if err != nil {
+		return handleGoError(err)
+	}
+	h, ok := messageHandlers[ty]
+	if !ok {
+		return handleGoError("No handler found for message type: %q", ty)
+	}
+	body, err := message.LookupKey("body")
+	if err != nil {
+		body = ppapi.VarUndefined
+	}
+	err = h(body)
+	body.Release()
+	if err != nil {
+		handleGoError(err)
+	}
+}
+
+func (inst browsprInstance) DidCreate(args map[string]string) bool {
+	fmt.Printf("Got to DidCreate")
+	return true
+}
+
+func (*browsprInstance) DidDestroy() {
+	fmt.Printf("Got to DidDestroy()")
+}
+
+func (*browsprInstance) DidChangeView(view ppapi.View) {
+	fmt.Printf("Got to DidChangeView(%v)", view)
+}
+
+func (*browsprInstance) DidChangeFocus(has_focus bool) {
+	fmt.Printf("Got to DidChangeFocus(%v)", has_focus)
+}
+
+func (*browsprInstance) HandleDocumentLoad(url_loader ppapi.Resource) bool {
+	fmt.Printf("Got to HandleDocumentLoad(%v)", url_loader)
+	return true
+}
+
+func (*browsprInstance) HandleInputEvent(event ppapi.InputEvent) bool {
+	fmt.Printf("Got to HandleInputEvent(%v)", event)
+	return true
+}
+
+func (*browsprInstance) Graphics3DContextLost() {
+	fmt.Printf("Got to Graphics3DContextLost()")
+}
+
+func (*browsprInstance) MouseLockLost() {
+	fmt.Printf("Got to MouseLockLost()")
+}
diff --git a/services/wsprd/browspr/pipe.go b/services/wsprd/browspr/pipe.go
new file mode 100644
index 0000000..9406bd4
--- /dev/null
+++ b/services/wsprd/browspr/pipe.go
@@ -0,0 +1,68 @@
+package browspr
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"veyron.io/veyron/veyron2/options"
+	"veyron.io/wspr/veyron/services/wsprd/app"
+	"veyron.io/wspr/veyron/services/wsprd/lib"
+)
+
+// pipe controls the flow of messages for a specific instance (corresponding to a specific tab).
+type pipe struct {
+	browspr    *Browspr
+	controller *app.Controller
+	instanceId int32
+}
+
+func newPipe(b *Browspr, instanceId int32) *pipe {
+	pipe := &pipe{
+		browspr:    b,
+		instanceId: instanceId,
+	}
+
+	// TODO(bprosnitz) Principal() maybe should not take a string in the future.
+	p, err := b.accountManager.LookupPrincipal(fmt.Sprintf("%d", instanceId))
+	if err != nil {
+		p = b.rt.Principal()
+		b.rt.Logger().Errorf("No principal associated with instanceId %d: %v", instanceId, err)
+		// TODO(bjornick): Send an error to the client when all of the principal stuff is set up.
+	}
+
+	pipe.controller, err = app.NewController(pipe.createWriter, &b.listenSpec, b.namespaceRoots, options.RuntimePrincipal{p})
+	if err != nil {
+		b.rt.Logger().Errorf("Could not create controller: %v", err)
+		return nil
+	}
+
+	return pipe
+}
+
+func (p *pipe) createWriter(messageId int64) lib.ClientWriter {
+	return &postMessageWriter{
+		messageId: messageId,
+		p:         p,
+	}
+}
+
+func (p *pipe) cleanup() {
+	p.browspr.logger.VI(0).Info("Cleaning up websocket")
+	p.controller.Cleanup()
+}
+
+func (p *pipe) handleMessage(jsonMsg string) error {
+	var msg app.Message
+	if err := json.Unmarshal([]byte(jsonMsg), &msg); err != nil {
+		fullErr := fmt.Errorf("Can't unmarshall message: %s error: %v", jsonMsg, err)
+		// Send the failed to unmarshal error to the client.
+		errWriter := &postMessageWriter{p: p}
+		errWriter.Error(fullErr)
+		return fullErr
+	}
+
+	writer := p.createWriter(msg.Id)
+	context := p.browspr.rt.NewContext()
+	p.controller.HandleIncomingMessage(context, msg, writer)
+	return nil
+}
diff --git a/services/wsprd/browspr/writer.go b/services/wsprd/browspr/writer.go
new file mode 100644
index 0000000..bf8e3dd
--- /dev/null
+++ b/services/wsprd/browspr/writer.go
@@ -0,0 +1,26 @@
+package browspr
+
+import (
+	"veyron.io/wspr/veyron/services/wsprd/app"
+	"veyron.io/wspr/veyron/services/wsprd/lib"
+)
+
+// postMessageWriter is a lib.ClientWriter that handles sending messages over postMessage to the extension.
+type postMessageWriter struct {
+	messageId int64
+	p         *pipe
+}
+
+func (w *postMessageWriter) Send(messageType lib.ResponseType, data interface{}) error {
+	outMsg, err := app.ConstructOutgoingMessage(w.messageId, messageType, data)
+	if err != nil {
+		return err
+	}
+
+	w.p.browspr.postMessage(w.p.instanceId, "msg", outMsg)
+	return nil
+}
+
+func (w *postMessageWriter) Error(err error) {
+	w.Send(lib.ResponseError, app.FormatAsVerror(err, w.p.browspr.logger))
+}
diff --git a/services/wsprd/wspr/wspr.go b/services/wsprd/wspr/wspr.go
index 024c13c..40c0703 100644
--- a/services/wsprd/wspr/wspr.go
+++ b/services/wsprd/wspr/wspr.go
@@ -23,17 +23,15 @@
 	"net"
 	"net/http"
 	_ "net/http/pprof"
-	"strings"
 	"sync"
 	"time"
 
 	"veyron.io/veyron/veyron2"
-	"veyron.io/veyron/veyron2/context"
 	"veyron.io/veyron/veyron2/ipc"
 	"veyron.io/veyron/veyron2/rt"
-	"veyron.io/veyron/veyron2/security"
 	"veyron.io/veyron/veyron2/vlog"
 
+	"veyron.io/wspr/veyron/services/wsprd/account"
 	"veyron.io/wspr/veyron/services/wsprd/principal"
 )
 
@@ -42,32 +40,6 @@
 	pongTimeout  = pingInterval + 10*time.Second // maximum wait for pong.
 )
 
-type blesserService interface {
-	BlessUsingAccessToken(ctx context.T, token string, opts ...ipc.CallOpt) (blessingObj security.WireBlessings, account string, err error)
-}
-
-type bs struct {
-	client ipc.Client
-	name   string
-}
-
-func (s *bs) BlessUsingAccessToken(ctx context.T, token string, opts ...ipc.CallOpt) (blessingObj security.WireBlessings, account string, err error) {
-	var call ipc.Call
-	if call, err = s.client.StartCall(ctx, s.name, "BlessUsingAccessToken", []interface{}{token}, opts...); err != nil {
-		return
-	}
-	var email string
-	if ierr := call.Finish(&blessingObj, &email, &err); ierr != nil {
-		err = ierr
-	}
-	serverBlessings, _ := call.RemoteBlessings()
-	return blessingObj, accountName(serverBlessings, email), nil
-}
-
-func accountName(serverBlessings []string, email string) string {
-	return strings.Join(serverBlessings, "#") + security.ChainSeparator + email
-}
-
 type WSPR struct {
 	mu      sync.Mutex
 	tlsCert *tls.Certificate
@@ -80,7 +52,7 @@
 	identdEP         string
 	namespaceRoots   []string
 	principalManager *principal.PrincipalManager
-	blesser          blesserService
+	accountManager   *account.AccountManager
 	pipes            map[*http.Request]*pipe
 }
 
@@ -128,9 +100,6 @@
 
 // Starts serving http requests. This method is blocking.
 func (ctx *WSPR) Serve() {
-	// Initialize the Blesser service.
-	ctx.blesser = &bs{client: ctx.rt.Client(), name: ctx.identdEP}
-
 	// Configure HTTP routes.
 	http.HandleFunc("/debug", ctx.handleDebug)
 	http.HandleFunc("/create-account", ctx.handleCreateAccount)
@@ -189,6 +158,8 @@
 		vlog.Fatalf("principal.NewPrincipalManager failed: %s", err)
 	}
 
+	wspr.accountManager = account.NewAccountManager(newrt, identdEP, wspr.principalManager)
+
 	return wspr
 }
 
@@ -260,24 +231,9 @@
 		ctx.logAndSendBadReqErr(w, fmt.Sprintf("Error parsing body: %v", err))
 	}
 
-	// Get a blessing for the access token from blessing server.
-	rctx, cancel := ctx.rt.NewContext().WithTimeout(time.Minute)
-	defer cancel()
-	blessingsAny, account, err := ctx.blesser.BlessUsingAccessToken(rctx, data.AccessToken)
+	account, err := ctx.accountManager.CreateAccount(data.AccessToken)
 	if err != nil {
-		ctx.logAndSendBadReqErr(w, fmt.Sprintf("Error getting blessing for access token: %v", err))
-		return
-	}
-
-	accountBlessings, err := security.NewBlessings(blessingsAny)
-	if err != nil {
-		ctx.logAndSendBadReqErr(w, fmt.Sprintf("Error creating blessings from wire data: %v", err))
-		return
-	}
-	// Add accountBlessings to principalManager under the provided
-	// account.
-	if err := ctx.principalManager.AddAccount(account, accountBlessings); err != nil {
-		ctx.logAndSendBadReqErr(w, fmt.Sprintf("Error adding account: %v", err))
+		ctx.logAndSendBadReqErr(w, err.Error())
 		return
 	}
 
@@ -315,10 +271,8 @@
 		http.Error(w, fmt.Sprintf("Error parsing body: %v", err), http.StatusBadRequest)
 	}
 
-	// Store the origin.
-	// TODO(nlacasse, bjornick): determine what the caveats should be.
-	if err := ctx.principalManager.AddOrigin(data.Origin, data.Account, nil); err != nil {
-		http.Error(w, fmt.Sprintf("Error associating account: %v", err), http.StatusBadRequest)
+	if err := ctx.accountManager.AssociateAccount(data.Origin, data.Account); err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 	}
 
diff --git a/services/wsprd/wspr/wspr_test.go b/services/wsprd/wspr/wspr_account_test.go
similarity index 98%
rename from services/wsprd/wspr/wspr_test.go
rename to services/wsprd/wspr/wspr_account_test.go
index 4e36af1..b429960 100644
--- a/services/wsprd/wspr/wspr_test.go
+++ b/services/wsprd/wspr/wspr_account_test.go
@@ -33,7 +33,7 @@
 
 func (m *mockBlesserService) BlessUsingAccessToken(c context.T, accessToken string, co ...ipc.CallOpt) (security.WireBlessings, string, error) {
 	var empty security.WireBlessings
-	m.count = m.count + 1
+	m.count++
 	name := fmt.Sprintf("%s%s%d", topLevelName, security.ChainSeparator, m.count)
 	blessing, err := m.p.BlessSelf(name)
 	if err != nil {
@@ -48,7 +48,7 @@
 	spec := profiles.LocalListenSpec
 	spec.Proxy = "/mock/proxy"
 	wspr := NewWSPR(0, spec, "/mock/identd", nil)
-	wspr.blesser = newMockBlesserService(wspr.rt.Principal())
+	wspr.accountManager.SetMockBlesser(newMockBlesserService(wspr.rt.Principal()))
 	return wspr, func() {
 		wspr.Shutdown()
 	}
diff --git a/services/wsprd/wspr_nacl/main_nacl.go b/services/wsprd/wspr_nacl/main_nacl.go
deleted file mode 100644
index aa33d58..0000000
--- a/services/wsprd/wspr_nacl/main_nacl.go
+++ /dev/null
@@ -1,224 +0,0 @@
-package main
-
-import (
-	"bytes"
-	"crypto/ecdsa"
-	"fmt"
-	"runtime/ppapi"
-
-	"veyron.io/veyron/veyron2/ipc"
-	"veyron.io/veyron/veyron2/options"
-	"veyron.io/veyron/veyron2/rt"
-	"veyron.io/veyron/veyron2/security"
-	"veyron.io/wspr/veyron/services/wsprd/wspr"
-
-	_ "veyron.io/veyron/veyron/profiles"
-	vsecurity "veyron.io/veyron/veyron/security"
-)
-
-func main() {
-	ppapi.Init(newWsprInstance)
-}
-
-// WSPR instance represents an instance on a PPAPI client and receives callbacks from PPAPI to handle events.
-type wsprInstance struct {
-	ppapi.Instance
-	fs ppapi.FileSystem
-}
-
-var _ ppapi.InstanceHandlers = &wsprInstance{}
-
-const wsprKeyDir = "/wspr/keys"
-
-func (inst *wsprInstance) initFileSystem() {
-	var err error
-	// Create a filesystem.
-	if inst.fs, err = inst.CreateFileSystem(ppapi.PP_FILESYSTEMTYPE_LOCALPERSISTENT); err != nil {
-		panic(err.Error())
-	}
-	if ty := inst.fs.Type(); ty != ppapi.PP_FILESYSTEMTYPE_LOCALPERSISTENT {
-		panic(fmt.Errorf("unexpected filesystem type: %d", ty))
-	}
-	// Open filesystem with expected size of 2K
-	if err = inst.fs.OpenFS(1 << 11); err != nil {
-		panic(fmt.Errorf("failed to open filesystem:%s", err))
-	}
-	// Create directory to store wspr keys
-	if err = inst.fs.MkdirAll(wsprKeyDir); err != nil {
-		panic(fmt.Errorf("failed to create directory:%s", err))
-	}
-}
-
-func (wsprInstance) DidCreate(args map[string]string) bool {
-	fmt.Printf("Got to DidCreate")
-	return true
-}
-
-func (wsprInstance) DidDestroy() {
-	fmt.Printf("Got to DidDestroy()")
-}
-
-func (wsprInstance) DidChangeView(view ppapi.View) {
-	fmt.Printf("Got to DidChangeView(%v)", view)
-}
-
-func (wsprInstance) DidChangeFocus(has_focus bool) {
-	fmt.Printf("Got to DidChangeFocus(%v)", has_focus)
-}
-
-func (wsprInstance) HandleDocumentLoad(url_loader ppapi.Resource) bool {
-	fmt.Printf("Got to HandleDocumentLoad(%v)", url_loader)
-	return true
-}
-
-func (wsprInstance) HandleInputEvent(event ppapi.InputEvent) bool {
-	fmt.Printf("Got to HandleInputEvent(%v)", event)
-	return true
-}
-
-func (wsprInstance) Graphics3DContextLost() {
-	fmt.Printf("Got to Graphics3DContextLost()")
-}
-
-// StartWSPR handles starting WSPR.
-func (inst *wsprInstance) StartWSPR(message ppapi.Var) {
-	var ecdsaKey *ecdsa.PrivateKey
-	wsprKeyFile := wsprKeyDir + "/privateKey.pem."
-
-	// See whether we have any cached keys for WSPR
-	if rFile, err := inst.fs.Open(wsprKeyFile); err == nil {
-		fmt.Print("Opening cached wspr ecdsaPrivateKey")
-		defer rFile.Release()
-		key, err := vsecurity.LoadPEMKey(rFile, nil)
-		if err != nil {
-			panic(fmt.Errorf("failed to load wspr key:%s", err))
-		}
-		var ok bool
-		if ecdsaKey, ok = key.(*ecdsa.PrivateKey); !ok {
-			panic(fmt.Errorf("got key of type %T, want *ecdsa.PrivateKey", key))
-		}
-	} else {
-		if pemKey, err := message.LookupStringValuedKey("pemPrivateKey"); err == nil {
-			fmt.Print("Using ecdsaPrivateKey from incoming request")
-			key, err := vsecurity.LoadPEMKey(bytes.NewBufferString(pemKey), nil)
-			if err != nil {
-				panic(err.Error())
-			}
-			var ok bool
-			ecdsaKey, ok = key.(*ecdsa.PrivateKey)
-			if !ok {
-				panic(fmt.Errorf("got key of type %T, want *ecdsa.PrivateKey", key))
-			}
-		} else {
-			fmt.Print("Generating new wspr ecdsaPrivateKey")
-			// Generate new keys and store them.
-			var err error
-			if _, ecdsaKey, err = vsecurity.NewPrincipalKey(); err != nil {
-				panic(fmt.Errorf("failed to generate security key:%s", err))
-			}
-		}
-		// Persist the keys in a local file.
-		wFile, err := inst.fs.Create(wsprKeyFile)
-		if err != nil {
-			panic(fmt.Errorf("failed to create file to persist wspr keys:%s", err))
-		}
-		defer wFile.Release()
-		var b bytes.Buffer
-		if err = vsecurity.SavePEMKey(&b, ecdsaKey, nil); err != nil {
-			panic(fmt.Errorf("failed to save wspr key:%s", err))
-		}
-		if n, err := wFile.Write(b.Bytes()); n != b.Len() || err != nil {
-			panic(fmt.Errorf("failed to write wspr key:%s", err))
-		}
-	}
-
-	principal, err := vsecurity.NewPrincipalFromSigner(security.NewInMemoryECDSASigner(ecdsaKey))
-	if err != nil {
-		panic(err.Error())
-	}
-
-	defaultBlessingName, err := message.LookupStringValuedKey("defaultBlessingName")
-	if err != nil {
-		panic(err.Error())
-	}
-
-	if err := vsecurity.InitDefaultBlessings(principal, defaultBlessingName); err != nil {
-		panic(err.Error())
-	}
-	runtime := rt.Init(options.RuntimePrincipal{principal})
-
-	veyronProxy, err := message.LookupStringValuedKey("proxyName")
-	if err != nil {
-		panic(err.Error())
-	}
-	if veyronProxy == "" {
-		panic("Empty proxy")
-	}
-
-	mounttable, err := message.LookupStringValuedKey("namespaceRoot")
-	if err != nil {
-		panic(err.Error())
-	}
-	runtime.Namespace().SetRoots(mounttable)
-
-	identd, err := message.LookupStringValuedKey("identityd")
-	if err != nil {
-		panic(err.Error())
-	}
-
-	wsprHttpPort, err := message.LookupIntValuedKey("wsprHttpPort")
-	if err != nil {
-		panic(err.Error())
-	}
-
-	// TODO(cnicolaou,bprosnitz) Should we use the roaming profile?
-	// It uses flags. We should change that.
-	listenSpec := ipc.ListenSpec{
-		Proxy:    veyronProxy,
-		Protocol: "tcp",
-		Address:  ":0",
-	}
-
-	fmt.Printf("Starting WSPR with config: proxy=%q mounttable=%q identityd=%q port=%d", veyronProxy, mounttable, identd, wsprHttpPort)
-	proxy := wspr.NewWSPR(wsprHttpPort, listenSpec, identd, []string{mounttable}, options.RuntimePrincipal{principal})
-
-	proxy.Listen()
-	go func() {
-		proxy.Serve()
-	}()
-}
-
-// HandleMessage receives messages from Javascript and uses them to perform actions.
-// A message is of the form {"type": "typeName", "body": { stuff here }},
-// where the body is passed to the message handler.
-func (inst *wsprInstance) HandleMessage(message ppapi.Var) {
-	fmt.Printf("Entered HandleMessage\n")
-	type handlerType func(ppapi.Var)
-	handlerMap := map[string]handlerType{
-		"start": inst.StartWSPR,
-	}
-	ty, err := message.LookupStringValuedKey("type")
-	if err != nil {
-		panic(err.Error())
-	}
-	h, ok := handlerMap[ty]
-	if !ok {
-		panic(fmt.Sprintf("No handler found for message type: %q", ty))
-	}
-	body, err := message.LookupKey("body")
-	if err != nil {
-		body = ppapi.VarFromString("INVALID")
-	}
-	h(body)
-	body.Release()
-}
-
-func (wsprInstance) MouseLockLost() {
-	fmt.Printf("Got to MouseLockLost()")
-}
-
-func newWsprInstance(inst ppapi.Instance) ppapi.InstanceHandlers {
-	wspr := &wsprInstance{Instance: inst}
-	wspr.initFileSystem()
-	return wspr
-}