Skip to content
Snippets Groups Projects
Commit 70db55c4 authored by Josh Brooks's avatar Josh Brooks
Browse files

Fix issues in integration testing

parent 6639ac05
No related branches found
No related tags found
2 merge requests!67Release,!47Modify Login_Unsafe for pregenerated user JSON
...@@ -92,7 +92,7 @@ func NewClient(ndfJSON, storageDir string, password []byte, ...@@ -92,7 +92,7 @@ func NewClient(ndfJSON, storageDir string, password []byte,
protoUser := createNewUser(rngStreamGen, cmixGrp, e2eGrp) protoUser := createNewUser(rngStreamGen, cmixGrp, e2eGrp)
jww.DEBUG.Printf("User generation took: %s", time.Now().Sub(start)) jww.DEBUG.Printf("User generation took: %s", time.Now().Sub(start))
err = checkVersionAndSetupStorage(def, storageDir, password, protoUser, _, err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
cmixGrp, e2eGrp, rngStreamGen, false, registrationCode) cmixGrp, e2eGrp, rngStreamGen, false, registrationCode)
if err != nil { if err != nil {
return err return err
...@@ -123,7 +123,7 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, ...@@ -123,7 +123,7 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string,
protoUser := createPrecannedUser(precannedID, rngStream, cmixGrp, e2eGrp) protoUser := createPrecannedUser(precannedID, rngStream, cmixGrp, e2eGrp)
err = checkVersionAndSetupStorage(def, storageDir, password, protoUser, _, err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
cmixGrp, e2eGrp, rngStreamGen, true, "") cmixGrp, e2eGrp, rngStreamGen, true, "")
if err != nil { if err != nil {
return err return err
...@@ -153,7 +153,7 @@ func NewVanityClient(ndfJSON, storageDir string, password []byte, ...@@ -153,7 +153,7 @@ func NewVanityClient(ndfJSON, storageDir string, password []byte,
protoUser := createNewVanityUser(rngStream, cmixGrp, e2eGrp, userIdPrefix) protoUser := createNewVanityUser(rngStream, cmixGrp, e2eGrp, userIdPrefix)
err = checkVersionAndSetupStorage(def, storageDir, password, protoUser, _, err = checkVersionAndSetupStorage(def, storageDir, password, protoUser,
cmixGrp, e2eGrp, rngStreamGen, false, registrationCode) cmixGrp, e2eGrp, rngStreamGen, false, registrationCode)
if err != nil { if err != nil {
return err return err
...@@ -202,42 +202,50 @@ func OpenClient(storageDir string, password []byte, parameters params.Network) ( ...@@ -202,42 +202,50 @@ func OpenClient(storageDir string, password []byte, parameters params.Network) (
// NewProtoClient_Unsafe initializes a client object from a JSON containing // NewProtoClient_Unsafe initializes a client object from a JSON containing
// predefined cryptographic which defines a user. This is designed for some // predefined cryptographic which defines a user. This is designed for some
// specific deployment procedures and is generally unsafe. // specific deployment procedures and is generally unsafe.
func NewProtoClient_Unsafe(storageDir string, password []byte, func NewProtoClient_Unsafe(ndfJSON, storageDir string, password,
protoClientJSON []byte, protoClientJSON []byte) error {
parameters params.Network, def *ndf.NetworkDefinition) (*Client, error) {
jww.INFO.Printf("NewProtoClient_Unsafe") jww.INFO.Printf("NewProtoClient_Unsafe")
// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG) rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
// Parse the NDF
def, err := parseNDF(ndfJSON)
if err != nil {
return err
}
cmixGrp, e2eGrp := decodeGroups(def) cmixGrp, e2eGrp := decodeGroups(def)
// Pull the proto user from the JSON // Pull the proto user from the JSON
protoUser := &user.Proto{} protoUser := &user.Proto{}
err := json.Unmarshal(protoClientJSON, protoUser) err = json.Unmarshal(protoClientJSON, protoUser)
if err != nil { if err != nil {
return nil, err return err
} }
// Initialize a user object for storage set up // Initialize a user object for storage set up
usr := user.NewUserFromProto(protoUser) usr := user.NewUserFromProto(protoUser)
// Set up storage // Set up storage
err = checkVersionAndSetupStorage(def, storageDir, password, usr, storageSess, err := checkVersionAndSetupStorage(def, storageDir, password, usr,
cmixGrp, e2eGrp, rngStreamGen, false, protoUser.RegCode) cmixGrp, e2eGrp, rngStreamGen, false, protoUser.RegCode)
//Open the client
c, err := OpenClient(storageDir, password, parameters)
if err != nil { if err != nil {
return nil, err return err
} }
// Set registration values in storage // Set registration values in storage
c.GetStorage().User().SetReceptionRegistrationValidationSignature(protoUser.ReceptionRegValidationSig) storageSess.User().SetReceptionRegistrationValidationSignature(protoUser.ReceptionRegValidationSig)
c.GetStorage().User().SetTransmissionRegistrationValidationSignature(protoUser.TransmissionRegValidationSig) storageSess.User().SetTransmissionRegistrationValidationSignature(protoUser.TransmissionRegValidationSig)
c.GetStorage().User().SetRegistrationTimestamp(protoUser.RegistrationTimestamp.UnixNano()) storageSess.User().SetRegistrationTimestamp(protoUser.RegistrationTimestamp)
return c, nil //move the registration state to indicate registered with registration on proto client
err = storageSess.ForwardRegistrationStatus(storage.PermissioningComplete)
if err != nil {
return err
}
return nil
} }
// Login initializes a client object from existing storage. // Login initializes a client object from existing storage.
...@@ -366,54 +374,6 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte, ...@@ -366,54 +374,6 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
return c, nil return c, nil
} }
// LoginWithProtoClient creates a client object with a protoclient JSON containing the
// cryptographic primitives. This is designed for some specific deployment
// procedures and is generally unsafe. It is unsafe because all network relationships
// will no longer be present in the new session file.
func LoginWithProtoClient(storageDir string, password []byte,
protoClientJSON []byte,
newBaseNdf string, parameters params.Network) (*Client, error) {
jww.INFO.Printf("LoginWithNewBaseNDF_UNSAFE()")
// Parse the NDF
def, err := parseNDF(newBaseNdf)
if err != nil {
return nil, err
}
//Open the client
c, err := NewProtoClient_Unsafe(storageDir, password, protoClientJSON, parameters, def)
if err != nil {
return nil, err
}
//initialize comms
err = c.initComms()
if err != nil {
return nil, err
}
//store the updated base NDF
c.storage.SetNDF(def)
// Initialize network and link it to context
c.network, err = network.NewManager(c.storage, c.switchboard, c.rng,
c.events, c.comms, parameters, def)
if err != nil {
return nil, err
}
// initialize the auth tracker
c.auth = auth.NewManager(c.switchboard, c.storage, c.network)
err = c.registerFollower()
if err != nil {
return nil, err
}
return c, nil
}
func (c *Client) initComms() error { func (c *Client) initComms() error {
var err error var err error
...@@ -476,7 +436,9 @@ func (c *Client) registerFollower() error { ...@@ -476,7 +436,9 @@ func (c *Client) registerFollower() error {
} }
//register the core follower service //register the core follower service
err = c.followerServices.add(func() (stoppable.Stoppable, error) { return c.network.Follow(cer) }) err = c.followerServices.add(func() (stoppable.Stoppable, error) {
return c.network.Follow(cer)
})
if err != nil { if err != nil {
return errors.WithMessage(err, "Failed to start following "+ return errors.WithMessage(err, "Failed to start following "+
"the network") "the network")
...@@ -792,13 +754,15 @@ func decodeGroups(ndf *ndf.NetworkDefinition) (cmixGrp, e2eGrp *cyclic.Group) { ...@@ -792,13 +754,15 @@ func decodeGroups(ndf *ndf.NetworkDefinition) (cmixGrp, e2eGrp *cyclic.Group) {
// checkVersionAndSetupStorage is common code shared by NewClient, NewPrecannedClient and NewVanityClient // checkVersionAndSetupStorage is common code shared by NewClient, NewPrecannedClient and NewVanityClient
// it checks client version and creates a new storage for user data // it checks client version and creates a new storage for user data
func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, storageDir string, password []byte, func checkVersionAndSetupStorage(def *ndf.NetworkDefinition,
protoUser user.User, cmixGrp, e2eGrp *cyclic.Group, rngStreamGen *fastRNG.StreamGenerator, storageDir string, password []byte,
isPrecanned bool, registrationCode string) error { protoUser user.User,
cmixGrp, e2eGrp *cyclic.Group, rngStreamGen *fastRNG.StreamGenerator,
isPrecanned bool, registrationCode string) (*storage.Session, error) {
// Get current client version // Get current client version
currentVersion, err := version.ParseVersion(SEMVER) currentVersion, err := version.ParseVersion(SEMVER)
if err != nil { if err != nil {
return errors.WithMessage(err, "Could not parse version string.") return nil, errors.WithMessage(err, "Could not parse version string.")
} }
// Create Storage // Create Storage
...@@ -806,7 +770,7 @@ func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, storageDir string, ...@@ -806,7 +770,7 @@ func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, storageDir string,
storageSess, err := storage.New(storageDir, passwordStr, protoUser, storageSess, err := storage.New(storageDir, passwordStr, protoUser,
currentVersion, cmixGrp, e2eGrp, rngStreamGen) currentVersion, cmixGrp, e2eGrp, rngStreamGen)
if err != nil { if err != nil {
return err return nil, err
} }
// Save NDF to be used in the future // Save NDF to be used in the future
...@@ -830,9 +794,9 @@ func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, storageDir string, ...@@ -830,9 +794,9 @@ func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, storageDir string,
}, protoUser.ReceptionID) }, protoUser.ReceptionID)
if err != nil { if err != nil {
return errors.WithMessage(err, "Failed to denote state "+ return nil, errors.WithMessage(err, "Failed to denote state "+
"change in session") "change in session")
} }
return nil return storageSess, nil
} }
...@@ -43,7 +43,7 @@ func (c *Client) RegisterForNotifications(token string) error { ...@@ -43,7 +43,7 @@ func (c *Client) RegisterForNotifications(token string) error {
TransmissionSalt: c.GetUser().TransmissionSalt, TransmissionSalt: c.GetUser().TransmissionSalt,
TransmissionRsaSig: c.GetStorage().User().GetTransmissionRegistrationValidationSignature(), TransmissionRsaSig: c.GetStorage().User().GetTransmissionRegistrationValidationSignature(),
IIDTransmissionRsaSig: sig, IIDTransmissionRsaSig: sig,
RegistrationTimestamp: c.GetUser().RegistrationTimestamp.UnixNano(), RegistrationTimestamp: c.GetUser().RegistrationTimestamp,
}) })
if err != nil { if err != nil {
err := errors.Errorf( err := errors.Errorf(
......
///////////////////////////////////////////////////////////////////////////////
// Copyright © 2020 xx network SEZC //
// //
// Use of this source code is governed by a license that can be found in the //
// LICENSE file //
///////////////////////////////////////////////////////////////////////////////
package cmd
import (
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/viper"
"gitlab.com/elixxir/client/api"
"gitlab.com/elixxir/client/interfaces/params"
"gitlab.com/xx_network/primitives/utils"
"io/ioutil"
"time"
)
var protoCmd = &cobra.Command{
Use: "proto",
Short: "Load client with a proto client JSON file.",
Args: cobra.NoArgs,
Run: func(cmd *cobra.Command, args []string) {
// If output path is specified, only write to file
var client *api.Client
jww.INFO.Printf("In proto user path")
protoOutputPath := viper.GetString("protoUserOut")
if protoOutputPath != "" {
client = initClient()
jsonBytes, err := client.ConstructProtoUerFile()
if err != nil {
jww.FATAL.Panicf("Failed to construct proto user file: %v", err)
}
err = utils.WriteFileDef(protoOutputPath, jsonBytes)
if err != nil {
jww.FATAL.Panicf("Failed to write proto user to file: %v", err)
}
} else {
jww.INFO.Printf("Loading proto client")
client = loadProtoClient()
}
},
}
func loadProtoClient() *api.Client {
protoUserPath := viper.GetString("protoUserPath")
protoUserFile, err := utils.ReadFile(protoUserPath)
if err != nil {
jww.FATAL.Panicf("Failed to read proto user: %v", err)
}
pass := viper.GetString("password")
storeDir := viper.GetString("session")
netParams := params.GetDefaultNetwork()
netParams.E2EParams.MinKeys = uint16(viper.GetUint("e2eMinKeys"))
netParams.E2EParams.MaxKeys = uint16(viper.GetUint("e2eMaxKeys"))
netParams.E2EParams.NumRekeys = uint16(
viper.GetUint("e2eNumReKeys"))
netParams.ForceHistoricalRounds = viper.GetBool("forceHistoricalRounds")
netParams.FastPolling = viper.GetBool("slowPolling")
netParams.ForceMessagePickupRetry = viper.GetBool("forceMessagePickupRetry")
if netParams.ForceMessagePickupRetry {
period := 3 * time.Second
jww.INFO.Printf("Setting Uncheck Round Period to %v", period)
netParams.UncheckRoundPeriod = period
}
netParams.VerboseRoundTracking = viper.GetBool("verboseRoundTracking")
// Load NDF
ndfPath := viper.GetString("ndf")
ndfJSON, err := ioutil.ReadFile(ndfPath)
if err != nil {
jww.FATAL.Panicf(err.Error())
}
jww.INFO.Printf("login with proto")
client, err := api.LoginWithProtoClient(storeDir, []byte(pass),
protoUserFile, string(ndfJSON), netParams)
if err != nil {
jww.FATAL.Panicf("Failed to login: %v", err)
}
return client
}
// init is the initialization function for Cobra which defines commands
// and flags.
func init() {
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
rootCmd.AddCommand(protoCmd)
}
...@@ -23,6 +23,7 @@ import ( ...@@ -23,6 +23,7 @@ import (
"gitlab.com/elixxir/client/switchboard" "gitlab.com/elixxir/client/switchboard"
"gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/crypto/contact"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"gitlab.com/xx_network/primitives/utils"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
...@@ -58,13 +59,8 @@ var rootCmd = &cobra.Command{ ...@@ -58,13 +59,8 @@ var rootCmd = &cobra.Command{
pprof.StartCPUProfile(f) pprof.StartCPUProfile(f)
} }
protoUserPath := viper.GetString("protoUserPath") client := initClient()
var client *api.Client
if protoUserPath != "" {
loadProtoClient()
} else {
client = initClient()
}
user := client.GetUser() user := client.GetUser()
jww.INFO.Printf("User: %s", user.ReceptionID) jww.INFO.Printf("User: %s", user.ReceptionID)
writeContact(user.GetContact()) writeContact(user.GetContact())
...@@ -387,6 +383,8 @@ func createClient() *api.Client { ...@@ -387,6 +383,8 @@ func createClient() *api.Client {
regCode := viper.GetString("regcode") regCode := viper.GetString("regcode")
precannedID := viper.GetUint("sendid") precannedID := viper.GetUint("sendid")
userIDprefix := viper.GetString("userid-prefix") userIDprefix := viper.GetString("userid-prefix")
protoUserPath := viper.GetString("protoUserPath")
//create a new client if none exist //create a new client if none exist
if _, err := os.Stat(storeDir); os.IsNotExist(err) { if _, err := os.Stat(storeDir); os.IsNotExist(err) {
// Load NDF // Load NDF
...@@ -399,14 +397,19 @@ func createClient() *api.Client { ...@@ -399,14 +397,19 @@ func createClient() *api.Client {
if precannedID != 0 { if precannedID != 0 {
err = api.NewPrecannedClient(precannedID, err = api.NewPrecannedClient(precannedID,
string(ndfJSON), storeDir, []byte(pass)) string(ndfJSON), storeDir, []byte(pass))
} else { } else if protoUserPath != "" {
if userIDprefix != "" { protoUserJson, err := utils.ReadFile(protoUserPath)
err = api.NewVanityClient(string(ndfJSON), storeDir, if err != nil {
[]byte(pass), regCode, userIDprefix) jww.FATAL.Panicf("%v", err)
} else {
err = api.NewClient(string(ndfJSON), storeDir,
[]byte(pass), regCode)
} }
err = api.NewProtoClient_Unsafe(string(ndfJSON), storeDir,
[]byte(pass), protoUserJson)
} else if userIDprefix != "" {
err = api.NewVanityClient(string(ndfJSON), storeDir,
[]byte(pass), regCode, userIDprefix)
} else {
err = api.NewClient(string(ndfJSON), storeDir,
[]byte(pass), regCode)
} }
if err != nil { if err != nil {
...@@ -458,12 +461,19 @@ func initClient() *api.Client { ...@@ -458,12 +461,19 @@ func initClient() *api.Client {
jww.FATAL.Panicf("%+v", err) jww.FATAL.Panicf("%+v", err)
} }
jsoBytes, err := client.ConstructProtoUerFile() if protoUser := viper.GetString("protoUserOut"); protoUser != "" {
if err != nil {
jww.WARN.Printf("err: %v", err)
}
jww.WARN.Printf("json %s", string(jsoBytes)) jsonBytes, err := client.ConstructProtoUerFile()
if err != nil {
jww.FATAL.Panicf("Failed to construct proto user file: %v", err)
}
err = utils.WriteFileDef(protoUser, jsonBytes)
if err != nil {
jww.FATAL.Panicf("Failed to write proto user to file: %v", err)
}
}
return client return client
} }
...@@ -907,15 +917,14 @@ func init() { ...@@ -907,15 +917,14 @@ func init() {
viper.BindPFlag("profile-cpu", rootCmd.Flags().Lookup("profile-cpu")) viper.BindPFlag("profile-cpu", rootCmd.Flags().Lookup("profile-cpu"))
// Proto user flags // Proto user flags
protoCmd.Flags().String("protoUserPath", "protoUser.json", rootCmd.Flags().String("protoUserPath", "",
"Path to proto user JSON file containing cryptographic primitives "+ "Path to proto user JSON file containing cryptographic primitives "+
"the client will load") "the client will load")
viper.BindPFlag("protoUserPath", protoCmd.Flags().Lookup("protoUserPath")) viper.BindPFlag("protoUserPath", rootCmd.Flags().Lookup("protoUserPath"))
protoCmd.Flags().String("protoUserOut", "protoUser.json", rootCmd.Flags().String("protoUserOut", "",
"Path to which a normally constructed client "+ "Path to which a normally constructed client "+
"will write proto user JSON file") "will write proto user JSON file")
viper.BindPFlag("protoUserOut", protoCmd.Flags().Lookup("protoUserOut")) viper.BindPFlag("protoUserOut", rootCmd.Flags().Lookup("protoUserOut"))
} }
......
...@@ -4,7 +4,6 @@ import ( ...@@ -4,7 +4,6 @@ import (
"gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/crypto/signature/rsa"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"time"
) )
type Proto struct { type Proto struct {
...@@ -17,9 +16,9 @@ type Proto struct { ...@@ -17,9 +16,9 @@ type Proto struct {
ReceptionRSA *rsa.PrivateKey ReceptionRSA *rsa.PrivateKey
Precanned bool Precanned bool
// Timestamp in which user has registered with the network // Timestamp in which user has registered with the network
RegistrationTimestamp time.Time RegistrationTimestamp int64
RegCode string RegCode string
TransmissionRegValidationSig []byte TransmissionRegValidationSig []byte
ReceptionRegValidationSig []byte ReceptionRegValidationSig []byte
......
...@@ -13,7 +13,6 @@ import ( ...@@ -13,7 +13,6 @@ import (
"gitlab.com/elixxir/primitives/fact" "gitlab.com/elixxir/primitives/fact"
"gitlab.com/xx_network/crypto/signature/rsa" "gitlab.com/xx_network/crypto/signature/rsa"
"gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id"
"time"
) )
type User struct { type User struct {
...@@ -26,7 +25,7 @@ type User struct { ...@@ -26,7 +25,7 @@ type User struct {
ReceptionRSA *rsa.PrivateKey ReceptionRSA *rsa.PrivateKey
Precanned bool Precanned bool
// Timestamp in which user has registered with the network // Timestamp in which user has registered with the network
RegistrationTimestamp time.Time RegistrationTimestamp int64
//cmix Identity //cmix Identity
CmixDhPrivateKey *cyclic.Int CmixDhPrivateKey *cyclic.Int
......
...@@ -146,7 +146,7 @@ func buildSlotMessage(msg format.Message, recipient *id.ID, target *id.ID, ...@@ -146,7 +146,7 @@ func buildSlotMessage(msg format.Message, recipient *id.ID, target *id.ID,
if param.IdentityPreimage != nil { if param.IdentityPreimage != nil {
preimage = param.IdentityPreimage preimage = param.IdentityPreimage
jww.INFO.Printf("Sending to %s with override preimage %v", recipient, preimage) jww.INFO.Printf("Sending to %s with override preimage %v", recipient, preimage)
}else{ } else {
preimage = preimage2.MakeDefault(recipient) preimage = preimage2.MakeDefault(recipient)
jww.INFO.Printf("Sending to %s with default preimage %v", recipient, preimage) jww.INFO.Printf("Sending to %s with default preimage %v", recipient, preimage)
} }
......
...@@ -96,6 +96,10 @@ func registerNodes(sender *gateway.Sender, session *storage.Session, ...@@ -96,6 +96,10 @@ func registerNodes(sender *gateway.Sender, session *storage.Session,
//registerWithNode serves as a helper for RegisterWithNodes //registerWithNode serves as a helper for RegisterWithNodes
// It registers a user with a specific in the client's ndf. // It registers a user with a specific in the client's ndf.
// todo: follow uci. TransmissionRSA and ReceptionRSA are marshaled into JSON as
// objects. MAke sure JSON is intelligent enough on unmarshal to read that data.
// Also make sure (if unmarshalled correctly) that data makes it's way to storage
// as expected.
func registerWithNode(sender *gateway.Sender, comms RegisterNodeCommsInterface, func registerWithNode(sender *gateway.Sender, comms RegisterNodeCommsInterface,
ngw network.NodeGateway, regSig []byte, registrationTimestampNano int64, ngw network.NodeGateway, regSig []byte, registrationTimestampNano int64,
uci *user.CryptographicIdentity, store *cmix.Store, rng csprng.Source, uci *user.CryptographicIdentity, store *cmix.Store, rng csprng.Source,
......
...@@ -16,9 +16,9 @@ func (s *Session) GetUser() user.User { ...@@ -16,9 +16,9 @@ func (s *Session) GetUser() user.User {
return user.User{ return user.User{
TransmissionID: ci.GetTransmissionID().DeepCopy(), TransmissionID: ci.GetTransmissionID().DeepCopy(),
TransmissionSalt: copySlice(ci.GetTransmissionSalt()), TransmissionSalt: copySlice(ci.GetTransmissionSalt()),
TransmissionRSA: ci.GetReceptionRSA(), TransmissionRSA: ci.GetTransmissionRSA(),
ReceptionID: ci.GetReceptionID().DeepCopy(), ReceptionID: ci.GetReceptionID().DeepCopy(),
RegistrationTimestamp: s.user.GetRegistrationTimestamp(), RegistrationTimestamp: s.user.GetRegistrationTimestamp().UnixNano(),
ReceptionSalt: copySlice(ci.GetReceptionSalt()), ReceptionSalt: copySlice(ci.GetReceptionSalt()),
ReceptionRSA: ci.GetReceptionRSA(), ReceptionRSA: ci.GetReceptionRSA(),
Precanned: ci.IsPrecanned(), Precanned: ci.IsPrecanned(),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment