From d5b7b326d17dfdd4c993a94571b3c0f57c5e724b Mon Sep 17 00:00:00 2001
From: Benjamin Wenger <ben@elixxir.ioo>
Date: Wed, 23 Sep 2020 12:54:37 -0700
Subject: [PATCH] refactored to remove the context, added version handling,
 moved permissioning to its own package, refactored new and load clients

---
 api/client.go                                 | 138 ++++++++++--------
 api/permissioning.go                          |  37 +++--
 api/version.go                                |  39 +++++
 api/version_vars.go                           |  37 +++++
 cmd/udb.go                                    |  16 +-
 cmd/version.go                                |   6 +-
 context/context.go                            |  18 ---
 context/networkManager.go                     |   2 -
 network/manager.go                            |  28 +---
 network/message/sendUnsafe.go                 |   2 +-
 permissioning/permissioning.go                |  34 +++++
 .../register.go                               |  18 +--
 .../register_test.go                          |  21 +--
 permissioning/remoteVersion.go                |  45 ++++++
 storage/regCode.go                            |  29 ++++
 storage/session.go                            |  28 +---
 16 files changed, 308 insertions(+), 190 deletions(-)
 create mode 100644 api/version.go
 create mode 100644 api/version_vars.go
 delete mode 100644 context/context.go
 create mode 100644 permissioning/permissioning.go
 rename {network/permissioning => permissioning}/register.go (65%)
 rename {network/permissioning => permissioning}/register_test.go (85%)
 create mode 100644 permissioning/remoteVersion.go
 create mode 100644 storage/regCode.go

diff --git a/api/client.go b/api/client.go
index 86cb1775c..1d1e91815 100644
--- a/api/client.go
+++ b/api/client.go
@@ -16,9 +16,11 @@ import (
 	"gitlab.com/elixxir/client/context"
 	"gitlab.com/elixxir/client/context/params"
 	"gitlab.com/elixxir/client/context/stoppable"
-	"gitlab.com/elixxir/client/context/switchboard"
 	"gitlab.com/elixxir/client/network"
+	"gitlab.com/elixxir/client/permissioning"
 	"gitlab.com/elixxir/client/storage"
+	"gitlab.com/elixxir/client/switchboard"
+	"gitlab.com/elixxir/comms/client"
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/elixxir/crypto/csprng"
 	"gitlab.com/elixxir/crypto/cyclic"
@@ -32,17 +34,29 @@ import (
 )
 
 type Client struct {
+	//generic RNG for client
+	rng *fastRNG.StreamGenerator
+	// the storage session securely stores data to disk and memoizes as is
+	// appropriate
 	storage     *storage.Session
-	ctx         *context.Context
+	//the switchboard is used for inter-process signaling about received messages
 	switchboard *switchboard.Switchboard
-	network     context.NetworkManager
+	//object used for communications
+	comms *client.Comms
+
+	// note that the manager has a pointer to the context in many cases, but
+	// this interface allows it to be mocked for easy testing without the
+	// loop
+	network context.NetworkManager
+	//object used to register and communicate with permissioning
+	permissioning *permissioning.Permissioning
 }
 
 // NewClient creates client storage, generates keys, connects, and registers
 // with the network. Note that this does not register a username/identity, but
 // merely creates a new cryptographic identity for adding such information
 // at a later date.
-func NewClient(netJSON, storageDir string, password []byte) (*Client, error) {
+func NewClient(defJSON, storageDir string, password []byte) (*Client, error) {
 	if clientStorageExists(storageDir) {
 		return nil, errors.Errorf("client already exists at %s",
 			storageDir)
@@ -53,58 +67,28 @@ func NewClient(netJSON, storageDir string, password []byte) (*Client, error) {
 	rngStream := rngStreamGen.GetStream()
 
 	// Parse the NDF
-	ndf, err := parseNDF(netJSON)
+	def, err := parseNDF(defJSON)
 	if err != nil {
 		return nil, err
 	}
-	cmixGrp, e2eGrp := decodeGroups(ndf)
+	cmixGrp, e2eGrp := decodeGroups(def)
 
-	user := createNewUser(rngStream, cmixGrp, e2eGrp)
+	protoUser := createNewUser(rngStream, cmixGrp, e2eGrp)
 
 	// Create Storage
 	passwordStr := string(password)
 	storageSess, err := storage.New(storageDir, passwordStr,
-		user.UID, user.Salt, user.RSAKey, user.IsPrecanned,
-		user.CMixKey, user.E2EKey, cmixGrp, e2eGrp, rngStreamGen)
+		protoUser.UID, protoUser.Salt, protoUser.RSAKey, protoUser.IsPrecanned,
+		protoUser.CMixKey, protoUser.E2EKey, cmixGrp, e2eGrp, rngStreamGen)
 	if err != nil {
 		return nil, err
 	}
 
 	// Save NDF to be used in the future
-	err = storageSess.SetNDF(netJSON)
-	if err != nil {
-		return nil, err
-	}
-
-	// Set up a new context
-	ctx := &context.Context{
-		Session:     storageSess,
-		Switchboard: switchboard.New(),
-		Rng:         rngStreamGen,
-		Manager:     nil,
-	}
+	storageSess.SetBaseNDF(def)
 
-	// Initialize network and link it to context
-	netman, err := network.NewManager(ctx, params.GetDefaultNetwork(), ndf)
-	if err != nil {
-		return nil, err
-	}
-	ctx.Manager = netman
-
-	client := &Client{
-		storage:     storageSess,
-		ctx:         ctx,
-		switchboard: ctx.Switchboard,
-		network:     netman,
-	}
-
-	// Now register with network, note that regCode is no longer required
-	err = client.RegisterWithPermissioning("")
-	if err != nil {
-		return nil, err
-	}
-
-	return client, nil
+	//execute the rest of the loading as normal
+	return loadClient(storageSess, rngStreamGen)
 }
 
 // LoadClient initalizes a client object from existing storage.
@@ -124,40 +108,68 @@ func LoadClient(storageDir string, password []byte) (*Client, error) {
 		return nil, err
 	}
 
-	netJSON, err := storageSess.GetNDF()
+	//execute the rest of the loading as normal
+	return loadClient(storageSess, rngStreamGen)
+}
+
+// LoadClient initalizes a client object from existing storage.
+func loadClient(session *storage.Session, rngStreamGen *fastRNG.StreamGenerator) (c *Client, err error) {
+
+	// Set up a new context
+	c = &Client{
+		storage:     session,
+		switchboard: switchboard.New(),
+		rng:         rngStreamGen,
+		comms:       nil,
+		network:     nil,
+	}
+
+	//get the user from session
+	user := c.storage.User()
+	cryptoUser := user.GetCryptographicIdentity()
+
+	//start comms
+	c.comms, err = client.NewClientComms(cryptoUser.GetUserID(),
+		rsa.CreatePublicKeyPem(cryptoUser.GetRSA().GetPublic()),
+		rsa.CreatePrivateKeyPem(cryptoUser.GetRSA()),
+		cryptoUser.GetSalt())
 	if err != nil {
-		return nil, err
+		return nil, errors.WithMessage(err, "failed to load client")
 	}
-	ndf, err := parseNDF(string(netJSON))
+
+	//get the NDF to pass into permissioning and the network manager
+	def := session.GetBaseNDF()
+
+	//initialize permissioning
+	c.permissioning, err = permissioning.Init(c.comms, def)
+
+	// check the client version is up to date to the network
+	err = c.checkVersion()
 	if err != nil {
-		return nil, err
+		return nil, errors.WithMessage(err, "failed to load client")
 	}
 
-	// Set up a new context
-	ctx := &context.Context{
-		Session:     storageSess,
-		Switchboard: switchboard.New(),
-		Rng:         rngStreamGen,
-		Manager:     nil,
+	//register with permissioning if necessary
+	if c.storage.GetRegistrationStatus() == storage.KeyGenComplete {
+		err = c.registerWithPermissioning()
+		if err != nil {
+			return nil, errors.WithMessage(err, "failed to load client")
+		}
 	}
 
 	// Initialize network and link it to context
-	netman, err := network.NewManager(ctx, params.GetDefaultNetwork(), ndf)
+	c.network, err = network.NewManager(c.storage, c.switchboard, c.rng, c.comms,
+		params.GetDefaultNetwork(), def)
 	if err != nil {
 		return nil, err
 	}
-	ctx.Manager = netman
 
-	client := &Client{
-		storage:     storageSess,
-		ctx:         ctx,
-		switchboard: ctx.Switchboard,
-		network:     netman,
-	}
-
-	return client, nil
+	return c, nil
 }
 
+
+
+
 // ----- Client Functions -----
 
 // RegisterListener registers a listener callback function that is called
@@ -283,7 +295,7 @@ func (c *Client) RegisterPhone(phone string) ([]byte, error) {
 }
 
 // ConfirmRegistration sends the user discovery agent a confirmation
-// token (from Register Email/Phone) and code (string sent via Email
+// token (from register Email/Phone) and code (string sent via Email
 // or SMS to confirm ownership) to confirm ownership.
 func (c *Client) ConfirmRegistration(token, code []byte) error {
 	jww.INFO.Printf("ConfirmRegistration(%s, %s)", token, code)
diff --git a/api/permissioning.go b/api/permissioning.go
index 2a7444d7e..1d0fe051f 100644
--- a/api/permissioning.go
+++ b/api/permissioning.go
@@ -8,38 +8,37 @@ package api
 
 import (
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/elixxir/client/storage"
 )
 
 // Returns an error if registration fails.
-func (c *Client) RegisterWithPermissioning(registrationCode string) error {
-	ctx := c.ctx
-	netman := ctx.Manager
+func (c *Client) registerWithPermissioning() error {
+	userData := c.storage.User()
+	//get the users public key
+	pubKey := userData.GetCryptographicIdentity().GetRSA().GetPublic()
 
-	//Check the regState is in proper state for registration
-	regState := c.storage.GetRegistrationStatus()
-	if regState != storage.KeyGenComplete {
-		return errors.Errorf("Attempting to register before key generation!")
+	//load the registration code
+	regCode, err := c.storage.GetRegCode()
+	if err != nil {
+		return errors.WithMessage(err, "failed to register with "+
+			"permissioning")
 	}
 
-	userData := ctx.Session.User()
-
-	// Register with the permissioning server and generate user information
-	regValidationSignature, err := netman.RegisterWithPermissioning(
-		registrationCode)
+	//register with permissioning
+	regValidationSignature, err := c.permissioning.Register(pubKey, regCode)
 	if err != nil {
-		globals.Log.INFO.Printf(err.Error())
-		return err
+		return errors.WithMessage(err, "failed to register with "+
+			"permissioning")
 	}
 
-	// update the session with the registration response
+	//store the signature
 	userData.SetRegistrationValidationSignature(regValidationSignature)
 
-	err = ctx.Session.ForwardRegistrationStatus(storage.PermissioningComplete)
+	//update the registration status
+	err = c.storage.ForwardRegistrationStatus(storage.PermissioningComplete)
 	if err != nil {
-		return err
+		return errors.WithMessage(err, "failed to update local state "+
+			"after registration with permissioning")
 	}
-
 	return nil
 }
diff --git a/api/version.go b/api/version.go
new file mode 100644
index 000000000..639329b21
--- /dev/null
+++ b/api/version.go
@@ -0,0 +1,39 @@
+package api
+
+import (
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/primitives/version"
+)
+
+func (c *Client) Version() version.Version {
+	v, err := version.ParseVersion(SEMVER)
+	if err != nil {
+		jww.FATAL.Panicf("Failed to parse the client version: %s", err)
+	}
+	return v
+}
+
+func (c *Client) checkVersion() error {
+	clientVersion := c.Version()
+	jww.INFO.Printf("Client Version: %s", clientVersion)
+
+	has, netVersion, err := c.permissioning.GetNetworkVersion()
+	if err != nil {
+		return errors.WithMessage(err, "failed to get check "+
+			"version compatibility")
+	}
+	if has {
+		jww.INFO.Printf("Minimum Network Version: %v", netVersion)
+		if !version.IsCompatible(netVersion, clientVersion) {
+			return errors.Errorf("Client and Minimum Network Version are "+
+				"incompatible\n"+
+				"\tMinimum Network: %s\n"+
+				"\tClient: %s", netVersion, clientVersion)
+		}
+	} else {
+		jww.WARN.Printf("Network requires no minnimim version")
+	}
+
+	return nil
+}
diff --git a/api/version_vars.go b/api/version_vars.go
new file mode 100644
index 000000000..157aee200
--- /dev/null
+++ b/api/version_vars.go
@@ -0,0 +1,37 @@
+// Code generated by go generate; DO NOT EDIT.
+// This file was generated by robots at
+// 2020-08-10 10:46:23.193662 -0700 PDT m=+0.042594188
+package api
+
+const GITVERSION = `4ddf4b3 Merge branch 'XX-2471/XXPrimitives' into 'release'`
+const SEMVER = "1.4.0"
+const DEPENDENCIES = `module gitlab.com/elixxir/client
+
+go 1.13
+
+require (
+	github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
+	github.com/golang/protobuf v1.4.2
+	github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
+	github.com/pelletier/go-toml v1.6.0 // indirect
+	github.com/pkg/errors v0.9.1
+	github.com/smartystreets/assertions v1.0.1 // indirect
+	github.com/spf13/afero v1.2.2 // indirect
+	github.com/spf13/cast v1.3.1 // indirect
+	github.com/spf13/cobra v1.0.0
+	github.com/spf13/jwalterweatherman v1.1.0
+	github.com/spf13/pflag v1.0.5 // indirect
+	github.com/spf13/viper v1.6.2
+	gitlab.com/elixxir/comms v0.0.0-20200810165153-3039323b5656
+	gitlab.com/elixxir/crypto v0.0.0-20200806211835-b8ce4472f399
+	gitlab.com/elixxir/ekv v0.0.0-20200729182028-159355ea5842
+	gitlab.com/elixxir/primitives v0.0.0-20200805174810-86b366d1dd2d
+	gitlab.com/xx_network/comms v0.0.0-20200806235452-3a82720833ba
+	gitlab.com/xx_network/crypto v0.0.0-20200806235322-ede3c15881ce
+	gitlab.com/xx_network/primitives v0.0.0-20200804183002-f99f7a7284da
+	golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
+	gopkg.in/ini.v1 v1.52.0 // indirect
+)
+
+replace google.golang.org/grpc => github.com/grpc/grpc-go v1.27.1
+`
diff --git a/cmd/udb.go b/cmd/udb.go
index 8a3ffd4d8..a0c5982af 100644
--- a/cmd/udb.go
+++ b/cmd/udb.go
@@ -7,8 +7,8 @@
 package cmd
 
 import (
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/api"
-	"gitlab.com/elixxir/client/globals"
 	"gitlab.com/xx_network/primitives/id"
 	"strings"
 	//"time"
@@ -18,15 +18,15 @@ type callbackSearch struct{}
 
 func (cs callbackSearch) Callback(userID, pubKey []byte, err error) {
 	if err != nil {
-		globals.Log.INFO.Printf("UDB search failed: %v\n", err.Error())
+		jww.INFO.Printf("UDB search failed: %v\n", err.Error())
 	} else if len(pubKey) == 0 {
-		globals.Log.INFO.Printf("Public Key returned is empty\n")
+		jww.INFO.Printf("Public Key returned is empty\n")
 	} else {
 		userID, err := id.Unmarshal(userID)
 		if err != nil {
-			globals.Log.ERROR.Printf("Malformed user ID from successful UDB search: %v", err)
+			jww.ERROR.Printf("Malformed user ID from successful UDB search: %v", err)
 		}
-		globals.Log.INFO.Printf("UDB search successful. Returned user %v\n",
+		jww.INFO.Printf("UDB search successful. Returned user %v\n",
 			userID)
 	}
 }
@@ -38,7 +38,7 @@ func parseUdbMessage(msg string, client *api.Client) {
 	// Split the message on spaces
 	args := strings.Fields(msg)
 	if len(args) < 3 {
-		globals.Log.ERROR.Printf("UDB command must have at least three arguments!")
+		jww.ERROR.Printf("UDB command must have at least three arguments!")
 	}
 	// The first arg is the command
 	// the second is the valueType
@@ -48,8 +48,8 @@ func parseUdbMessage(msg string, client *api.Client) {
 	if strings.EqualFold(keyword, "SEARCH") {
 		//client.SearchForUser(args[2], searchCallback, 2*time.Minute)
 	} else if strings.EqualFold(keyword, "REGISTER") {
-		globals.Log.ERROR.Printf("UDB REGISTER not allowed, it is already done during user registration")
+		jww.ERROR.Printf("UDB REGISTER not allowed, it is already done during user registration")
 	} else {
-		globals.Log.ERROR.Printf("UDB command not recognized!")
+		jww.ERROR.Printf("UDB command not recognized!")
 	}
 }
diff --git a/cmd/version.go b/cmd/version.go
index 364bd0f08..c231ec506 100644
--- a/cmd/version.go
+++ b/cmd/version.go
@@ -11,7 +11,7 @@ package cmd
 import (
 	"fmt"
 	"github.com/spf13/cobra"
-	"gitlab.com/elixxir/client/globals"
+	"gitlab.com/elixxir/client/api"
 	"gitlab.com/elixxir/primitives/utils"
 )
 
@@ -19,8 +19,8 @@ import (
 const currentVersion = "1.4.0"
 
 func printVersion() {
-	fmt.Printf("Elixxir Client v%s -- %s\n\n", globals.SEMVER, globals.GITVERSION)
-	fmt.Printf("Dependencies:\n\n%s\n", globals.DEPENDENCIES)
+	fmt.Printf("Elixxir Client v%s -- %s\n\n", api.SEMVER, api.GITVERSION)
+	fmt.Printf("Dependencies:\n\n%s\n", api.DEPENDENCIES)
 }
 
 func init() {
diff --git a/context/context.go b/context/context.go
deleted file mode 100644
index 565d431e8..000000000
--- a/context/context.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package context
-
-import (
-	"gitlab.com/elixxir/client/storage"
-	"gitlab.com/elixxir/client/switchboard"
-	"gitlab.com/elixxir/crypto/fastRNG"
-)
-
-type Context struct {
-	Session     *storage.Session
-	Switchboard *switchboard.Switchboard
-	// note that the manager has a pointer to the context in many cases, but
-	// this interface allows it to be mocked for easy testing without the
-	// loop
-	Manager NetworkManager
-	//generic RNG for client
-	Rng *fastRNG.StreamGenerator
-}
diff --git a/context/networkManager.go b/context/networkManager.go
index 9f31acbee..b2803eb68 100644
--- a/context/networkManager.go
+++ b/context/networkManager.go
@@ -15,8 +15,6 @@ type NetworkManager interface {
 	SendCMIX(message format.Message, p params.CMIX) (id.Round, error)
 	GetInstance() *network.Instance
 	GetHealthTracker() HealthTracker
-	RegisterWithPermissioning(string) ([]byte, error)
-	GetRemoteVersion() (string, error)
 	GetStoppable() stoppable.Stoppable
 }
 
diff --git a/network/manager.go b/network/manager.go
index 7013d7f6f..48fc5d3fd 100644
--- a/network/manager.go
+++ b/network/manager.go
@@ -19,15 +19,12 @@ import (
 	"gitlab.com/elixxir/client/network/keyExchange"
 	"gitlab.com/elixxir/client/network/message"
 	"gitlab.com/elixxir/client/network/node"
-	"gitlab.com/elixxir/client/network/permissioning"
 	"gitlab.com/elixxir/client/network/rounds"
 	"gitlab.com/elixxir/client/storage"
 	"gitlab.com/elixxir/client/switchboard"
 	"gitlab.com/elixxir/comms/client"
 	"gitlab.com/elixxir/comms/network"
 	"gitlab.com/elixxir/crypto/fastRNG"
-	"gitlab.com/xx_network/crypto/signature/rsa"
-	"gitlab.com/xx_network/primitives/id"
 	"gitlab.com/xx_network/primitives/ndf"
 
 	"time"
@@ -87,22 +84,6 @@ func NewManager(session *storage.Session, switchboard *switchboard.Switchboard,
 	return &m, nil
 }
 
-// GetRemoteVersion contacts the permissioning server and returns the current
-// supported client version.
-func (m *manager) GetRemoteVersion() (string, error) {
-	permissioningHost, ok := m.Comms.GetHost(&id.Permissioning)
-	if !ok {
-		return "", errors.Errorf("no permissioning host with id %s",
-			id.Permissioning)
-	}
-	registrationVersion, err := m.Comms.SendGetCurrentClientVersionMessage(
-		permissioningHost)
-	if err != nil {
-		return "", err
-	}
-	return registrationVersion.Version, nil
-}
-
 // StartRunners kicks off all network reception goroutines ("threads").
 func (m *manager) StartRunners() error {
 	if m.runners.IsRunning() {
@@ -114,7 +95,7 @@ func (m *manager) StartRunners() error {
 	m.runners.Add(m.Health)
 
 	// Node Updates
-	m.runners.Add(node.StartRegistration(m.Context, m.Comms, m.NodeRegistration)) // Adding/Keys
+	m.runners.Add(node.StartRegistration(m.Instance, m.Session, m.Rng, m.Comms, m.NodeRegistration)) // Adding/Keys
 	//TODO-remover
 	//m.runners.Add(StartNodeRemover(m.Context))        // Removing
 
@@ -130,16 +111,11 @@ func (m *manager) StartRunners() error {
 	m.runners.Add(m.round.StartProcessors())
 
 	// Key exchange
-	m.runners.Add(keyExchange.Start(m.Context, m.message.GetTriggerGarbledCheckChannel()))
+	m.runners.Add(keyExchange.Start(m.Switchboard, m.Session, m, m.message.GetTriggerGarbledCheckChannel()))
 
 	return nil
 }
 
-func (m *manager) RegisterWithPermissioning(registrationCode string) ([]byte, error) {
-	pubKey := m.Session.User().GetCryptographicIdentity().GetRSA().GetPublic()
-	return permissioning.Register(m.Comms, pubKey, registrationCode)
-}
-
 // StopRunners stops all the reception goroutines
 func (m *manager) GetStoppable() stoppable.Stoppable {
 	return m.runners
diff --git a/network/message/sendUnsafe.go b/network/message/sendUnsafe.go
index 8619e521e..9dc16de88 100644
--- a/network/message/sendUnsafe.go
+++ b/network/message/sendUnsafe.go
@@ -31,7 +31,7 @@ func (m *Manager) SendUnsafe(msg message.Send, param params.Unsafe) ([]id.Round,
 	wg := sync.WaitGroup{}
 
 	for i, p := range partitions {
-		msgCmix := format.NewMessage(m.Context.Session.Cmix().GetGroup().GetP().ByteLen())
+		msgCmix := format.NewMessage(m.Session.Cmix().GetGroup().GetP().ByteLen())
 		msgCmix.SetContents(p)
 		e2e.SetUnencrypted(msgCmix, msg.Recipient)
 		wg.Add(1)
diff --git a/permissioning/permissioning.go b/permissioning/permissioning.go
new file mode 100644
index 000000000..7ebb8ac90
--- /dev/null
+++ b/permissioning/permissioning.go
@@ -0,0 +1,34 @@
+package permissioning
+
+import (
+	"github.com/pkg/errors"
+	"gitlab.com/elixxir/comms/client"
+	"gitlab.com/xx_network/comms/connect"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/ndf"
+)
+
+type Permissioning struct {
+	host  *connect.Host
+	comms *client.Comms
+}
+
+func Init(comms *client.Comms, def *ndf.NetworkDefinition) (*Permissioning, error) {
+
+	perm := Permissioning{
+		host:  nil,
+		comms: comms,
+	}
+
+	var err error
+	//add the permissioning host to comms
+	perm.host, err = comms.AddHost(&id.Permissioning, def.Registration.Address,
+		[]byte(def.Registration.TlsCertificate), false,
+		false)
+
+	if err != nil {
+		return nil, errors.WithMessage(err, "failed to create permissioning")
+	}
+
+	return &perm, nil
+}
diff --git a/network/permissioning/register.go b/permissioning/register.go
similarity index 65%
rename from network/permissioning/register.go
rename to permissioning/register.go
index ab43f1230..b7a186937 100644
--- a/network/permissioning/register.go
+++ b/permissioning/register.go
@@ -5,23 +5,21 @@ import (
 	pb "gitlab.com/elixxir/comms/mixmessages"
 	"gitlab.com/xx_network/comms/connect"
 	"gitlab.com/xx_network/crypto/signature/rsa"
-	"gitlab.com/xx_network/primitives/id"
 )
 
+func (perm *Permissioning) Register(publicKey *rsa.PublicKey, registrationCode string) ([]byte, error) {
+	return register(perm.comms, perm.host, publicKey, registrationCode)
+}
+
 // client.Comms should implement this interface
-type RegistrationMessageSender interface {
+type registrationMessageSender interface {
 	SendRegistrationMessage(host *connect.Host, message *pb.UserRegistration) (*pb.UserRegistrationConfirmation, error)
-	GetHost(*id.ID) (*connect.Host, bool)
 }
 
-//Register registers the user with optional registration code
+//register registers the user with optional registration code
 // Returns an error if registration fails.
-func Register(comms RegistrationMessageSender, publicKey *rsa.PublicKey, registrationCode string) ([]byte, error) {
-	// Send registration code and public key to RegistrationServer
-	host, ok := comms.GetHost(&id.Permissioning)
-	if !ok {
-		return nil, errors.New("Failed to find permissioning host")
-	}
+func register(comms registrationMessageSender, host *connect.Host,
+	publicKey *rsa.PublicKey, registrationCode string) ([]byte, error) {
 
 	response, err := comms.
 		SendRegistrationMessage(host,
diff --git a/network/permissioning/register_test.go b/permissioning/register_test.go
similarity index 85%
rename from network/permissioning/register_test.go
rename to permissioning/register_test.go
index 5e63abca2..bdf96a3bc 100644
--- a/network/permissioning/register_test.go
+++ b/permissioning/register_test.go
@@ -56,7 +56,7 @@ func TestRegisterWithPermissioning(t *testing.T) {
 	}
 
 	regCode := "flooble doodle"
-	sig, err := Register(&sender, key.GetPublic(), regCode)
+	sig, err := register(&sender, sender.getHost, key.GetPublic(), regCode)
 	if err != nil {
 		t.Error(err)
 	}
@@ -79,19 +79,8 @@ func TestRegisterWithPermissioning(t *testing.T) {
 	}
 }
 
-// Shows that returning an error from GetHost results in an error from
-// Register
-func TestRegisterWithPermissioning_GetHostErr(t *testing.T) {
-	var sender MockRegistrationSender
-	sender.succeedGetHost = false
-	_, err := Register(&sender, nil, "")
-	if err == nil {
-		t.Error("no error if getHost fails")
-	}
-}
-
 // Shows that returning an error from the permissioning server results in an
-// error from Register
+// error from register
 func TestRegisterWithPermissioning_ResponseErr(t *testing.T) {
 	rng := csprng.NewSystemRNG()
 	key, err := rsa.GenerateKey(rng, 256)
@@ -101,14 +90,14 @@ func TestRegisterWithPermissioning_ResponseErr(t *testing.T) {
 	var sender MockRegistrationSender
 	sender.succeedGetHost = true
 	sender.errInReply = "failure occurred on permissioning"
-	_, err = Register(&sender, key.GetPublic(), "")
+	_, err = register(&sender, nil, key.GetPublic(), "")
 	if err == nil {
 		t.Error("no error if registration fails on permissioning")
 	}
 }
 
 // Shows that returning an error from the RPC (e.g. context deadline exceeded)
-// results in an error from Register
+// results in an error from register
 func TestRegisterWithPermissioning_ConnectionErr(t *testing.T) {
 	rng := csprng.NewSystemRNG()
 	key, err := rsa.GenerateKey(rng, 256)
@@ -118,7 +107,7 @@ func TestRegisterWithPermissioning_ConnectionErr(t *testing.T) {
 	var sender MockRegistrationSender
 	sender.succeedGetHost = true
 	sender.errSendRegistration = errors.New("connection problem")
-	_, err = Register(&sender, key.GetPublic(), "")
+	_, err = register(&sender, nil, key.GetPublic(), "")
 	if err == nil {
 		t.Error("no error if e.g. context deadline exceeded")
 	}
diff --git a/permissioning/remoteVersion.go b/permissioning/remoteVersion.go
new file mode 100644
index 000000000..90a66b212
--- /dev/null
+++ b/permissioning/remoteVersion.go
@@ -0,0 +1,45 @@
+package permissioning
+
+import (
+	"github.com/pkg/errors"
+	"gitlab.com/elixxir/primitives/version"
+	pb "gitlab.com/elixxir/comms/mixmessages"
+	"gitlab.com/xx_network/comms/connect"
+)
+
+// GetNetworkVersion contacts the permissioning server and returns the current
+// supported client version.
+// returns a bool which designates if the network is enforcing versioning
+// (not enforcing versioning is mostly a debugging)
+// returns the version and an error if problems arise
+func (perm *Permissioning) GetNetworkVersion() (bool, version.Version, error) {
+	return getRemoteVersion(perm.host, perm.comms)
+}
+
+type getRemoteClientVersionComms interface {
+	SendGetCurrentClientVersionMessage(host *connect.Host) (*pb.ClientVersion, error)
+}
+
+// getRemoteVersion contacts the permissioning server and returns the current
+// supported client version.
+func getRemoteVersion(permissioningHost *connect.Host, comms getRemoteClientVersionComms) (bool, version.Version, error) {
+	//gets the remove version
+	response, err := comms.SendGetCurrentClientVersionMessage(
+		permissioningHost)
+	if err != nil {
+		return false, version.Version{}, errors.WithMessage(err,
+			"Failed to get minimum client version from network")
+	}
+	if response.Version == "" {
+		return false, version.Version{}, nil
+	}
+
+	netVersion, err := version.ParseVersion(response.Version)
+	if err != nil {
+		return false, version.Version{}, errors.WithMessagef(err,
+			"Failed to parse minimum client version %s from network",
+			response.Version)
+	}
+
+	return true, netVersion, nil
+}
diff --git a/storage/regCode.go b/storage/regCode.go
new file mode 100644
index 000000000..68e147f12
--- /dev/null
+++ b/storage/regCode.go
@@ -0,0 +1,29 @@
+package storage
+
+import (
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/client/vendor/github.com/pkg/errors"
+	"time"
+)
+
+const regCodeKey = "regCode"
+const regCodeVersion = 0
+
+// SetNDF stores a network definition json file
+func (s *Session) SetRegCode(regCode string) error {
+	return s.Set(regCodeKey,
+		&versioned.Object{
+			Version:   regCodeVersion,
+			Data:      []byte(regCode),
+			Timestamp: time.Now(),
+		})
+}
+
+// Returns the stored network definition json file
+func (s *Session) GetRegCode() (string, error) {
+	regCode, err := s.Get(regCodeKey)
+	if err != nil {
+		return "", errors.WithMessage(err, "Failed to load the regcode")
+	}
+	return string(regCode.Data), nil
+}
diff --git a/storage/session.go b/storage/session.go
index 02b3c5a8c..7367c1c00 100644
--- a/storage/session.go
+++ b/storage/session.go
@@ -10,7 +10,7 @@ package storage
 
 import (
 	"github.com/pkg/errors"
-	"gitlab.com/elixxir/client/globals"
+	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage/cmix"
 	"gitlab.com/elixxir/client/storage/conversation"
 	"gitlab.com/elixxir/client/storage/e2e"
@@ -27,7 +27,6 @@ import (
 	"gitlab.com/xx_network/primitives/ndf"
 	"sync"
 	"testing"
-	"time"
 )
 
 // Number of rounds to store in the CheckedRound buffer
@@ -217,25 +216,6 @@ func (s *Session) Partition() *partition.Store {
 	return s.partition
 }
 
-// SetNDF stores a network definition json file
-func (s *Session) SetNDF(ndfJSON string) error {
-	return s.Set("NetworkDefinition",
-		&versioned.Object{
-			Version:   uint64(1),
-			Data:      []byte(ndfJSON),
-			Timestamp: time.Now(),
-		})
-}
-
-// Returns the stored network definition json file
-func (s *Session) GetNDF() (string, error) {
-	ndf, err := s.Get("NetworkDefinition")
-	if err != nil {
-		return "", err
-	}
-	return string(ndf.Data), nil
-}
-
 // Get an object from the session
 func (s *Session) Get(key string) (*versioned.Object, error) {
 	return s.kv.Get(key)
@@ -262,7 +242,7 @@ func InitTestingSession(i interface{}) *Session {
 	case *testing.B:
 		break
 	default:
-		globals.Log.FATAL.Panicf("InitTestingSession is restricted to testing only. Got %T", i)
+		jww.FATAL.Panicf("InitTestingSession is restricted to testing only. Got %T", i)
 	}
 
 	privKey, _ := rsa.LoadPrivateKeyFromPem([]byte("-----BEGIN PRIVATE KEY-----\nMIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC7Dkb6VXFn4cdp\nU0xh6ji0nTDQUyT9DSNW9I3jVwBrWfqMc4ymJuonMZbuqK+cY2l+suS2eugevWZr\ntzujFPBRFp9O14Jl3fFLfvtjZvkrKbUMHDHFehascwzrp3tXNryiRMmCNQV55TfI\nTVCv8CLE0t1ibiyOGM9ZWYB2OjXt59j76lPARYww5qwC46vS6+3Cn2Yt9zkcrGes\nkWEFa2VttHqF910TP+DZk2R5C7koAh6wZYK6NQ4S83YQurdHAT51LKGrbGehFKXq\n6/OAXCU1JLi3kW2PovTb6MZuvxEiRmVAONsOcXKu7zWCmFjuZZwfRt2RhnpcSgzf\nrarmsGM0LZh6JY3MGJ9YdPcVGSz+Vs2E4zWbNW+ZQoqlcGeMKgsIiQ670g0xSjYI\nCqldpt79gaET9PZsoXKEmKUaj6pq1d4qXDk7s63HRQazwVLGBdJQK8qX41eCdR8V\nMKbrCaOkzD5zgnEu0jBBAwdMtcigkMIk1GRv91j7HmqwryOBHryLi6NWBY3tjb4S\no9AppDQB41SH3SwNenAbNO1CXeUqN0hHX6I1bE7OlbjqI7tXdrTllHAJTyVVjenP\nel2ApMXp+LVRdDbKtwBiuM6+n+z0I7YYerxN1gfvpYgcXm4uye8dfwotZj6H2J/u\nSALsU2v9UHBzprdrLSZk2YpozJb+CQIDAQABAoICAARjDFUYpeU6zVNyCauOM7BA\ns4FfQdHReg+zApTfWHosDQ04NIc9CGbM6e5E9IFlb3byORzyevkllf5WuMZVWmF8\nd1YBBeTftKYBn2Gwa42Ql9dl3eD0wQ1gUWBBeEoOVZQ0qskr9ynpr0o6TfciWZ5m\nF50UWmUmvc4ppDKhoNwogNU/pKEwwF3xOv2CW2hB8jyLQnk3gBZlELViX3UiFKni\n/rCfoYYvDFXt+ABCvx/qFNAsQUmerurQ3Ob9igjXRaC34D7F9xQ3CMEesYJEJvc9\nGjvr5DbnKnjx152HS56TKhK8gp6vGHJz17xtWECXD3dIUS/1iG8bqXuhdg2c+2aW\nm3MFpa5jgpAawUWc7c32UnqbKKf+HI7/x8J1yqJyNeU5SySyYSB5qtwTShYzlBW/\nyCYD41edeJcmIp693nUcXzU+UAdtpt0hkXS59WSWlTrB/huWXy6kYXLNocNk9L7g\niyx0cOmkuxREMHAvK0fovXdVyflQtJYC7OjJxkzj2rWO+QtHaOySXUyinkuTb5ev\nxNhs+ROWI/HAIE9buMqXQIpHx6MSgdKOL6P6AEbBan4RAktkYA6y5EtH/7x+9V5E\nQTIz4LrtI6abaKb4GUlZkEsc8pxrkNwCqOAE/aqEMNh91Na1TOj3f0/a6ckGYxYH\npyrvwfP2Ouu6e5FhDcCBAoIBAQDcN8mK99jtrH3q3Q8vZAWFXHsOrVvnJXyHLz9V\n1Rx/7TnMUxvDX1PIVxhuJ/tmHtxrNIXOlps80FCZXGgxfET/YFrbf4H/BaMNJZNP\nag1wBV5VQSnTPdTR+Ijice+/ak37S2NKHt8+ut6yoZjD7sf28qiO8bzNua/OYHkk\nV+RkRkk68Uk2tFMluQOSyEjdsrDNGbESvT+R1Eotupr0Vy/9JRY/TFMc4MwJwOoy\ns7wYr9SUCq/cYn7FIOBTI+PRaTx1WtpfkaErDc5O+nLLEp1yOrfktl4LhU/r61i7\nfdtafUACTKrXG2qxTd3w++mHwTwVl2MwhiMZfxvKDkx0L2gxAoIBAQDZcxKwyZOy\ns6Aw7igw1ftLny/dpjPaG0p6myaNpeJISjTOU7HKwLXmlTGLKAbeRFJpOHTTs63y\ngcmcuE+vGCpdBHQkaCev8cve1urpJRcxurura6+bYaENO6ua5VzF9BQlDYve0YwY\nlbJiRKmEWEAyULjbIebZW41Z4UqVG3MQI750PRWPW4WJ2kDhksFXN1gwSnaM46KR\nPmVA0SL+RCPcAp/VkImCv0eqv9exsglY0K/QiJfLy3zZ8QvAn0wYgZ3AvH3lr9rJ\nT7pg9WDb+OkfeEQ7INubqSthhaqCLd4zwbMRlpyvg1cMSq0zRvrFpwVlSY85lW4F\ng/tgjJ99W9VZAoIBAH3OYRVDAmrFYCoMn+AzA/RsIOEBqL8kaz/Pfh9K4D01CQ/x\naqryiqqpFwvXS4fLmaClIMwkvgq/90ulvuCGXeSG52D+NwW58qxQCxgTPhoA9yM9\nVueXKz3I/mpfLNftox8sskxl1qO/nfnu15cXkqVBe4ouD+53ZjhAZPSeQZwHi05h\nCbJ20gl66M+yG+6LZvXE96P8+ZQV80qskFmGdaPozAzdTZ3xzp7D1wegJpTz3j20\n3ULKAiIb5guZNU0tEZz5ikeOqsQt3u6/pVTeDZR0dxnyFUf/oOjmSorSG75WT3sA\n0ZiR0SH5mhFR2Nf1TJ4JHmFaQDMQqo+EG6lEbAECggEAA7kGnuQ0lSCiI3RQV9Wy\nAa9uAFtyE8/XzJWPaWlnoFk04jtoldIKyzHOsVU0GOYOiyKeTWmMFtTGANre8l51\nizYiTuVBmK+JD/2Z8/fgl8dcoyiqzvwy56kX3QUEO5dcKO48cMohneIiNbB7PnrM\nTpA3OfkwnJQGrX0/66GWrLYP8qmBDv1AIgYMilAa40VdSyZbNTpIdDgfP6bU9Ily\nG7gnyF47HHPt5Cx4ouArbMvV1rof7ytCrfCEhP21Lc46Ryxy81W5ZyzoQfSxfdKb\nGyDR+jkryVRyG69QJf5nCXfNewWbFR4ohVtZ78DNVkjvvLYvr4qxYYLK8PI3YMwL\nsQKCAQB9lo7JadzKVio+C18EfNikOzoriQOaIYowNaaGDw3/9KwIhRsKgoTs+K5O\ngt/gUoPRGd3M2z4hn5j4wgeuFi7HC1MdMWwvgat93h7R1YxiyaOoCTxH1klbB/3K\n4fskdQRxuM8McUebebrp0qT5E0xs2l+ABmt30Dtd3iRrQ5BBjnRc4V//sQiwS1aC\nYi5eNYCQ96BSAEo1dxJh5RI/QxF2HEPUuoPM8iXrIJhyg9TEEpbrEJcxeagWk02y\nOMEoUbWbX07OzFVvu+aJaN/GlgiogMQhb6IiNTyMlryFUleF+9OBA8xGHqGWA6nR\nOaRA5ZbdE7g7vxKRV36jT3wvD7W+\n-----END PRIVATE KEY-----\n"))
@@ -271,7 +251,7 @@ func InitTestingSession(i interface{}) *Session {
 	s := &Session{kv: kv}
 	u, err := user.NewUser(kv, id.NewIdFromString("zezima", id.User, i), []byte("salt"), privKey, false)
 	if err != nil {
-		globals.Log.FATAL.Panicf("InitTestingSession failed to create dummy user: %+v", err)
+		jww.FATAL.Panicf("InitTestingSession failed to create dummy user: %+v", err)
 	}
 	u.SetRegistrationValidationSignature([]byte("sig"))
 	s.user = u
@@ -294,7 +274,7 @@ func InitTestingSession(i interface{}) *Session {
 			"DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", 16))
 	cmix, err := cmix.NewStore(cmixGrp, kv, cmixGrp.NewInt(2))
 	if err != nil {
-		globals.Log.FATAL.Panicf("InitTestingSession failed to create dummy cmix session: %+v", err)
+		jww.FATAL.Panicf("InitTestingSession failed to create dummy cmix session: %+v", err)
 	}
 	s.cmix = cmix
 	return s
-- 
GitLab