Skip to content
Snippets Groups Projects
Select Git revision
  • 41db4bcea193f2c5eddd075f07ddf1ba874d1de1
  • release default protected
  • 11-22-implement-kv-interface-defined-in-collectiveversionedkvgo
  • hotfix/TestHostPool_UpdateNdf_AddFilter
  • XX-4719/announcementChannels
  • xx-4717/logLevel
  • jonah/noob-channel
  • master protected
  • XX-4707/tagDiskJson
  • xx-4698/notification-retry
  • hotfix/notifylockup
  • syncNodes
  • hotfix/localCB
  • XX-4677/NewChanManagerMobile
  • XX-4689/DmSync
  • duplicatePrefix
  • XX-4601/HavenInvites
  • finalizedUICallbacks
  • XX-4673/AdminKeySync
  • debugNotifID
  • anne/test
  • v4.7.5
  • v4.7.4
  • v4.7.3
  • v4.7.2
  • v4.7.1
  • v4.6.3
  • v4.6.1
  • v4.5.0
  • v4.4.4
  • v4.3.11
  • v4.3.8
  • v4.3.7
  • v4.3.6
  • v4.3.5
  • v4.2.0
  • v4.3.0
  • v4.3.4
  • v4.3.3
  • v4.3.2
  • v4.3.1
41 results

client_test.go

