Skip to content
Snippets Groups Projects
Commit 37f99124 authored by Jono's avatar Jono
Browse files

Merge branch 'XX-915' of gitlab.com:elixxir/client

parents feadf0d2 50a28ad3
No related branches found
No related tags found
No related merge requests found
......@@ -24,14 +24,13 @@ Required args:
|Long flag|Short flag|Effect|Example|
|---|---|---|---|
|--numnodes|-n|Number of nodes in each team in the network|-n 3|
|--userid|-i|ID of the user of this client|-i 5|
Optional args:
|Long flag|Short flag|Effect|Example|
|---|---|---|---|
|--gwaddr|-g|Address of the gateway to connect to (Overrides config file)|-g localhost:8443|
|--gwaddresses|-g|Addresses of the gateway to connect to, separated by commas (Overrides config file)|-g localhost:8443,localhost:8444|
|--destid|-d|ID of the user to send messages to|-d 6|
|--message|-m|Text message to send|-m "let's both have a good day"|
|--verbose|-v|Prints more logging messages for debugging|-v|
......@@ -40,7 +39,8 @@ Optional args:
|--noBlockingTransmission| |Disables transmission rate limiting (useful for dummy client)|--noBlockingTransmission|
|--mint| |Creates some coins for this user for testing and demos|--mint|
|--help|-h|Prints a help message with all of these flags|-h|
|--certpath|-c|Enables TLS by passing in path to the gateway certificate file|-c "~/Documents/gateway.cert"|
|--gwcertpath|-c|Enables TLS by passing in path to the gateway certificate file|-c "~/Documents/gateway.cert"|
|--registrationcertpath|-r|Enables TLS by passing in path to the registration server certificate file|-r "~/Documents/registration.cert"|
|--dummyfrequency| |How often dummy messages should be sent per second. This flag is likely to be replaced when we implement better dummy message sending.|--dummyfrequency 0.5|
##Project Structure
......
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2018 Privategrity Corporation /
// Copyright © 2019 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
......@@ -7,6 +7,7 @@
package api
import (
"crypto/rand"
"errors"
"fmt"
"github.com/golang/protobuf/proto"
......@@ -19,8 +20,13 @@ import (
"gitlab.com/elixxir/client/payment"
"gitlab.com/elixxir/client/switchboard"
"gitlab.com/elixxir/client/user"
"gitlab.com/elixxir/comms/client"
"gitlab.com/elixxir/comms/connect"
pb "gitlab.com/elixxir/comms/mixmessages"
"gitlab.com/elixxir/crypto/csprng"
"gitlab.com/elixxir/crypto/cyclic"
"gitlab.com/elixxir/crypto/registration"
"gitlab.com/elixxir/crypto/signature"
"gitlab.com/elixxir/primitives/id"
goio "io"
"time"
......@@ -57,70 +63,143 @@ func InitClient(s globals.Storage, loc string) error {
// Registers user and returns the User ID.
// Returns an error if registration fails.
func Register(registrationCode string, gwAddr string,
numNodes uint, mint bool) (*id.User, error) {
func Register(registrationCode, registrationAddr string, gwAddresses []string,
mint bool) (*id.User, error) {
var err error
if numNodes < 1 {
if len(gwAddresses) < 1 {
globals.Log.ERROR.Printf("Register: Invalid number of nodes")
err = errors.New("could not register due to invalid number of nodes")
return id.ZeroID, err
}
// Because the method returns a pointer to the user ID, don't clear the
// user ID as the caller needs to use it
UID, successLook := user.Users.LookupUser(registrationCode)
if !successLook {
globals.Log.ERROR.Printf("Register: HUID does not match")
err = errors.New("could not register due to invalid HUID")
// Generate salt for UserID
salt := make([]byte, 256)
_, err = csprng.NewSystemRNG().Read(salt)
if err != nil {
globals.Log.ERROR.Printf("Register: Unable to generate salt! %s", err)
return id.ZeroID, err
}
u, successGet := user.Users.GetUser(UID)
// Generate DSA keypair
params := signature.NewDSAParams(rand.Reader, signature.L2048N256)
privateKey := params.PrivateKeyGen(rand.Reader)
if !successGet {
globals.Log.ERROR.Printf("Register: ID lookup failed")
err = errors.New("could not register due to ID lookup failure")
// Generate UserID by hashing salt and public key
UID := registration.GenUserID(privateKey.PublicKeyGen(), salt)
// Send registration code and public key to RegistrationServer
p, q, g := privateKey.GetParams()
response, err := client.SendRegistrationMessage(registrationAddr,
&pb.RegisterUserMessage{
Y: privateKey.GetPublicKey().Bytes(),
P: p.Bytes(),
Q: q.Bytes(),
G: g.Bytes(),
})
if err != nil {
globals.Log.ERROR.Printf(
"Register: Unable to contact Registration Server! %s", err)
return id.ZeroID, err
}
nodekeys, successKeys := user.Users.LookupKeys(u.User)
if !successKeys {
globals.Log.ERROR.Printf("Register: could not find user keys")
err = errors.New("could not register due to missing user keys")
if response.Error != "" {
globals.Log.ERROR.Printf("Register: %s", response.Error)
return id.ZeroID, errors.New(response.Error)
}
// Keep track of Server public keys provided at end of registration
serverPublicKeys := make([]*signature.DSAPublicKey, len(gwAddresses))
regHash, regR, regS := response.Hash, response.R, response.S
// Loop over all Servers
for _, gwAddr := range gwAddresses {
// Send signed public key and salt for UserID to Server
nonceResponse, err := client.SendRequestNonceMessage(gwAddr,
&pb.RequestNonceMessage{
Salt: salt,
Y: privateKey.GetPublicKey().Bytes(),
P: p.Bytes(),
Q: q.Bytes(),
G: g.Bytes(),
Hash: regHash,
R: regR,
S: regS,
})
if err != nil {
globals.Log.ERROR.Printf(
"Register: Unable to request nonce! %s",
err)
return id.ZeroID, err
}
nk := make([]user.NodeKeys, numNodes)
for i := uint(0); i < numNodes; i++ {
nk[i] = *nodekeys
if nonceResponse.Error != "" {
globals.Log.ERROR.Printf("Register: %s", nonceResponse.Error)
return id.ZeroID, errors.New(nonceResponse.Error)
}
nus := user.NewSession(u, gwAddr, nk, cyclic.NewIntFromBytes([]byte("this is not a real public key")))
_, err = payment.CreateWallet(nus, mint)
// Use Client keypair to sign Server nonce
nonce := nonceResponse.Nonce
sig, err := privateKey.Sign(nonce, rand.Reader)
if err != nil {
globals.Log.ERROR.Printf(
"Register: Unable to sign nonce! %s", err)
return id.ZeroID, err
}
errStore := nus.StoreSession()
// FIXME If we have an error here, the session that gets created doesn't get immolated.
// Immolation should happen in a deferred call instead.
if errStore != nil {
err = errors.New(fmt.Sprintf(
"Register: could not register due to failed session save"+
": %s", errStore.Error()))
globals.Log.ERROR.Printf(err.Error())
// Send signed nonce to Server
// TODO: This returns a receipt that can be used to speed up registration
confirmResponse, err := client.SendConfirmNonceMessage(gwAddr,
&pb.ConfirmNonceMessage{
Hash: nonce,
R: sig.R.Bytes(),
S: sig.S.Bytes(),
})
if err != nil {
globals.Log.ERROR.Printf(
"Register: Unable to send signed nonce! %s", err)
return id.ZeroID, err
}
nus.Immolate()
nus = nil
if confirmResponse.Error != "" {
globals.Log.ERROR.Printf(
"Register: %s", confirmResponse.Error)
return id.ZeroID, errors.New(confirmResponse.Error)
}
// Append Server public key
serverPublicKeys = append(serverPublicKeys,
signature.ReconstructPublicKey(signature.
CustomDSAParams(
cyclic.NewIntFromBytes(confirmResponse.GetP()),
cyclic.NewIntFromBytes(confirmResponse.GetQ()),
cyclic.NewIntFromBytes(confirmResponse.GetG())),
cyclic.NewIntFromBytes(confirmResponse.GetY())))
}
// FIXME: Add private key to session storage
//nus := user.NewSession(u, gwAddresses[0], nk, cyclic.NewIntFromBytes([]byte(
// "this is not a real public key")))
//
//_, err = payment.CreateWallet(nus, mint)
//if err != nil {
// return id.ZeroID, err
//}
//
//errStore := nus.StoreSession()
//
//// FIXME If we have an error here, the session that gets created doesn't get immolated.
//// Immolation should happen in a deferred call instead.
//if errStore != nil {
// err = errors.New(fmt.Sprintf(
// "Register: could not register due to failed session save"+
// ": %s", errStore.Error()))
// globals.Log.ERROR.Printf(err.Error())
// return id.ZeroID, err
//}
//
//nus.Immolate()
//nus = nil
return UID, err
}
......
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2018 Privategrity Corporation /
// Copyright © 2019 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
......@@ -74,7 +74,6 @@ func Listen(userId []byte, messageType int32, newListener Listener) string {
// Returns a parsed message
// Pass the listener handle that Listen() returned to delete the listener
func StopListening(listenerHandle string) {
api.StopListening(listenerHandle, switchboard.Listeners)
......@@ -109,49 +108,19 @@ func InitClient(storage Storage, loc string) error {
}
// Registers user and returns the User ID. Returns null if registration fails.
// registrationCode is a one time use string.
// nick is a nickname which must be 32 characters or less.
// nodeAddr is the ip address and port of the last node in the form: 192.168.1.1:50000
// registrationCode is a one time use string
// registrationAddr is the address of the registration server
// gwAddresses is a list of gateway addresses
// numNodes is the number of nodes in the system
// Valid codes:
// 1
// “David”
// RUHPS2MI
// 2
// “Jim”
// AXJ3XIBD
// 3
// “Ben”
// AW55QN6U
// 4
// “Rick”
// XYRAUUO6
// 5
// “Spencer”
// UAV6IWD6
// 6
// “Jake”
// XEHCZT5U
// 7
// “Mario”
// BW7NEXOZ
// 8
// “Will”
// IRZVJ55Y
// 9
// “Allan”
// YRZEM7BW
// 10
// “Jono”
// OIF3OJ5I
func Register(registrationCode string, gwAddr string, numNodes int,
func Register(registrationCode, registrationAddr string, gwAddresses []string,
mint bool) ([]byte, error) {
if numNodes < 1 {
if len(gwAddresses) < 1 {
return id.ZeroID[:], errors.New("invalid number of nodes")
}
UID, err := api.Register(registrationCode, gwAddr, uint(numNodes), mint)
UID, err := api.Register(registrationCode, registrationAddr,
gwAddresses, mint)
if err != nil {
return id.ZeroID[:], err
......
////////////////////////////////////////////////////////////////////////////////
// Copyright © 2018 Privategrity Corporation /
// Copyright © 2019 Privategrity Corporation /
// /
// All rights reserved. /
////////////////////////////////////////////////////////////////////////////////
......@@ -34,16 +34,16 @@ import (
var verbose bool
var userId uint64
var destinationUserId uint64
var gwAddr string
var gwAddresses []string
var message string
var numNodes uint
var sessionFile string
var dummyFrequency float64
var noBlockingTransmission bool
var mint bool
var rateLimiting uint32
var showVer bool
var certPath string
var gwCertPath string
var registrationCertPath string
// Execute adds all child commands to the root command and sets flags
// appropriately. This is called by main.main(). It only needs to
......@@ -100,7 +100,7 @@ func sessionInitialization() {
// Handle parsing gateway addresses from the config file
gateways := viper.GetStringSlice("gateways")
if gwAddr == "" {
if len(gwAddresses) < 1 {
// If gwAddr was not passed via command line, check config file
if len(gateways) < 1 {
// No gateways in config file or passed via command line
......@@ -108,9 +108,8 @@ func sessionInitialization() {
" configuration file or pass via command line using -g!")
return
} else {
// List of gateways found in config file, select one to use
// TODO: For now, just use the first one?
gwAddr = gateways[0]
// List of gateways found in config file
gwAddresses = gateways
}
}
......@@ -120,16 +119,16 @@ func sessionInitialization() {
// to allow testing with IDs that are long enough to exercise more than
// 64 bits
regCode := new(id.User).SetUints(&[4]uint64{0, 0, 0, userId}).RegistrationCode()
_, err := bindings.Register(regCode, gwAddr, int(numNodes), mint)
_, err := bindings.Register(regCode, "", gwAddresses, mint)
if err != nil {
fmt.Printf("Could Not Register User: %s\n", err.Error())
return
}
}
// Log the user in
// Log the user in, for now using the first gateway specified
uid := id.NewUserFromUint(userId, nil)
_, err = bindings.Login(uid[:], gwAddr, "")
_, err = bindings.Login(uid[:], gwAddresses[0], "")
if err != nil {
fmt.Printf("Could Not Log In\n")
......@@ -224,14 +223,13 @@ var rootCmd = &cobra.Command{
return
} else {
cmd.MarkPersistentFlagRequired("userid")
cmd.MarkPersistentFlagRequired("numnodes")
}
var dummyPeriod time.Duration
var timer *time.Timer
// Set the GatewayCertPath explicitly to avoid data races
SetCertPath(certPath)
// Set the cert paths explicitly to avoid data races
SetCertPaths(gwCertPath, registrationCertPath)
// Set up the listeners for both of the types the client needs for
// the integration test
......@@ -367,14 +365,14 @@ func init() {
rootCmd.PersistentFlags().Uint64VarP(&userId, "userid", "i", 0,
"ID to sign in as")
rootCmd.PersistentFlags().StringVarP(&gwAddr, "gwaddr", "g", "",
"Gateway address to send messages to")
rootCmd.PersistentFlags().StringVarP(&certPath, "certpath", "c", "",
rootCmd.PersistentFlags().StringSliceVarP(&gwAddresses, "gwaddresses",
"g", make([]string, 0), "Gateway addresses for message sending, comma-separated")
rootCmd.PersistentFlags().StringVarP(&gwCertPath, "gwcertpath", "c", "",
"Path to the certificate file for connecting to gateway using TLS")
// TODO: support this negotiating separate keys with different servers
rootCmd.PersistentFlags().UintVarP(&numNodes, "numnodes", "n", 1,
"The number of servers in the network that the client is"+
" connecting to")
rootCmd.PersistentFlags().StringVarP(&registrationCertPath, "registrationcertpath", "r",
"",
"Path to the certificate file for connecting to registration server"+
" using TLS")
rootCmd.PersistentFlags().StringVarP(&sessionFile, "sessionfile", "f",
"", "Passes a file path for loading a session. "+
......@@ -395,9 +393,10 @@ func init() {
"will transmit a random message. Dummies are only sent if this flag is passed")
}
// Sets the cert path in comms
func SetCertPath(path string) {
connect.GatewayCertPath = path
// Sets the cert paths in comms
func SetCertPaths(gwCertPath, registrationCertPath string) {
connect.GatewayCertPath = gwCertPath
connect.RegistrationCertPath = registrationCertPath
}
// initConfig reads in config file and ENV variables if set.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment