From cf0da18831151a587b9e2d0743444cf0c27269a4 Mon Sep 17 00:00:00 2001
From: josh <josh@elixxir.io>
Date: Fri, 15 Oct 2021 13:19:11 -0700
Subject: [PATCH] Modify Login_Unsafe for pregenerated user JSON

---
 api/client.go            |  69 ++++++++++++++++++--------
 api/user.go              | 103 ++++++++++++++++++++++-----------------
 interfaces/user/proto.go |  35 +++++++++++++
 interfaces/user/user.go  |  17 +++++++
 storage/session.go       |   3 +-
 5 files changed, 161 insertions(+), 66 deletions(-)
 create mode 100644 interfaces/user/proto.go

diff --git a/api/client.go b/api/client.go
index bc460a17d..a6cf414bc 100644
--- a/api/client.go
+++ b/api/client.go
@@ -8,6 +8,7 @@
 package api
 
 import (
+	"encoding/json"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/auth"
@@ -72,7 +73,8 @@ type Client struct {
 // 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(ndfJSON, storageDir string, password []byte, registrationCode string) error {
+func NewClient(ndfJSON, storageDir string, password []byte,
+	registrationCode string) error {
 	jww.INFO.Printf("NewClient(dir: %s)", storageDir)
 	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
 	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
@@ -103,7 +105,8 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str
 // 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 NewPrecannedClient(precannedID uint, defJSON, storageDir string, password []byte) error {
+func NewPrecannedClient(precannedID uint, defJSON, storageDir string,
+	password []byte) error {
 	jww.INFO.Printf("NewPrecannedClient()")
 	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
 	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
@@ -132,7 +135,8 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [
 // 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 NewVanityClient(ndfJSON, storageDir string, password []byte, registrationCode string, userIdPrefix string) error {
+func NewVanityClient(ndfJSON, storageDir string, password []byte,
+	registrationCode string, userIdPrefix string) error {
 	jww.INFO.Printf("NewVanityClient()")
 	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
 	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
@@ -193,6 +197,45 @@ func OpenClient(storageDir string, password []byte, parameters params.Network) (
 	return c, nil
 }
 
+// NewProtoClient_Unsafe initializes a client object from a JSON containing
+// predefined cryptographic which defines a user. This is designed for some
+// specific deployment procedures and is generally unsafe.
+func NewProtoClient_Unsafe(storageDir string, password []byte,
+	protoClientJSON []byte,
+	parameters params.Network, def *ndf.NetworkDefinition) (*Client, error) {
+	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
+	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
+
+	cmixGrp, e2eGrp := decodeGroups(def)
+
+	// Pull the proto user from the JSON
+	protoUser := &user.Proto{}
+	err := json.Unmarshal(protoClientJSON, protoUser)
+	if err != nil {
+		return nil, err
+	}
+
+	// Initialize a user object for storage set up
+	usr := user.NewUserFromProto(protoUser)
+
+	// Set up storage
+	err = checkVersionAndSetupStorage(def, storageDir, password, usr,
+		cmixGrp, e2eGrp, rngStreamGen, false, protoUser.RegCode)
+
+	//Open the client
+	c, err := OpenClient(storageDir, password, parameters)
+	if err != nil {
+		return nil, err
+	}
+
+	// Set registration values in storage
+	c.GetStorage().User().SetReceptionRegistrationValidationSignature(protoUser.ReceptionRegValidationSig)
+	c.GetStorage().User().SetTransmissionRegistrationValidationSignature(protoUser.TransmissionRegValidationSig)
+	c.GetStorage().User().SetRegistrationTimestamp(protoUser.RegistrationTimestamp.UnixNano())
+
+	return c, nil
+}
+
 // Login initializes a client object from existing storage.
 func Login(storageDir string, password []byte, parameters params.Network) (*Client, error) {
 	jww.INFO.Printf("Login()")
@@ -234,7 +277,8 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie
 		hp.KaClientOpts.Time = time.Duration(math.MaxInt64)
 		hp.AuthEnabled = false
 		hp.MaxRetries = 5
-		_, err = c.comms.AddHost(&id.NotificationBot, def.Notification.Address, []byte(def.Notification.TlsCertificate), hp)
+		_, err = c.comms.AddHost(&id.NotificationBot, def.Notification.Address,
+			[]byte(def.Notification.TlsCertificate), hp)
 		if err != nil {
 			jww.WARN.Printf("Failed adding host for notifications: %+v", err)
 		}
@@ -262,7 +306,7 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie
 // LoginWithNewBaseNDF_UNSAFE initializes a client object from existing storage
 // while replacing the base NDF.  This is designed for some specific deployment
 // procedures and is generally unsafe.
-func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
+func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte, protoClientJSON []byte,
 	newBaseNdf string, parameters params.Network) (*Client, error) {
 	jww.INFO.Printf("LoginWithNewBaseNDF_UNSAFE()")
 
@@ -273,8 +317,7 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
 	}
 
 	//Open the client
-	c, err := OpenClient(storageDir, password, parameters)
-
+	c, err := NewProtoClient_Unsafe(storageDir, password, protoClientJSON, parameters, def)
 	if err != nil {
 		return nil, err
 	}
@@ -288,18 +331,6 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
 	//store the updated base NDF
 	c.storage.SetNDF(def)
 
-	//initialize registration
-	if def.Registration.Address != "" {
-		err = c.initPermissioning(def)
-		if err != nil {
-			return nil, err
-		}
-	} else {
-		jww.WARN.Printf("Registration with permissioning skipped due to " +
-			"blank permissionign address. Client will not be able to register " +
-			"or track network.")
-	}
-
 	// Initialize network and link it to context
 	c.network, err = network.NewManager(c.storage, c.switchboard, c.rng,
 		c.events, c.comms, parameters, def)
diff --git a/api/user.go b/api/user.go
index ef8eb1092..1b22a0877 100644
--- a/api/user.go
+++ b/api/user.go
@@ -36,6 +36,62 @@ func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.U
 
 	var cMixKeyBytes, e2eKeyBytes, transmissionSalt, receptionSalt []byte
 
+	cMixKeyBytes, e2eKeyBytes, transmissionSalt, receptionSalt,
+		transmissionRsaKey, receptionRsaKey = createDhKeys(rng, cmix, e2e)
+
+	// Salt, UID, etc gen
+	stream := rng.GetStream()
+	transmissionSalt = make([]byte, SaltSize)
+
+	n, err := stream.Read(transmissionSalt)
+
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+	if n != SaltSize {
+		jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
+	}
+
+	receptionSalt = make([]byte, SaltSize)
+
+	n, err = stream.Read(receptionSalt)
+
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+	if n != SaltSize {
+		jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
+	}
+
+	stream.Close()
+
+	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	receptionID, err := xx.NewID(receptionRsaKey.GetPublic(), receptionSalt, id.User)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
+	return user.User{
+		TransmissionID:   transmissionID.DeepCopy(),
+		TransmissionSalt: transmissionSalt,
+		TransmissionRSA:  transmissionRsaKey,
+		ReceptionID:      receptionID.DeepCopy(),
+		ReceptionSalt:    receptionSalt,
+		ReceptionRSA:     receptionRsaKey,
+		Precanned:        false,
+		CmixDhPrivateKey: cmix.NewIntFromBytes(cMixKeyBytes),
+		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
+	}
+}
+
+func createDhKeys(rng *fastRNG.StreamGenerator,
+	cmix, e2e *cyclic.Group) (cMixKeyBytes, e2eKeyBytes,
+	transmissionSalt, receptionSalt []byte,
+	transmissionRsaKey, receptionRsaKey *rsa.PrivateKey) {
 	wg := sync.WaitGroup{}
 
 	wg.Add(4)
@@ -93,53 +149,8 @@ func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.U
 	}()
 	wg.Wait()
 
-	// Salt, UID, etc gen
-	stream := rng.GetStream()
-	transmissionSalt = make([]byte, SaltSize)
-
-	n, err := stream.Read(transmissionSalt)
-
-	if err != nil {
-		jww.FATAL.Panicf(err.Error())
-	}
-	if n != SaltSize {
-		jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
-	}
-
-	receptionSalt = make([]byte, SaltSize)
-
-	n, err = stream.Read(receptionSalt)
-
-	if err != nil {
-		jww.FATAL.Panicf(err.Error())
-	}
-	if n != SaltSize {
-		jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
-	}
-
-	stream.Close()
-
-	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User)
-	if err != nil {
-		jww.FATAL.Panicf(err.Error())
-	}
-
-	receptionID, err := xx.NewID(receptionRsaKey.GetPublic(), receptionSalt, id.User)
-	if err != nil {
-		jww.FATAL.Panicf(err.Error())
-	}
+	return
 
-	return user.User{
-		TransmissionID:   transmissionID.DeepCopy(),
-		TransmissionSalt: transmissionSalt,
-		TransmissionRSA:  transmissionRsaKey,
-		ReceptionID:      receptionID.DeepCopy(),
-		ReceptionSalt:    receptionSalt,
-		ReceptionRSA:     receptionRsaKey,
-		Precanned:        false,
-		CmixDhPrivateKey: cmix.NewIntFromBytes(cMixKeyBytes),
-		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
-	}
 }
 
 // TODO: Add precanned user code structures here.
diff --git a/interfaces/user/proto.go b/interfaces/user/proto.go
new file mode 100644
index 000000000..8eff94714
--- /dev/null
+++ b/interfaces/user/proto.go
@@ -0,0 +1,35 @@
+package user
+
+import (
+	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/xx_network/crypto/signature/rsa"
+	"gitlab.com/xx_network/primitives/id"
+	"time"
+)
+
+type Proto struct {
+	//General Identity
+	TransmissionID   *id.ID
+	TransmissionSalt []byte
+	TransmissionRSA  *rsa.PrivateKey
+	ReceptionID      *id.ID
+	ReceptionSalt    []byte
+	ReceptionRSA     *rsa.PrivateKey
+	Precanned        bool
+	// Timestamp in which user has registered with the network
+	RegistrationTimestamp time.Time
+
+	Username string
+	RegCode  string
+
+	TransmissionRegValidationSig []byte
+	ReceptionRegValidationSig    []byte
+
+	//cmix Identity
+	CmixDhPrivateKey *cyclic.Int
+	CmixDhPublicKey  *cyclic.Int
+
+	//e2e Identity
+	E2eDhPrivateKey *cyclic.Int
+	E2eDhPublicKey  *cyclic.Int
+}
diff --git a/interfaces/user/user.go b/interfaces/user/user.go
index 8788856b4..c3f5875aa 100644
--- a/interfaces/user/user.go
+++ b/interfaces/user/user.go
@@ -44,3 +44,20 @@ func (u User) GetContact() contact.Contact {
 		Facts:    make([]fact.Fact, 0),
 	}
 }
+
+func NewUserFromProto(proto *Proto) User {
+	return User{
+		TransmissionID:        proto.TransmissionID,
+		TransmissionSalt:      proto.TransmissionSalt,
+		TransmissionRSA:       proto.TransmissionRSA,
+		ReceptionID:           proto.ReceptionID,
+		ReceptionSalt:         proto.ReceptionSalt,
+		ReceptionRSA:          proto.ReceptionRSA,
+		Precanned:             proto.Precanned,
+		RegistrationTimestamp: proto.RegistrationTimestamp,
+		CmixDhPrivateKey:      proto.CmixDhPrivateKey,
+		CmixDhPublicKey:       proto.CmixDhPublicKey,
+		E2eDhPrivateKey:       proto.E2eDhPrivateKey,
+		E2eDhPublicKey:        proto.E2eDhPublicKey,
+	}
+}
diff --git a/storage/session.go b/storage/session.go
index fd98a85c2..9b949f240 100644
--- a/storage/session.go
+++ b/storage/session.go
@@ -101,7 +101,8 @@ func New(baseDir, password string, u userInterface.User, currentVersion version.
 			"Create new session")
 	}
 
-	s.user, err = user.NewUser(s.kv, u.TransmissionID, u.ReceptionID, u.TransmissionSalt, u.ReceptionSalt, u.TransmissionRSA, u.ReceptionRSA, u.Precanned)
+	s.user, err = user.NewUser(s.kv, u.TransmissionID, u.ReceptionID, u.TransmissionSalt,
+		u.ReceptionSalt, u.TransmissionRSA, u.ReceptionRSA, u.Precanned)
 	if err != nil {
 		return nil, errors.WithMessage(err, "Failed to create user")
 	}
-- 
GitLab