Blame
  • client_test.go 14.15 KiB
    ////////////////////////////////////////////////////////////////////////////////
    // Copyright © 2019 Privategrity Corporation                                   /
    //                                                                             /
    // All rights reserved.                                                        /
    ////////////////////////////////////////////////////////////////////////////////
    
    package api
    
    import (
    	"bytes"
    	"crypto/sha256"
    	"encoding/gob"
    	"github.com/golang/protobuf/proto"
    	"gitlab.com/elixxir/client/cmixproto"
    	"gitlab.com/elixxir/client/globals"
    	"gitlab.com/elixxir/client/keyStore"
    	"gitlab.com/elixxir/client/parse"
    	"gitlab.com/elixxir/client/user"
    	"gitlab.com/elixxir/crypto/csprng"
    	"gitlab.com/elixxir/crypto/diffieHellman"
    	"gitlab.com/elixxir/crypto/e2e"
    	"gitlab.com/elixxir/crypto/hash"
    	"gitlab.com/elixxir/crypto/signature"
    	"gitlab.com/elixxir/primitives/format"
    	"gitlab.com/elixxir/primitives/id"
    	"reflect"
    	"testing"
    	"time"
    )
    
    var testClient *Client
    
    func TestRegistrationGob(t *testing.T) {
    	// Get a Client
    	var err error
    	testClient, err = NewClient(&globals.RamStorage{}, "")
    	if err != nil {
    		t.Error(err)
    	}
    
    	// populate a gob in the store
    	grp := getGroup()
    	_, err = testClient.Register(true, "UAV6IWD6",
    		"", "", RegGWAddresses[:], false, grp)
    	if err != nil {
    		t.Error(err)
    	}
    
    	// get the gob out of there again
    	sessionGob := testClient.storage.Load()
    	var sessionBytes bytes.Buffer
    	sessionBytes.Write(sessionGob)
    	dec := gob.NewDecoder(&sessionBytes)
    	Session = user.SessionObj{}
    	err = dec.Decode(&Session)
    	if err != nil {
    		t.Error(err)
    	}
    
    	VerifyRegisterGobAddress(t)
    	VerifyRegisterGobKeys(t)
    	VerifyRegisterGobUser(t)
    }
    
    func VerifyRegisterGobAddress(t *testing.T) {
    
    	if Session.GetGWAddress() != RegGWAddresses[0] {
    		t.Errorf("GetGWAddress() returned %v, expected %v",
    			Session.GetGWAddress(), RegGWAddresses[0])
    	}
    }
    
    func VerifyRegisterGobUser(t *testing.T) {
    	if *Session.GetCurrentUser().User != *id.NewUserFromUint(5, t) {
    		t.Errorf("User's ID was %q, expected %v",
    			Session.GetCurrentUser().User, 5)
    	}
    }
    
    func VerifyRegisterGobKeys(t *testing.T) {
    	grp := getGroup()
    	h := sha256.New()
    	h.Write([]byte(string(20005)))
    	expectedTransmissionBaseKey := grp.NewIntFromBytes(h.Sum(nil))
    	if Session.GetKeys()[0].TransmissionKey.Cmp(
    		expectedTransmissionBaseKey) != 0 {
    		t.Errorf("Transmission base key was %v, expected %v",
    			Session.GetKeys()[0].TransmissionKey.Text(16),
    			expectedTransmissionBaseKey.Text(16))
    	}
    	h = sha256.New()
    	h.Write([]byte(string(40005)))
    	expectedReceptionBaseKey := grp.NewIntFromBytes(h.Sum(nil))
    	if Session.GetKeys()[0].ReceptionKey.Cmp(
    		expectedReceptionBaseKey) != 0 {
    		t.Errorf("Reception base key was %v, expected %v",
    			Session.GetKeys()[0].ReceptionKey.Text(16),
    			expectedReceptionBaseKey.Text(16))
    	}
    }
    
    // Make sure that a formatted text message can deserialize to the text
    // message we would expect
    func TestFormatTextMessage(t *testing.T) {
    	msgText := "Hello"
    	msg := FormatTextMessage(msgText)
    	parsed := cmixproto.TextMessage{}
    	err := proto.Unmarshal(msg, &parsed)
    	// Make sure it parsed correctly
    	if err != nil {
    		t.Errorf("Got error parsing text message: %v", err.Error())
    	}
    	// Check the field that we explicitly set by calling the method
    	if parsed.Message != msgText {
    		t.Errorf("Got wrong text from parsing message. Got %v, expected %v",
    			parsed.Message, msgText)
    	}
    	// Make sure that timestamp is reasonable
    	timeDifference := time.Now().Unix() - parsed.Time
    	if timeDifference > 2 || timeDifference < -2 {
    		t.Errorf("Message timestamp was off by more than one second. "+
    			"Original time: %x, parsed time: %x", time.Now().Unix(), parsed.Time)
    	}
    	t.Logf("message: %q", msg)
    }
    
    func TestParsedMessage_GetSender(t *testing.T) {
    	pm := ParsedMessage{}
    	sndr := pm.GetSender()
    
    	if !reflect.DeepEqual(sndr, []byte{}) {
    		t.Errorf("Sender not empty from typed message")
    	}
    }
    
    func TestParsedMessage_GetPayload(t *testing.T) {
    	pm := ParsedMessage{}
    	payload := []byte{0, 1, 2, 3}
    	pm.Payload = payload
    	pld := pm.GetPayload()
    
    	if !reflect.DeepEqual(pld, payload) {
    		t.Errorf("Output payload does not match input payload: %v %v", payload, pld)
    	}
    }
    
    func TestParsedMessage_GetRecipient(t *testing.T) {
    	pm := ParsedMessage{}
    	rcpt := pm.GetRecipient()
    
    	if !reflect.DeepEqual(rcpt, []byte{}) {
    		t.Errorf("Recipient not empty from typed message")
    	}
    }
    
    func TestParsedMessage_GetMessageType(t *testing.T) {
    	pm := ParsedMessage{}
    	var typeTest int32
    	typeTest = 6
    	pm.Typed = typeTest
    	typ := pm.GetMessageType()
    
    	if typ != typeTest {
    		t.Errorf("Returned type does not match")
    	}
    }
    
    func TestParse(t *testing.T) {
    	ms := parse.Message{}
    	ms.Body = []byte{0, 1, 2}
    	ms.MessageType = int32(cmixproto.Type_NO_TYPE)
    	ms.Receiver = id.ZeroID
    	ms.Sender = id.ZeroID
    
    	messagePacked := ms.Pack()
    
    	msOut, err := ParseMessage(messagePacked)
    
    	if err != nil {
    		t.Errorf("Message failed to parse: %s", err.Error())
    	}
    
    	if msOut.GetMessageType() != int32(ms.MessageType) {
    		t.Errorf("Types do not match after message parse: %v vs %v", msOut.GetMessageType(), ms.MessageType)
    	}
    
    	if !reflect.DeepEqual(ms.Body, msOut.GetPayload()) {
    		t.Errorf("Bodies do not match after message parse: %v vs %v", msOut.GetPayload(), ms.Body)
    	}
    
    }
    
    // Test that registerUserE2E correctly creates keys and adds them to maps
    func TestRegisterUserE2E(t *testing.T) {
    	grp := getGroup()
    	userID := id.NewUserFromUint(18, t)
    	partner := id.NewUserFromUint(14, t)
    	params := signature.CustomDSAParams(
    		grp.GetP(),
    		grp.GetG(),
    		grp.GetQ())
    	rng := csprng.NewSystemRNG()
    	myPrivKey := params.PrivateKeyGen(rng)
    	myPrivKeyCyclic := grp.NewIntFromLargeInt(myPrivKey.GetKey())
    	myPubKey := myPrivKey.PublicKeyGen()
    	partnerPrivKey := params.PrivateKeyGen(rng)
    	partnerPubKey := partnerPrivKey.PublicKeyGen()
    	partnerPubKeyCyclic := grp.NewIntFromLargeInt(partnerPubKey.GetKey())
    
    	myUser := &user.User{User: userID, Nick: "test"}
    	session := user.NewSession(testClient.storage,
    		myUser, "", []user.NodeKeys{}, myPubKey, myPrivKey, grp)
    
    	testClient.sess = session
    
    	testClient.registerUserE2E(partner, partnerPubKeyCyclic.Bytes())
    
    	// Confirm we can get all types of keys
    	km := session.GetKeyStore().GetSendManager(partner)
    	if km == nil {
    		t.Errorf("KeyStore returned nil when obtaining KeyManager for sending")
    	}
    	key, action := km.PopKey()
    	if key == nil {
    		t.Errorf("TransmissionKeys map returned nil")
    	} else if key.GetOuterType() != format.E2E {
    		t.Errorf("Key type expected 'E2E', got %s",
    			key.GetOuterType())
    	} else if action != keyStore.None {
    		t.Errorf("Expected 'None' action, got %s instead",
    			action)
    	}
    
    	key, action = km.PopRekey()
    	if key == nil {
    		t.Errorf("TransmissionReKeys map returned nil")
    	} else if key.GetOuterType() != format.Rekey {
    		t.Errorf("Key type expected 'Rekey', got %s",
    			key.GetOuterType())
    	} else if action != keyStore.None {
    		t.Errorf("Expected 'None' action, got %s instead",
    			action)
    	}
    
    	// Generate one reception key of each type to test
    	// fingerprint map
    	baseKey, _ := diffieHellman.CreateDHSessionKey(partnerPubKeyCyclic, myPrivKeyCyclic, grp)
    	recvKeys := e2e.DeriveKeys(grp, baseKey, partner, uint(1))
    	recvReKeys := e2e.DeriveEmergencyKeys(grp, baseKey, partner, uint(1))
    
    	h, _ := hash.NewCMixHash()
    	h.Write(recvKeys[0].Bytes())
    	fp := format.Fingerprint{}
    	copy(fp[:], h.Sum(nil))
    
    	key = session.GetKeyStore().GetRecvKey(fp)
    	if key == nil {
    		t.Errorf("ReceptionKeys map returned nil for Key")
    	} else if key.GetOuterType() != format.E2E {
    		t.Errorf("Key type expected 'E2E', got %s",
    			key.GetOuterType())
    	}
    
    	h.Reset()
    	h.Write(recvReKeys[0].Bytes())
    	copy(fp[:], h.Sum(nil))
    
    	key = session.GetKeyStore().GetRecvKey(fp)
    	if key == nil {
    		t.Errorf("ReceptionKeys map returned nil for ReKey")
    	} else if key.GetOuterType() != format.Rekey {
    		t.Errorf("Key type expected 'Rekey', got %s",
    			key.GetOuterType())
    	}
    }
    
    // Test all keys created with registerUserE2E match what is expected
    func TestRegisterUserE2E_CheckAllKeys(t *testing.T) {
    	grp := getGroup()
    	userID := id.NewUserFromUint(18, t)
    	partner := id.NewUserFromUint(14, t)
    	params := signature.CustomDSAParams(
    		grp.GetP(),
    		grp.GetG(),
    		grp.GetQ())
    	rng := csprng.NewSystemRNG()
    	myPrivKey := params.PrivateKeyGen(rng)
    	myPrivKeyCyclic := grp.NewIntFromLargeInt(myPrivKey.GetKey())
    	myPubKey := myPrivKey.PublicKeyGen()
    	partnerPrivKey := params.PrivateKeyGen(rng)
    	partnerPubKey := partnerPrivKey.PublicKeyGen()
    	partnerPubKeyCyclic := grp.NewIntFromLargeInt(partnerPubKey.GetKey())
    
    	myUser := &user.User{User: userID, Nick: "test"}
    	session := user.NewSession(testClient.storage,
    		myUser, "", []user.NodeKeys{}, myPubKey,
    		myPrivKey, grp)
    
    	testClient.sess = session
    
    	testClient.registerUserE2E(partner, partnerPubKeyCyclic.Bytes())
    
    	// Generate all keys and confirm they all match
    	keyParams := testClient.GetKeyParams()
    	baseKey, _ := diffieHellman.CreateDHSessionKey(partnerPubKeyCyclic, myPrivKeyCyclic, grp)
    	keyTTL, numKeys := e2e.GenerateKeyTTL(baseKey.GetLargeInt(),
    		keyParams.MinKeys, keyParams.MaxKeys, keyParams.TTLParams)
    
    	sendKeys := e2e.DeriveKeys(grp, baseKey, userID, uint(numKeys))
    	sendReKeys := e2e.DeriveEmergencyKeys(grp, baseKey,
    		userID, uint(keyParams.NumRekeys))
    	recvKeys := e2e.DeriveKeys(grp, baseKey, partner, uint(numKeys))
    	recvReKeys := e2e.DeriveEmergencyKeys(grp, baseKey,
    		partner, uint(keyParams.NumRekeys))
    
    	// Confirm all keys
    	km := session.GetKeyStore().GetSendManager(partner)
    	if km == nil {
    		t.Errorf("KeyStore returned nil when obtaining KeyManager for sending")
    	}
    	for i := 0; i < int(numKeys); i++ {
    		key, action := km.PopKey()
    		if key == nil {
    			t.Errorf("TransmissionKeys map returned nil")
    		} else if key.GetOuterType() != format.E2E {
    			t.Errorf("Key type expected 'E2E', got %s",
    				key.GetOuterType())
    		}
    
    		if i < int(keyTTL-1) {
    			if action != keyStore.None {
    				t.Errorf("Expected 'None' action, got %s instead",
    					action)
    			}
    		} else {
    			if action != keyStore.Rekey {
    				t.Errorf("Expected 'Rekey' action, got %s instead",
    					action)
    			}
    		}
    
    		if key.GetKey().Cmp(sendKeys[int(numKeys)-1-i]) != 0 {
    			t.Errorf("Key value expected %s, got %s",
    				sendKeys[int(numKeys)-1-i].Text(10),
    				key.GetKey().Text(10))
    		}
    	}
    
    	for i := 0; i < int(keyParams.NumRekeys); i++ {
    		key, action := km.PopRekey()
    		if key == nil {
    			t.Errorf("TransmissionReKeys map returned nil")
    		} else if key.GetOuterType() != format.Rekey {
    			t.Errorf("Key type expected 'Rekey', got %s",
    				key.GetOuterType())
    		}
    
    		if i < int(keyParams.NumRekeys-1) {
    			if action != keyStore.None {
    				t.Errorf("Expected 'None' action, got %s instead",
    					action)
    			}
    		} else {
    			if action != keyStore.Purge {
    				t.Errorf("Expected 'Purge' action, got %s instead",
    					action)
    			}
    		}
    
    		if key.GetKey().Cmp(sendReKeys[int(keyParams.NumRekeys)-1-i]) != 0 {
    			t.Errorf("Key value expected %s, got %s",
    				sendReKeys[int(keyParams.NumRekeys)-1-i].Text(10),
    				key.GetKey().Text(10))
    		}
    	}
    
    	h, _ := hash.NewCMixHash()
    	fp := format.Fingerprint{}
    
    	for i := 0; i < int(numKeys); i++ {
    		h.Reset()
    		h.Write(recvKeys[i].Bytes())
    		copy(fp[:], h.Sum(nil))
    		key := session.GetKeyStore().GetRecvKey(fp)
    		if key == nil {
    			t.Errorf("ReceptionKeys map returned nil for Key")
    		} else if key.GetOuterType() != format.E2E {
    			t.Errorf("Key type expected 'E2E', got %s",
    				key.GetOuterType())
    		}
    
    		if key.GetKey().Cmp(recvKeys[i]) != 0 {
    			t.Errorf("Key value expected %s, got %s",
    				recvKeys[i].Text(10),
    				key.GetKey().Text(10))
    		}
    	}
    
    	for i := 0; i < int(keyParams.NumRekeys); i++ {
    		h.Reset()
    		h.Write(recvReKeys[i].Bytes())
    		copy(fp[:], h.Sum(nil))
    		key := session.GetKeyStore().GetRecvKey(fp)
    		if key == nil {
    			t.Errorf("ReceptionKeys map returned nil for Rekey")
    		} else if key.GetOuterType() != format.Rekey {
    			t.Errorf("Key type expected 'Rekey', got %s",
    				key.GetOuterType())
    		}
    
    		if key.GetKey().Cmp(recvReKeys[i]) != 0 {
    			t.Errorf("Key value expected %s, got %s",
    				recvReKeys[i].Text(10),
    				key.GetKey().Text(10))
    		}
    	}
    }
    
    // FIXME Reinstate tests for the UDB api
    //var ListenCh chan *format.Message
    //var lastmsg string
    
    //type dummyMessaging struct {
    //	listener chan *format.Message
    //}
    
    // SendMessage to the server
    //func (d *dummyMessaging) SendMessage(recipientID id.User,
    //	message string) error {
    //	jww.INFO.Printf("Sending: %s", message)
    //	lastmsg = message
    //	return nil
    //}
    
    // Listen for messages from a given sender
    //func (d *dummyMessaging) Listen(senderID id.User) chan *format.Message {
    //	return d.listener
    //}
    
    // StopListening to a given switchboard (closes and deletes)
    //func (d *dummyMessaging) StopListening(listenerCh chan *format.Message) {}
    
    // MessageReceiver thread to get new messages
    //func (d *dummyMessaging) MessageReceiver(delay time.Duration) {}
    
    //var pubKeyBits []string
    //var keyFingerprint string
    //var pubKey []byte
    
    // SendMsg puts a fake udb response message on the channel
    //func SendMsg(msg string) {
    //	m, _ := format.NewMessage(13, 1, msg)
    //	ListenCh <- &m[0]
    //}
    
    //func TestRegisterPubKeyByteLen(t *testing.T) {
    //	ListenCh = make(chan *format.Message, 100)
    //	io.Messaging = &dummyMessaging{
    //		switchboard: ListenCh,
    //	}
    //	pubKeyBits = []string{
    //		"S8KXBczy0jins9uS4LgBPt0bkFl8t00MnZmExQ6GcOcu8O7DKgAsNz" +
    //			"LU7a+gMTbIsS995IL/kuFF8wcBaQJBY23095PMSQ/nMuetzhk9HdXxrGIiKBo3C/n4SClp" +
    //			"q4H+PoF9XziEVKua8JxGM2o83KiCK3tNUpaZbAAElkjueY4=",
    //		"8Lg/eoeKGgPlleTYfO3JyGfnwBtLi73ti0h2dBQWW94JTqTQDr+z" +
    //			"xVpLzdgTt+87TkAl0yXu9mOUXqGJ+51lTcRlIdIpWpfgUbibdRme8IThg0RNCF31ESKCts" +
    //			"o8gJ8mSVljIXxrC+Uuoi+Gl1LNN5nPARykatx0Y70xNdJd2BQ=",
    //	}
    //	pubKey = make([]byte, 256)
    //	for i := range pubKeyBits {
    //		pubkeyBytes, _ := base64.StdEncoding.DecodeString(pubKeyBits[i])
    //		for j := range pubkeyBytes {
    //			pubKey[j+i*128] = pubkeyBytes[j]
    //		}
    //	}
    //
    //	keyFingerprint = "8oKh7TYG4KxQcBAymoXPBHSD/uga9pX3Mn/jKhvcD8M="
    //	//SendMsg("SEARCH blah@privategrity.com NOTFOUND")
    //	SendMsg(fmt.Sprintf("GETKEY %s NOTFOUND", keyFingerprint))
    //	SendMsg("PUSHKEY ACK NEED 128")
    //	SendMsg(fmt.Sprintf("PUSHKEY COMPLETE %s", keyFingerprint))
    //	SendMsg("REGISTRATION COMPLETE")
    //
    //	err := bots.Register("EMAIL", "blah@privategrity.com", pubKey)
    //
    //	if err != nil {
    //		t.Errorf("Unexpected error: %s", err.Error())
    //	}
    //	if len(lastmsg) != 81 {
    //		t.Errorf("Message wrong length: %d v. expected 81", len(lastmsg))
    //	}
    //}