From 0839d37f162cbe5aaa75616428e9904a91613db0 Mon Sep 17 00:00:00 2001 From: "Richard T. Carback III" <rick.carback@gmail.com> Date: Mon, 21 Sep 2020 18:57:29 +0000 Subject: [PATCH] cleanup deprecated code Some of this will come back, but due to the major overhaul in the api we deemed it better to clear it out and copy it back. --- api/client_test.go | 814 --------------------------------- api/connect.go | 228 ---------- api/mockserver.go | 407 ----------------- api/mockserver_test.go | 581 ------------------------ api/register.go | 285 ------------ api/register_test.go | 138 ------ bindings/client.go | 497 --------------------- bindings/client_test.go | 914 -------------------------------------- bots/README.md | 1 - bots/bots.go | 122 ----- bots/bots_test.go | 290 ------------ bots/userDiscovery.go | 284 ------------ userRegistry/regCode.go | 21 - userRegistry/user.go | 161 ------- userRegistry/user_test.go | 134 ------ 15 files changed, 4877 deletions(-) delete mode 100644 api/client_test.go delete mode 100644 api/connect.go delete mode 100644 api/mockserver.go delete mode 100644 api/mockserver_test.go delete mode 100644 api/register.go delete mode 100644 api/register_test.go delete mode 100644 bindings/client.go delete mode 100644 bindings/client_test.go delete mode 100644 bots/README.md delete mode 100644 bots/bots.go delete mode 100644 bots/bots_test.go delete mode 100644 bots/userDiscovery.go delete mode 100644 userRegistry/regCode.go delete mode 100644 userRegistry/user.go delete mode 100644 userRegistry/user_test.go diff --git a/api/client_test.go b/api/client_test.go deleted file mode 100644 index 2d6b35217..000000000 --- a/api/client_test.go +++ /dev/null @@ -1,814 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -package api - -import ( - "github.com/golang/protobuf/proto" - "gitlab.com/elixxir/client/cmixproto" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/keyStore" - "gitlab.com/elixxir/client/network" - "gitlab.com/elixxir/client/network/keyExchange" - "gitlab.com/elixxir/client/parse" - "gitlab.com/elixxir/client/storage" - user2 "gitlab.com/elixxir/client/storage/user" - "gitlab.com/elixxir/client/user" - "gitlab.com/elixxir/crypto/csprng" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/diffieHellman" - "gitlab.com/elixxir/crypto/e2e" - "gitlab.com/elixxir/crypto/hash" - "gitlab.com/elixxir/crypto/large" - "gitlab.com/elixxir/primitives/format" - "gitlab.com/xx_network/crypto/signature/rsa" - "gitlab.com/xx_network/primitives/id" - "reflect" - "testing" - "time" -) - -var TestKeySize = 768 - -// 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) -} - -//Happy path -func TestParsedMessage_GetSender(t *testing.T) { - pm := ParsedMessage{} - sndr := pm.GetSender() - - if !reflect.DeepEqual(sndr, []byte{}) { - t.Errorf("Sender not empty from typed message") - } -} - -//Happy path -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) - } -} - -//Happy path -func TestParsedMessage_GetRecipient(t *testing.T) { - pm := ParsedMessage{} - rcpt := pm.GetRecipient() - - if !reflect.DeepEqual(rcpt, []byte{}) { - t.Errorf("Recipient not empty from typed message") - } -} - -//Happy path -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") - } -} - -// Error path -func TestNewClient_Panic(t *testing.T) { - defer func() { - if e := recover(); e != nil { - - } - - }() - // Arbitrary invalid interface - var i rsa.PublicKey - // Passed into NewTestClient call to cause a panic - NewTestClient(&globals.RamStorage{}, ".ekv-testnewclientpanic/a", "", def, i, send) - t.Errorf("Failed to detect a bad interface passed in") -} - -// Happy path -func TestNewClient(t *testing.T) { - _, err := NewTestClient(&globals.RamStorage{}, ".ekv-testnewclient/a", "", def, t, send) - if err != nil { - t.Errorf("Expected happy path, received error: %+v", err) - } -} - -//Happy path -func TestParse(t *testing.T) { - ms := parse.Message{} - ms.Body = []byte{0, 1, 2} - ms.MessageType = int32(keyExchange.Type_NO_TYPE) - ms.Receiver = &id.ZeroUser - ms.Sender = &id.ZeroUser - - 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) { - testClient, err := NewClient(&globals.RamStorage{}, ".ekv-testrege2e/a", "", def) - if err != nil { - t.Error(err) - } - - rng := csprng.NewSystemRNG() - cmixGrp, e2eGrp := getGroups() - userID := id.NewIdFromUInt(18, id.User, t) - partner := id.NewIdFromUInt(14, id.User, t) - - myPrivKeyCyclic := e2eGrp.RandomCoprime(e2eGrp.NewMaxInt()) - myPubKeyCyclic := e2eGrp.ExpG(myPrivKeyCyclic, e2eGrp.NewMaxInt()) - - partnerPubKeyCyclic := e2eGrp.RandomCoprime(e2eGrp.NewMaxInt()) - - privateKeyRSA, _ := rsa.GenerateKey(rng, TestKeySize) - publicKeyRSA := rsa.PublicKey{PublicKey: privateKeyRSA.PublicKey} - - myUser := &user2.User{User: userID, Username: "test"} - session := user.NewSession(testClient.storage, "password") - - userData := &user2.UserData{ - ThisUser: myUser, - RSAPrivateKey: privateKeyRSA, - RSAPublicKey: &publicKeyRSA, - CMIXDHPrivateKey: nil, - CMIXDHPublicKey: nil, - E2EDHPrivateKey: myPrivKeyCyclic, - E2EDHPublicKey: myPubKeyCyclic, - CmixGrp: cmixGrp, - E2EGrp: e2eGrp, - Salt: make([]byte, 1), - } - sessionV2 := storage.InitTestingSession(t) - sessionV2.CommitUserData(userData) - - testClient.session = session - testClient.sessionV2 = sessionV2 - - err = testClient.registerUserE2E(&storage.Contact{ - Id: partner, - PublicKey: partnerPubKeyCyclic.Bytes(), - }) - if err != nil { - t.Fatal(err) - } - - // 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() != parse.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() != parse.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, e2eGrp) - recvKeys := e2e.DeriveKeys(e2eGrp, baseKey, partner, uint(1)) - recvReKeys := e2e.DeriveEmergencyKeys(e2eGrp, 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() != parse.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() != parse.Rekey { - t.Errorf("Key type expected 'Rekey', got %s", - key.GetOuterType()) - } - disconnectServers() -} - -// Test all keys created with registerUserE2E match what is expected -func TestRegisterUserE2E_CheckAllKeys(t *testing.T) { - testClient, err := NewClient(&globals.RamStorage{}, ".ekv-testrege2e-allkeys/a", "", def) - if err != nil { - t.Fatal(err) - } - - cmixGrp, e2eGrp := getGroups() - userID := id.NewIdFromUInt(18, id.User, t) - partner := id.NewIdFromUInt(14, id.User, t) - - rng := csprng.NewSystemRNG() - myPrivKeyCyclic := e2eGrp.RandomCoprime(e2eGrp.NewMaxInt()) - myPubKeyCyclic := e2eGrp.ExpG(myPrivKeyCyclic, e2eGrp.NewMaxInt()) - - partnerPrivKeyCyclic := e2eGrp.RandomCoprime(e2eGrp.NewMaxInt()) - partnerPubKeyCyclic := e2eGrp.ExpG(partnerPrivKeyCyclic, e2eGrp.NewMaxInt()) - - privateKeyRSA, _ := rsa.GenerateKey(rng, TestKeySize) - publicKeyRSA := rsa.PublicKey{PublicKey: privateKeyRSA.PublicKey} - - myUser := &user2.User{User: userID, Username: "test"} - session := user.NewSession(testClient.storage, "password") - - userData := &user2.UserData{ - ThisUser: myUser, - RSAPrivateKey: privateKeyRSA, - RSAPublicKey: &publicKeyRSA, - CMIXDHPrivateKey: nil, - CMIXDHPublicKey: nil, - E2EDHPrivateKey: myPrivKeyCyclic, - E2EDHPublicKey: myPubKeyCyclic, - CmixGrp: cmixGrp, - E2EGrp: e2eGrp, - Salt: make([]byte, 1), - } - sessionV2 := storage.InitTestingSession(t) - sessionV2.CommitUserData(userData) - - testClient.session = session - testClient.sessionV2 = sessionV2 - - err = testClient.registerUserE2E(&storage.Contact{ - Id: partner, - PublicKey: partnerPubKeyCyclic.Bytes(), - }) - if err != nil { - t.Fatal(err) - } - - // Generate all keys and confirm they all match - keyParams := testClient.GetKeyParams() - baseKey, _ := diffieHellman.CreateDHSessionKey(partnerPubKeyCyclic, myPrivKeyCyclic, e2eGrp) - keyTTL, numKeys := e2e.GenerateKeyTTL(baseKey.GetLargeInt(), - keyParams.MinKeys, keyParams.MaxKeys, keyParams.TTLParams) - - sendKeys := e2e.DeriveKeys(e2eGrp, baseKey, userID, uint(numKeys)) - sendReKeys := e2e.DeriveEmergencyKeys(e2eGrp, baseKey, - userID, uint(keyParams.NumRekeys)) - recvKeys := e2e.DeriveKeys(e2eGrp, baseKey, partner, uint(numKeys)) - recvReKeys := e2e.DeriveEmergencyKeys(e2eGrp, 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() != parse.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() != parse.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() != parse.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() != parse.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)) - } - } - disconnectServers() -} - -// Test happy path for precannedRegister -func TestClient_precannedRegister(t *testing.T) { - //Start client - testClient, err := NewClient(&globals.RamStorage{}, ".ekv-testclient-precannedreg/a", "", def) - - if err != nil { - t.Error(err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Error(err) - } - - _, _, _, err = testClient.precannedRegister("WTROXJ33") - if err != nil { - t.Errorf("Error during precannedRegister: %+v", err) - } - - //Disconnect and shutdown servers - disconnectServers() -} - -// Test happy path for sendRegistrationMessage -func TestClient_sendRegistrationMessage(t *testing.T) { - - //Start client - testClient, err := NewClient(&globals.RamStorage{}, ".ekv-sendregmsg/a", "", def) - if err != nil { - t.Error(err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Error(err) - } - - rng := csprng.NewSystemRNG() - privateKeyRSA, _ := rsa.GenerateKey(rng, TestKeySize) - publicKeyRSA := rsa.PublicKey{PublicKey: privateKeyRSA.PublicKey} - - _, err = testClient.sendRegistrationMessage("WTROXJ33", &publicKeyRSA) - if err != nil { - t.Errorf("Error during sendRegistrationMessage: %+v", err) - } - - //Disconnect and shutdown servers - disconnectServers() -} - -// Test happy path for requestNonce -func TestClient_requestNonce(t *testing.T) { - cmixGrp, _ := getGroups() - privateKeyDH := cmixGrp.RandomCoprime(cmixGrp.NewMaxInt()) - publicKeyDH := cmixGrp.ExpG(privateKeyDH, cmixGrp.NewMaxInt()) - rng := csprng.NewSystemRNG() - privateKeyRSA, _ := rsa.GenerateKey(rng, TestKeySize) - publicKeyRSA := rsa.PublicKey{PublicKey: privateKeyRSA.PublicKey} - - testClient, err := NewClient(&globals.RamStorage{}, ".ekv-reqnonce/a", "", def) - if err != nil { - t.Error(err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Error(err) - } - - salt := make([]byte, 256) - _, err = csprng.NewSystemRNG().Read(salt) - if err != nil { - t.Errorf("Unable to generate salt! %s", err) - } - - gwID, err := id.Unmarshal(testClient.ndf.Gateways[0].ID) - if err != nil { - t.Fatal(err) - } - gwID.SetType(id.Gateway) - _, _, err = testClient.requestNonce(salt, []byte("test"), publicKeyDH, &publicKeyRSA, privateKeyRSA, gwID) - if err != nil { - t.Errorf("Error during requestNonce: %+v", err) - } - - disconnectServers() -} - -// Test happy path for confirmNonce -func TestClient_confirmNonce(t *testing.T) { - - testClient, err := NewClient(&globals.RamStorage{}, ".ekv-confirmnonce/a", "", def) - if err != nil { - t.Error(err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Error(err) - } - rng := csprng.NewSystemRNG() - privateKeyRSA, _ := rsa.GenerateKey(rng, TestKeySize) - gwID, err := id.Unmarshal(testClient.ndf.Gateways[0].ID) - if err != nil { - t.Fatal(err) - } - gwID.SetType(id.Gateway) - err = testClient.confirmNonce([]byte("user"), []byte("test"), privateKeyRSA, gwID) - if err != nil { - t.Errorf("Error during confirmNonce: %+v", err) - } - //Disconnect and shutdown servers - disconnectServers() -} - -func getGroups() (*cyclic.Group, *cyclic.Group) { - - cmixGrp := cyclic.NewGroup( - large.NewIntFromString("9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48"+ - "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F"+ - "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5"+ - "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2"+ - "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41"+ - "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE"+ - "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15"+ - "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", 16), - large.NewIntFromString("5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613"+ - "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4"+ - "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472"+ - "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5"+ - "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA"+ - "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71"+ - "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0"+ - "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", 16)) - - e2eGrp := cyclic.NewGroup( - large.NewIntFromString("E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B"+ - "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE"+ - "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F"+ - "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041"+ - "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45"+ - "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209"+ - "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29"+ - "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E"+ - "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2"+ - "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696"+ - "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E"+ - "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873"+ - "847AEF49F66E43873", 16), - large.NewIntFromString("2", 16)) - - return cmixGrp, e2eGrp - -} - -// Test happy path for client.GetSession -func TestClient_GetSession(t *testing.T) { - - //Start client - testClient, _ := NewClient(&globals.RamStorage{}, ".ekv-getsession/a", "", def) - - testClient.session = &user.SessionObj{} - - if !reflect.DeepEqual(testClient.GetSession(), testClient.session) { - t.Error("Received session not the same as the real session") - } - -} - -// Test happy path for client.GetCommManager -func TestClient_GetCommManager(t *testing.T) { - - //Start client - testClient, _ := NewClient(&globals.RamStorage{}, ".ekv-getcommmanager/a", "", def) - - testClient.receptionManager = &network.ReceptionManager{} - - if !reflect.DeepEqual(testClient.GetCommManager(), testClient.receptionManager) { - t.Error("Received session not the same as the real session") - } -} - -// Test that client.Shutcown clears out all the expected variables and stops the message reciever. -func TestClient_LogoutHappyPath(t *testing.T) { - //Initialize a client - d := DummyStorage{LocationA: ".ekv-logouthappypath/a", StoreA: []byte{'a', 'b', 'c'}} - tc, _ := NewClient(&d, ".ekv-logouthappypath/a", "", def) - - uid := id.NewIdFromString("kk", id.User, t) - tc.receptionManager, _ = network.NewReceptionManager(tc.rekeyChan, - tc.quitChan, - uid, nil, nil, nil, tc.switchboard) - - err := tc.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = tc.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - //Start Message receiver - callBack := func(err error) { - t.Log(err) - } - - err = tc.StartMessageReceiver(callBack) - if err != nil { - t.Logf("Failed to start message reciever %+v", err) - t.Fail() - } - - //Introduce a delay to allow things to startup and run - time.Sleep(1 * time.Second) - - err = tc.Logout(500 * time.Millisecond) - if err != nil { - t.Logf("Timeout occured failed to shutdown %+v", err) - t.Fail() - } - - //Check everything that should be nil is nil - if tc.session != nil { - t.Logf("Session should be set to nil on shutdown") - t.Fail() - } - if tc.registrationVersion != "" { - t.Logf("RegistrationVerison should be set to empty string on shutdown") - t.Fail() - } - if tc.receptionManager != nil { - t.Logf("ReceptionManager should be set to nil on shutdown") - t.Fail() - } - if tc.topology != nil { - t.Logf("Topology should be set to nil on shutdown") - t.Fail() - } - - //Test that the things that should not be nil are not nil - if tc.ndf == nil { - t.Logf("NDF should not be set to nil") - t.Fail() - } - if tc.storage == nil { - t.Logf("Storage should not be set to nil") - t.Fail() - } - if tc.opStatus == nil { - t.Logf("OPstatus should not be set to nil on shutdown") - t.Fail() - } - if tc.rekeyChan == nil { - t.Logf("rekeyChan should not be set to nil on shutdown") - t.Fail() - } -} - -//Test that the client shutdown will timeout when it fails to shutdown -func TestClient_LogoutTimeout(t *testing.T) { - //Initialize a client - d := DummyStorage{LocationA: ".ekv-logouttimeout/a", StoreA: []byte{'a', 'b', 'c'}} - tc, _ := NewClient(&d, ".ekv-logouttimeout/a", "", def) - - uid := id.NewIdFromString("kk", id.User, t) - tc.receptionManager, _ = network.NewReceptionManager(tc.rekeyChan, - tc.quitChan, uid, nil, nil, nil, tc.switchboard) - - err := tc.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = tc.GenerateKeys(nil, "") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - // Because we never initiated startMessageReceiver this should timeout. - err = tc.Logout(500 * time.Millisecond) - if err == nil { - t.Logf("Timeout out should have occured") - t.Fail() - } - - //Check everything that should be nil is nil - if tc.session == nil { - t.Logf("Session should not be set to nil on shutdown timeout") - t.Fail() - } - if tc.registrationVersion == "" { - t.Logf("RegistrationVerison should not be set to empty string on shutdown timeout") - t.Fail() - } - if tc.receptionManager == nil { - t.Logf("ReceptionManager should not be set to nil on shutdown timeout") - t.Fail() - } - if tc.topology == nil { - t.Logf("Topology should not be set to nil on shutdown timeout") - t.Fail() - } - if tc.opStatus == nil { - t.Logf("OPstatus should not be set to nil on shutdown timeout") - t.Fail() - } - if tc.rekeyChan == nil { - t.Logf("rekeyChan should not be set to nil on shutdown timeout") - t.Fail() - } - - //Test that the things that should not be nil are not nil - if tc.ndf == nil { - t.Logf("NDF should not be set to nil on shutdown timeout") - t.Fail() - } - if tc.storage == nil { - t.Logf("Storage should not be set to nil on shutdown timeout") - t.Fail() - } - -} - -// Test that if we logout we can logback in. -func TestClient_LogoutAndLoginAgain(t *testing.T) { - //Initialize a client - dummyStorage := &DummyStorage{LocationA: ".ekv-logoutloginagain/a", StoreA: []byte{'a', 'b', 'c'}} - tc, err := NewClient(dummyStorage, ".ekv-logoutloginagain/a", "", def) - if err != nil { - t.Errorf("Failed to create new client: %+v", err) - } - - uid := id.NewIdFromString("kk", id.User, t) - tc.receptionManager, _ = network.NewReceptionManager(tc.rekeyChan, - tc.quitChan, uid, nil, nil, nil, tc.switchboard) - - err = tc.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = tc.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - tc.sessionV2.SetRegState(user.PermissioningComplete) - - //Start Message receiver - callBack := func(err error) { - t.Log(err) - } - - err = tc.StartMessageReceiver(callBack) - if err != nil { - t.Logf("Failed to start message reciever %+v", err) - t.Fail() - } - - // Because we never initiated startMessageReceiver this should timeout. - err = tc.Logout(500 * time.Millisecond) - if err != nil { - t.Logf("Timeout out should have not occured. %+v", err) - t.Fail() - } - - //Redefine client with old session files and attempt to login. - tc, err = NewClient(dummyStorage, ".ekv-logoutloginagain/a", "", def) - if err != nil { - t.Errorf("Failed second client initialization: %+v", err) - } - err = tc.InitNetwork() - if err != nil { - t.Fatalf("InitNetwork should have succeeded when creating second client %v", err) - } - - _, err = tc.Login("password") - if err != nil { - t.Logf("Login failed %+v", err) - t.Fail() - } - -} diff --git a/api/connect.go b/api/connect.go deleted file mode 100644 index 68f398c00..000000000 --- a/api/connect.go +++ /dev/null @@ -1,228 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -package api - -import ( - "fmt" - "github.com/pkg/errors" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/network" - "gitlab.com/elixxir/primitives/version" - "gitlab.com/xx_network/comms/connect" - "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/ndf" -) - -var ErrNoPermissioning = errors.New("No Permissioning In NDF") - -// Checks version and connects to gateways using TLS filepaths to create -// credential information for connection establishment -// Call this before logging in! -func (cl *Client) InitNetwork() error { - var err error - if cl.receptionManager == nil { - // Start reception manager with a dummy user, - // so we can connect to things - cl.receptionManager, err = network.NewReceptionManager(cl.rekeyChan, - cl.quitChan, &id.DummyUser, nil, nil, nil, - cl.switchboard) - if err != nil { - return errors.Wrap(err, - "Failed to create reception manager") - } - } - - //InitNetwork to permissioning - err = addPermissioningHost(cl.receptionManager, cl.ndf) - - if err != nil { - if err != ErrNoPermissioning { - // Permissioning has an error so stop running - return err - } - globals.Log.WARN.Print("Skipping connection to permissioning, most likely no permissioning information in NDF") - } - - runPermissioning := err != ErrNoPermissioning - - if runPermissioning { - globals.Log.DEBUG.Printf("Setting up permissioning...") - err = cl.setupPermissioning() - - if err != nil { - return err - } - } - - // InitNetwork to nodes - cl.topology, err = BuildNodeTopology(cl.ndf) - if err != nil { - return err - } - err = addNotificationBotHost(cl.receptionManager, cl.ndf) - if err != nil { - return errors.Errorf("Failed to connect to notification bot at %+v", cl.ndf) - } - - return addGatewayHosts(cl.receptionManager, cl.ndf) -} - -// AddNotificationBotHost adds notification bot as a host within the reception manager -func addNotificationBotHost(rm *network.ReceptionManager, definition *ndf.NetworkDefinition) error { - - err := addHost(rm, &id.NotificationBot, definition.Notification.Address, - definition.Notification.TlsCertificate, false, true) - if err != nil { - return errors.Errorf("Failed to connect to notification bot at %+v", - definition.Notification.Address) - } - return nil -} - -// BuildNodeTopology is a helper function which goes through the ndf and -// builds a circuit for all the node's in the definition -func BuildNodeTopology(definition *ndf.NetworkDefinition) (*connect.Circuit, error) { - //build the topology - nodeIDs := make([]*id.ID, len(definition.Nodes)) - var err error - for i, node := range definition.Nodes { - nodeIDs[i], err = id.Unmarshal(node.ID) - if err != nil { - return nil, err - } - } - - return connect.NewCircuit(nodeIDs), nil -} - -// DisableTls disables tls for communications -func (cl *Client) DisableTls() { - globals.Log.INFO.Println("Running client without tls") - cl.receptionManager.Comms.DisableAuth() - cl.receptionManager.Tls = false -} - -// Begin client version checks via registration server -func (cl *Client) setupPermissioning() error { - - //Get remote version and update - ver, err := cl.receptionManager.GetRemoteVersion() - if err != nil { - return err - } - cl.registrationVersion = ver - - //Request a new ndf from permissioning - def, err = cl.receptionManager.Comms.RetrieveNdf(cl.ndf) - if err != nil { - return err - } - if def != nil { - cl.ndf = def - } - - globals.Log.DEBUG.Printf("Local version: %v; Remote version: %v", - globals.SEMVER, cl.GetRegistrationVersion()) - - // Only check the version if we got a remote version - // The remote version won't have been populated if we didn't connect to permissioning - if cl.GetRegistrationVersion() != "" { - // Parse client version - clientVersion, err := version.ParseVersion(globals.SEMVER) - if err != nil { - return err - } - - // Parse the permissioning version - regVersion, err := version.ParseVersion(cl.GetRegistrationVersion()) - if err != nil { - return err - } - - ok := version.IsCompatible(regVersion, clientVersion) - if !ok { - return errors.Errorf("Couldn't connect to gateways: Versions"+ - " incompatible; Local version: %v; remote version: %v", globals.SEMVER, - cl.GetRegistrationVersion()) - } - } else { - globals.Log.WARN.Printf("Not checking version from " + - "registration server, because it's not populated. Do you have " + - "access to the registration server?") - } - - return nil - -} - -// Connects to gateways using tls filepaths to create credential information -// for connection establishment -func addGatewayHosts(rm *network.ReceptionManager, definition *ndf.NetworkDefinition) error { - if len(definition.Gateways) < 1 { - return errors.New("could not connect due to invalid number of nodes") - } - - // connect to all gateways - var errs error = nil - for i, gateway := range definition.Gateways { - gwID, err := id.Unmarshal(definition.Gateways[i].ID) - if err != nil { - err = errors.Errorf("Failed to unmarshal gateway ID %s at index %v: %+v", - definition.Gateways[i].ID, i, err) - if errs != nil { - errs = err - } else { - errs = errors.Wrap(errs, err.Error()) - } - continue - } - err = addHost(rm, gwID, gateway.Address, gateway.TlsCertificate, false, false) - if err != nil { - err = errors.Errorf("Failed to create host for gateway %s at %s: %+v", - gwID.String(), gateway.Address, err) - if errs != nil { - errs = err - } else { - errs = errors.Wrap(errs, err.Error()) - } - } - } - return errs -} - -func addHost(rm *network.ReceptionManager, id *id.ID, address, cert string, disableTimeout, enableAuth bool) error { - var creds []byte - if cert != "" && rm.Tls { - creds = []byte(cert) - } - _, err := rm.Comms.AddHost(id, address, creds, disableTimeout, enableAuth) - if err != nil { - return err - } - return nil -} - -// There's currently no need to keep connected to permissioning constantly, -// so we have functions to connect to and disconnect from it when a connection -// to permissioning is needed -func addPermissioningHost(rm *network.ReceptionManager, definition *ndf.NetworkDefinition) error { - if definition.Registration.Address != "" { - err := addHost(rm, &id.Permissioning, definition.Registration.Address, - definition.Registration.TlsCertificate, false, false) - if err != nil { - return errors.New(fmt.Sprintf( - "Failed connecting to create host for permissioning: %+v", err)) - } - return nil - } else { - globals.Log.DEBUG.Printf("failed to connect to %v silently", definition.Registration.Address) - // Without an NDF, we can't connect to permissioning, but this isn't an - // error per se, because we should be phasing out permissioning at some - // point - return ErrNoPermissioning - } -} diff --git a/api/mockserver.go b/api/mockserver.go deleted file mode 100644 index b03fbb2ad..000000000 --- a/api/mockserver.go +++ /dev/null @@ -1,407 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -// This sets up a dummy/mock server instance for testing purposes -package api - -import ( - "encoding/json" - "fmt" - "github.com/pkg/errors" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/network/keyExchange" - "gitlab.com/elixxir/client/parse" - pb "gitlab.com/elixxir/comms/mixmessages" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/e2e" - "gitlab.com/elixxir/crypto/large" - "gitlab.com/elixxir/primitives/format" - "gitlab.com/xx_network/comms/connect" - "gitlab.com/xx_network/comms/messages" - "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/ndf" - "sync" - "time" -) - -var def *ndf.NetworkDefinition - -const InvalidClientVersion = "1.1.0" -const BatchSize = 10 - -// ---------------------------------------- MOCK MESSAGE -------------------------------------------------- - -// APIMessage are an implementation of the interface in bindings and API -// easy to use from Go -type APIMessage struct { - Payload []byte - SenderID *id.ID - RecipientID *id.ID -} - -func (m APIMessage) GetSender() *id.ID { - return m.SenderID -} - -func (m APIMessage) GetRecipient() *id.ID { - return m.RecipientID -} - -func (m APIMessage) GetPayload() []byte { - return m.Payload -} - -func (m APIMessage) GetMessageType() int32 { - return int32(keyExchange.Type_NO_TYPE) -} - -func (m APIMessage) GetCryptoType() parse.CryptoType { - return parse.None -} - -func (m APIMessage) GetTimestamp() time.Time { - return time.Now() -} - -func (m APIMessage) Pack() []byte { - // assuming that the type is independently populated. - // that's probably a bad idea - // there's no good reason to have the same method body for each of these - // two methods! - return m.Payload -} - -// -------------------------------------- MOCK DUMMY STORAGE --------------------------------------- - -// Mock dummy storage interface for testing. -type DummyStorage struct { - LocationA string - LocationB string - StoreA []byte - StoreB []byte - mutex sync.Mutex -} - -func (d *DummyStorage) IsEmpty() bool { - return d.StoreA == nil && d.StoreB == nil -} - -func (d *DummyStorage) SetLocation(lA, lB string) error { - d.LocationA = lA - d.LocationB = lB - return nil -} - -func (d *DummyStorage) GetLocation() (string, string) { - fmt.Printf("LOCATION LOCATION LOCATION: %s,%s\n\n", d.LocationA, - d.LocationB) - return d.LocationA, d.LocationB -} - -func (d *DummyStorage) SaveA(b []byte) error { - d.StoreA = make([]byte, len(b)) - copy(d.StoreA, b) - return nil -} - -func (d *DummyStorage) SaveB(b []byte) error { - d.StoreB = make([]byte, len(b)) - copy(d.StoreB, b) - return nil -} - -func (d *DummyStorage) Lock() { - d.mutex.Lock() -} - -func (d *DummyStorage) Unlock() { - d.mutex.Unlock() -} - -func (d *DummyStorage) LoadA() []byte { - return d.StoreA -} - -func (d *DummyStorage) LoadB() []byte { - return d.StoreB -} - -type DummyReceiver struct { - LastMessage APIMessage -} - -func (d *DummyReceiver) Receive(message APIMessage) { - d.LastMessage = message -} - -// --------------------------------- MOCK REGISTRATION SERVER ------------------------------------------------ -// Blank struct implementing Registration Handler interface for testing purposes (Passing to StartServer) -type MockRegistration struct { - //LastReceivedMessage pb.CmixMessage -} - -func (s *MockRegistration) RegisterNode(ID *id.ID, - NodeTLSCert, GatewayTLSCert, RegistrationCode, Addr, Addr2 string) error { - return nil -} - -func (s *MockRegistration) PollNdf(clientNdfHash []byte, auth *connect.Auth) ([]byte, error) { - - ndfData := def - ndfJson, _ := json.Marshal(ndfData) - return ndfJson, nil -} - -func (s *MockRegistration) Poll(*pb.PermissioningPoll, *connect.Auth, string) (*pb.PermissionPollResponse, error) { - return nil, nil -} - -// Registers a user and returns a signed public key -func (s *MockRegistration) RegisterUser(registrationCode, - key string) (hash []byte, err error) { - return nil, nil -} - -func (s *MockRegistration) GetCurrentClientVersion() (version string, err error) { - return globals.SEMVER, nil -} - -func (i *MockRegistration) CheckRegistration(msg *pb.RegisteredNodeCheck) (*pb.RegisteredNodeConfirmation, error) { - return nil, nil -} - -//registration handler for getUpdatedNDF error case -type MockPermNdfErrorCase struct { -} - -func (s *MockPermNdfErrorCase) RegisterNode(ID []byte, - NodeTLSCert, GatewayTLSCert, RegistrationCode, Addr, Addr2 string) error { - return nil -} - -func (s *MockPermNdfErrorCase) PollNdf(clientNdfHash []byte) ([]byte, error) { - errMsg := fmt.Sprintf("Permissioning server does not have an ndf to give to client") - return nil, errors.New(errMsg) -} - -func (s *MockPermNdfErrorCase) RegisterUser(registrationCode, - key string) (hash []byte, err error) { - return nil, nil -} - -func (s *MockPermNdfErrorCase) GetCurrentClientVersion() (version string, err error) { - return globals.SEMVER, nil -} - -//Mock Permissioning handler for error cases involving check version -type MockpermCheckversionErrorcase struct { -} - -func (s *MockpermCheckversionErrorcase) RegisterNode(ID []byte, - NodeTLSCert, GatewayTLSCert, RegistrationCode, Addr, Addr2 string) error { - return nil -} -func (s *MockpermCheckversionErrorcase) PollNdf(clientNdfHash []byte) ([]byte, error) { - ndfData := def - ndfJson, _ := json.Marshal(ndfData) - return ndfJson, nil -} -func (s *MockpermCheckversionErrorcase) RegisterUser(registrationCode, - key string) (hash []byte, err error) { - return nil, nil -} -func (s *MockpermCheckversionErrorcase) GetCurrentClientVersion() (version string, err error) { - return globals.SEMVER, errors.New("Could not get version") -} - -//Registration handler for handling a bad client version (aka client is not up to date) -type MockPermCheckversionBadversion struct { -} - -func (s *MockPermCheckversionBadversion) RegisterNode(ID []byte, - NodeTLSCert, GatewayTLSCert, RegistrationCode, Addr, Addr2 string) error { - return nil -} - -func (s *MockPermCheckversionBadversion) GetUpdatedNDF(clientNdfHash []byte) ([]byte, error) { - ndfData := buildMockNDF() - ndfJson, _ := json.Marshal(ndfData) - return ndfJson, nil -} - -func (s *MockPermCheckversionBadversion) RegisterUser(registrationCode, - key string) (hash []byte, err error) { - return nil, nil -} - -func (s *MockPermCheckversionBadversion) GetCurrentClientVersion() (version string, err error) { - return InvalidClientVersion, nil -} - -func buildMockNDF() ndf.NetworkDefinition { - - ExampleJSON := `{"Timestamp":"2019-06-04T20:48:48-07:00","gateways":[{"Address":"0.0.0.0:7900","Tls_certificate":"-----BEGIN CERTIFICATE-----\nMIIDgTCCAmmgAwIBAgIJAKLdZ8UigIAeMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjEaMBgGA1UEAwwRZ2F0ZXdheSou\nY21peC5yaXAwHhcNMTkwMzA1MTgzNTU0WhcNMjkwMzAyMTgzNTU0WjBvMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ2xhcmVtb250\nMRswGQYDVQQKDBJQcml2YXRlZ3JpdHkgQ29ycC4xGjAYBgNVBAMMEWdhdGV3YXkq\nLmNtaXgucmlwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9+AaxwDP\nxHbhLmn4HoZu0oUM48Qufc6T5XEZTrpMrqJAouXk+61Jc0EFH96/sbj7VyvnXPRo\ngIENbk2Y84BkB9SkRMIXya/gh9dOEDSgnvj/yg24l3bdKFqBMKiFg00PYB30fU+A\nbe3OI/le0I+v++RwH2AV0BMq+T6PcAGjCC1Q1ZB0wP9/VqNMWq5lbK9wD46IQiSi\n+SgIQeE7HoiAZXrGO0Y7l9P3+VRoXjRQbqfn3ETNL9ZvQuarwAYC9Ix5MxUrS5ag\nOmfjc8bfkpYDFAXRXmdKNISJmtCebX2kDrpP8Bdasx7Fzsx59cEUHCl2aJOWXc7R\n5m3juOVL1HUxjQIDAQABoyAwHjAcBgNVHREEFTATghFnYXRld2F5Ki5jbWl4LnJp\ncDANBgkqhkiG9w0BAQUFAAOCAQEAMu3xoc2LW2UExAAIYYWEETggLNrlGonxteSu\njuJjOR+ik5SVLn0lEu22+z+FCA7gSk9FkWu+v9qnfOfm2Am+WKYWv3dJ5RypW/hD\nNXkOYxVJNYFxeShnHohNqq4eDKpdqSxEcuErFXJdLbZP1uNs4WIOKnThgzhkpuy7\ntZRosvOF1X5uL1frVJzHN5jASEDAa7hJNmQ24kh+ds/Ge39fGD8pK31CWhnIXeDo\nvKD7wivi/gSOBtcRWWLvU8SizZkS3hgTw0lSOf5geuzvasCEYlqrKFssj6cTzbCB\nxy3ra3WazRTNTW4TmkHlCUC9I3oWTTxw5iQxF/I2kQQnwR7L3w==\n-----END CERTIFICATE-----"},{"Address":"0.0.0.0:7901","Tls_certificate":"-----BEGIN CERTIFICATE-----\nMIIDgTCCAmmgAwIBAgIJAKLdZ8UigIAeMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjEaMBgGA1UEAwwRZ2F0ZXdheSou\nY21peC5yaXAwHhcNMTkwMzA1MTgzNTU0WhcNMjkwMzAyMTgzNTU0WjBvMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ2xhcmVtb250\nMRswGQYDVQQKDBJQcml2YXRlZ3JpdHkgQ29ycC4xGjAYBgNVBAMMEWdhdGV3YXkq\nLmNtaXgucmlwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9+AaxwDP\nxHbhLmn4HoZu0oUM48Qufc6T5XEZTrpMrqJAouXk+61Jc0EFH96/sbj7VyvnXPRo\ngIENbk2Y84BkB9SkRMIXya/gh9dOEDSgnvj/yg24l3bdKFqBMKiFg00PYB30fU+A\nbe3OI/le0I+v++RwH2AV0BMq+T6PcAGjCC1Q1ZB0wP9/VqNMWq5lbK9wD46IQiSi\n+SgIQeE7HoiAZXrGO0Y7l9P3+VRoXjRQbqfn3ETNL9ZvQuarwAYC9Ix5MxUrS5ag\nOmfjc8bfkpYDFAXRXmdKNISJmtCebX2kDrpP8Bdasx7Fzsx59cEUHCl2aJOWXc7R\n5m3juOVL1HUxjQIDAQABoyAwHjAcBgNVHREEFTATghFnYXRld2F5Ki5jbWl4LnJp\ncDANBgkqhkiG9w0BAQUFAAOCAQEAMu3xoc2LW2UExAAIYYWEETggLNrlGonxteSu\njuJjOR+ik5SVLn0lEu22+z+FCA7gSk9FkWu+v9qnfOfm2Am+WKYWv3dJ5RypW/hD\nNXkOYxVJNYFxeShnHohNqq4eDKpdqSxEcuErFXJdLbZP1uNs4WIOKnThgzhkpuy7\ntZRosvOF1X5uL1frVJzHN5jASEDAa7hJNmQ24kh+ds/Ge39fGD8pK31CWhnIXeDo\nvKD7wivi/gSOBtcRWWLvU8SizZkS3hgTw0lSOf5geuzvasCEYlqrKFssj6cTzbCB\nxy3ra3WazRTNTW4TmkHlCUC9I3oWTTxw5iQxF/I2kQQnwR7L3w==\n-----END CERTIFICATE-----"},{"Address":"0.0.0.0:7902","Tls_certificate":"-----BEGIN CERTIFICATE-----\nMIIDgTCCAmmgAwIBAgIJAKLdZ8UigIAeMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQx\nGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjEaMBgGA1UEAwwRZ2F0ZXdheSou\nY21peC5yaXAwHhcNMTkwMzA1MTgzNTU0WhcNMjkwMzAyMTgzNTU0WjBvMQswCQYD\nVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ2xhcmVtb250\nMRswGQYDVQQKDBJQcml2YXRlZ3JpdHkgQ29ycC4xGjAYBgNVBAMMEWdhdGV3YXkq\nLmNtaXgucmlwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9+AaxwDP\nxHbhLmn4HoZu0oUM48Qufc6T5XEZTrpMrqJAouXk+61Jc0EFH96/sbj7VyvnXPRo\ngIENbk2Y84BkB9SkRMIXya/gh9dOEDSgnvj/yg24l3bdKFqBMKiFg00PYB30fU+A\nbe3OI/le0I+v++RwH2AV0BMq+T6PcAGjCC1Q1ZB0wP9/VqNMWq5lbK9wD46IQiSi\n+SgIQeE7HoiAZXrGO0Y7l9P3+VRoXjRQbqfn3ETNL9ZvQuarwAYC9Ix5MxUrS5ag\nOmfjc8bfkpYDFAXRXmdKNISJmtCebX2kDrpP8Bdasx7Fzsx59cEUHCl2aJOWXc7R\n5m3juOVL1HUxjQIDAQABoyAwHjAcBgNVHREEFTATghFnYXRld2F5Ki5jbWl4LnJp\ncDANBgkqhkiG9w0BAQUFAAOCAQEAMu3xoc2LW2UExAAIYYWEETggLNrlGonxteSu\njuJjOR+ik5SVLn0lEu22+z+FCA7gSk9FkWu+v9qnfOfm2Am+WKYWv3dJ5RypW/hD\nNXkOYxVJNYFxeShnHohNqq4eDKpdqSxEcuErFXJdLbZP1uNs4WIOKnThgzhkpuy7\ntZRosvOF1X5uL1frVJzHN5jASEDAa7hJNmQ24kh+ds/Ge39fGD8pK31CWhnIXeDo\nvKD7wivi/gSOBtcRWWLvU8SizZkS3hgTw0lSOf5geuzvasCEYlqrKFssj6cTzbCB\nxy3ra3WazRTNTW4TmkHlCUC9I3oWTTxw5iQxF/I2kQQnwR7L3w==\n-----END CERTIFICATE-----"}],"nodes":[{"Id":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"Dsa_public_key":"-----BEGIN PUBLIC KEY-----\nMIIDNDCCAiwCggEBAJ22+1lRtmu2/h4UDx0s5VAjdBYf1lON8WSCGGQvC1xIyPek\nGq36GHMkuHZ0+hgisA8ez4E2lD18VXVyZOWhpE/+AS6ZNuAMHT6TELAcfReYBdMF\niyqfS7b5cWv+YRfGtbPMTZvjQRBK1KgK1slOAF9LmT4U8JHrUXQ78zBQw43iNVZ+\nGzTD1qXAzqoaDzaCE8PRmEPQtLCdy5/HLTnI3kHxvxTUu0Vjyig3FiHK0zJLai05\nIUW+v6x0iAUjb1yi/pK4cc2PnDbTKStVCcqMqneirfx7/XfdpvcRJadFb+oVPkMy\nVqImHGoG7TaTeX55lfrVqrvPvj7aJ0HjdUBK4lsCIQDywxGTdM52yTVpkLRlN0oX\n8j+e01CJvZafYcbd6ZmMHwKCAQBcf/awb48UP+gohDNJPkdpxNmIrOW+JaDiSAln\nBxbGE9ewzuaTL4+qfETSyyRSPaU/vk9uw1lYktGqWMQyigbEahVmLn6qcDod7Pi7\nstBdvi65VsFCozhmHRBGHA0TVHIIUFfzSUMJ/6c8YR94syrbtXQMNhyfNb6QmX2y\nAU4u9apheC9Sq+uL1kMsTdCXvFQjsoXa+2DcNk6BYfSio1rKOhCxxNIDzHakcKM6\n/cvdkpWYWavYtW4XJSUteOrGbnG6muPx3SSHGZh0OTzU2DIYaABlR2Dh40wJ5NFV\nF5+ewNxEc/mWvc5u7Ryr7YtvEW962c9QXfD5mONKsnUUsP/nAoIBAERwUmUlL9YP\nq6MSn+bUr6qNZPsVYoQAo8nTjZWiuSjJa2XWnh7sftnISWkwkiiRxo7qfq3sAiD5\nB8+tM6kONeICBXukldXJerxoVBspYa+RiPuDWy2pwGRDBpfty3QqJOpu5g2ThYFJ\nD5Xu0yCuX8ZJRj33nliI8dQgKdQQva6p2VuXzyRT8LwXMfRwLuSB6Schc9mF8C\nkWCb4m0ujlEKe1xKoKt2zG9b1o7XyaVhxguSUAuEznifMzsEUfuONJOy+XoQELex\nF0wvLzNzABcyxkM3lx52uG41mKgJiV6Z0ZyuBRvt+V3VL/38tPn9lsTaFi8N6/IH\nRyy0bWP5s44=\n-----END PUBLIC KEY-----\n","Address":"0.0.0.0:5900","Tls_certificate":"-----BEGIN CERTIFICATE-----MIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDAeFwOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDhDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfsWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSEtJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uAm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9bJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEAAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEAneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIfU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2qvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4cyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1RtgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E56m52PyzMNV+2N21IPppKwA==-----END CERTIFICATE-----"},{"Id":[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"Dsa_public_key":"-----BEGIN PUBLIC KEY-----\nMIIDNDCCAiwCggEBAJ22+1lRtmu2/h4UDx0s5VAjdBYf1lON8WSCGGQvC1xIyPek\nGq36GHMkuHZ0+hgisA8ez4E2lD18VXVyZOWhpE/+AS6ZNuAMHT6TELAcfReYBdMF\niyqfS7b5cWv+YRfGtbPMTZvjQRBK1KgK1slOAF9LmT4U8JHrUXQ78zBQw43iNVZ+\nGzTD1qXAzqoaDzaCE8PRmEPQtLCdy5/HLTnI3kHxvxTUu0Vjyig3FiHK0zJLai05\nIUW+v6x0iAUjb1yi/pK4cc2PnDbTKStVCcqMqneirfx7/XfdpvcRJadFb+oVPkMy\nVqImHGoG7TaTeX55lfrVqrvPvj7aJ0HjdUBK4lsCIQDywxGTdM52yTVpkLRlN0oX\n8j+e01CJvZafYcbd6ZmMHwKCAQBcf/awb48UP+gohDNJPkdpxNmIrOW+JaDiSAln\nBxbGE9ewzuaTL4+qfETSyyRSPaU/vk9uw1lYktGqWMQyigbEahVmLn6qcDod7Pi7\nstBdvi65VsFCozhmHRBGHA0TVHIIUFfzSUMJ/6c8YR94syrbtXQMNhyfNb6QmX2y\nAU4u9apheC9Sq+uL1kMsTdCXvFQjsoXa+2DcNk6BYfSio1rKOhCxxNIDzHakcKM6\n/cvdkpWYWavYtW4XJSUteOrGbnG6muPx3SSHGZh0OTzU2DIYaABlR2Dh40wJ5NFV\nF5+ewNxEc/mWvc5u7Ryr7YtvEW962c9QXfD5mONKsnUUsP/nAoIBAFbADcqA8KQh\nxzgylW6VS1dYYelO5DjPZVVSjfdcbj1twu4ZHDNZLOexpv4nGY8xS6vesELXcVOR\n/CHXgh/3byBZYm0zkrBi/FsJJ3nP2uZ1+QCRldI2KzqcLOWH/CAYj8koork9k1Dp\nFq7rMSDgw4pktqvFj9Eev8dSZuRnoCfZbt/6vxi1r30AYAjDYOwcysqcVyUa1tPa\nLEh3JksttXUCd5cvfqatWedTs5Vxo7ICW1toGBHABYvSJkwK0YFfi5RLw+Oda1sA\njJ+aLcIxQjrpoRC2alXCdwmZXVb+O6zluQctw6LJjt4J704ueSvR4VNNhr0uLYGW\nk7e+WoQCS98=\n-----END PUBLIC KEY-----\n","Address":"0.0.0.0:5901","Tls_certificate":"-----BEGIN CERTIFICATE-----MIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDAeFwOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDhDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfsWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSEtJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uAm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9bJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEAAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEAneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIfU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2qvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4cyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1RtgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E56m52PyzMNV+2N21IPppKwA==-----END CERTIFICATE-----"},{"Id":[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"Dsa_public_key":"-----BEGIN PUBLIC KEY-----\nMIIDNTCCAiwCggEBAJ22+1lRtmu2/h4UDx0s5VAjdBYf1lON8WSCGGQvC1xIyPek\nGq36GHMkuHZ0+hgisA8ez4E2lD18VXVyZOWhpE/+AS6ZNuAMHT6TELAcfReYBdMF\niyqfS7b5cWv+YRfGtbPMTZvjQRBK1KgK1slOAF9LmT4U8JHrUXQ78zBQw43iNVZ+\nGzTD1qXAzqoaDzaCE8PRmEPQtLCdy5/HLTnI3kHxvxTUu0Vjyig3FiHK0zJLai05\nIUW+v6x0iAUjb1yi/pK4cc2PnDbTKStVCcqMqneirfx7/XfdpvcRJadFb+oVPkMy\nVqImHGoG7TaTeX55lfrVqrvPvj7aJ0HjdUBK4lsCIQDywxGTdM52yTVpkLRlN0oX\n8j+e01CJvZafYcbd6ZmMHwKCAQBcf/awb48UP+gohDNJPkdpxNmIrOW+JaDiSAln\nBxbGE9ewzuaTL4+qfETSyyRSPaU/vk9uw1lYktGqWMQyigbEahVmLn6qcDod7Pi7\nstBdvi65VsFCozhmHRBGHA0TVHIIUFfzSUMJ/6c8YR94syrbtXQMNhyfNb6QmX2y\nAU4u9apheC9Sq+uL1kMsTdCXvFQjsoXa+2DcNk6BYfSio1rKOhCxxNIDzHakcKM6\n/cvdkpWYWavYtW4XJSUteOrGbnG6muPx3SSHGZh0OTzU2DIYaABlR2Dh40wJ5NFV\nF5+ewNxEc/mWvc5u7Ryr7YtvEW962c9QXfD5mONKsnUUsP/nAoIBAQCN19tTnkS3\nitBQXXR/h8OKl+rliFBLgO6h6GvZL4yQDZFtBAOmkrs3wLoDroJRGCeqz/IUb+JF\njslEr/mpm2kcmK77hr535dq7HsWz1fFl9YyGTaOH055FLSV9QEPAV9j3zWADdQ1v\nuSQll+QfWi6lIibWV4HNQ2ywRFoOY8OBLCJB90UXLeJpaPanpqiM8hjda2VGRDbi\nIixEE2lCOWITydiz2DmvXrLhVGF49+g5MDwbWO65dmasCe//Ff6Z4bJ6n049xv\nVtac8nX6FO3eBsV5d+rG6HZXSG3brCKRCSKYCTX1IkTSiutYxYqvwaluoCjOakh0\nKkqvQ8IeVZ+B\n-----END PUBLIC KEY-----\n","Address":"0.0.0.0:5902","Tls_certificate":"-----BEGIN CERTIFICATE-----MIIDbDCCAlSgAwIBAgIJAOUNtZneIYECMA0GCSqGSIb3DQEBBQUAMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDAeFwOTAzMDUxODM1NDNaFw0yOTAzMDIxODM1NDNaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlDbGFyZW1vbnQxGzAZBgNVBAoMElByaXZhdGVncml0eSBDb3JwLjETMBEGA1UEAwwKKi5jbWl4LnJpcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPP0WyVkfZA/CEd2DgKpcudn0oDhDwsjmx8LBDWsUgQzyLrFiVigfUmUefknUH3dTJjmiJtGqLsayCnWdqWLHPJYvFfsWYW0IGF93UG/4N5UAWO4okC3CYgKSi4ekpfw2zgZq0gmbzTnXcHF9gfmQ7jJUKSEtJPSNzXq+PZeJTC9zJAb4Lj8QzH18rDM8DaL2y1ns0Y2Hu0edBFn/OqavBJKb/uAm3AEjqeOhC7EQUjVamWlTBPt40+B/6aFJX5BYm2JFkRsGBIyBVL46MvC02MgzTT9bJIJfwqmBaTruwemNgzGu7Jk03hqqS1TUEvSI6/x8bVoba3orcKkf9HsDjECAwEAAaMZMBcwFQYDVR0RBA4wDIIKKi5jbWl4LnJpcDANBgkqhkiG9w0BAQUFAAOCAQEAneUocN4AbcQAC1+b3To8u5UGdaGxhcGyZBlAoenRVdjXK3lTjsMdMWb4QctgNfIfU/zuUn2mxTmF/ekP0gCCgtleZr9+DYKU5hlXk8K10uKxGD6EvoiXZzlfeUuotgp2qvI3ysOm/hvCfyEkqhfHtbxjV7j7v7eQFPbvNaXbLa0yr4C4vMK/Z09Ui9JrZ/Z4cyIkxfC6/rOqAirSdIp09EGiw7GM8guHyggE4IiZrDslT8V3xIl985cbCxSxeW1RtgH4rdEXuVe9+31oJhmXOE9ux2jCop9tEJMgWg7HStrJ5plPbb+HmjoX3nBO04E56m52PyzMNV+2N21IPppKwA==-----END CERTIFICATE-----"}],"registration":{"Address":"0.0.0.0:5000","Tls_certificate":""},"udb":{"Id":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3],"Dsa_public_key":"-----BEGIN PUBLIC KEY-----\nMIIDNDCCAiwCggEBAJ22+1lRtmu2/h4UDx0s5VAjdBYf1lON8WSCGGQvC1xIyPek\nGq36GHMkuHZ0+hgisA8ez4E2lD18VXVyZOWhpE/+AS6ZNuAMHT6TELAcfReYBdMF\niyqfS7b5cWv+YRfGtbPMTZvjQRBK1KgK1slOAF9LmT4U8JHrUXQ78zBQw43iNVZ+\nGzTD1qXAzqoaDzaCE8PRmEPQtLCdy5/HLTnI3kHxvxTUu0Vjyig3FiHK0zJLai05\nIUW+v6x0iAUjb1yi/pK4cc2PnDbTKStVCcqMqneirfx7/XfdpvcRJadFb+oVPkMy\nVqImHGoG7TaTeX55lfrVqrvPvj7aJ0HjdUBK4lsCIQDywxGTdM52yTVpkLRlN0oX\n8j+e01CJvZafYcbd6ZmMHwKCAQBcf/awb48UP+gohDNJPkdpxNmIrOW+JaDiSAln\nBxbGE9ewzuaTL4+qfETSyyRSPaU/vk9uw1lYktGqWMQyigbEahVmLn6qcDod7Pi7\nstBdvi65VsFCozhmHRBGHA0TVHIIUFfzSUMJ/6c8YR94syrbtXQMNhyfNb6QmX2y\nAU4u9apheC9Sq+uL1kMsTdCXvFQjsoXa+2DcNk6BYfSio1rKOhCxxNIDzHakcKM6\n/cvdkpWYWavYtW4XJSUteOrGbnG6muPx3SSHGZh0OTzU2DIYaABlR2Dh40wJ5NFV\nF5+ewNxEc/mWvc5u7Ryr7YtvEW962c9QXfD5mONKsnUUsP/nAoIBACvR2lUslz3D\nB/MUo0rHVIHVkhVJCxNjtgTOYgJ9ckArSXQbYzr/fcigcNGjUO2LbK5NFp9GK43C\nrLxMUnJ9nkyIVPaWvquJFZItjcDK3NiNGyD4XyM0eRj4dYeSxQM48hvFbmtbjlXn\n9SQTnGIlr1XnTI4RVHZSQOL6kFJIaLw6wYrQ4w08Ng+p45brp5ercAHnLiftNUWP\nqROhQkdSEpS9LEwfotUSY1jP2AhQfaIMxaeXsZuTU1IYvdhMFRL3DR0r5Ww2Upf8\ng0Ace0mtnsUQ2OG+7MTh2jYIEWRjvuoe3RCz603ujW6g7BfQ1H7f4YFwc5xOOJ3u\nr4dj49dCCjc=\n-----END PUBLIC KEY-----\n"},"E2e":{"Prime":"E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AEDF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF453B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE92096EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F278DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873847AEF49F66E43873","Small_prime":"02","Generator":"02"},"CMIX":{"Prime":"9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B","Small_prime":"F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F","Generator":"5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7"}}` - retNDF, _, _ := ndf.DecodeNDF(ExampleJSON) - /* - var grp ndf.Group - grp.Prime = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + - "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + - "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + - "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + - "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + - "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + - "15728E5A8AACAA68FFFFFFFFFFFFFFFF" - grp.Generator = "2" - grp.SmallPrime = "2" - retNDF := ndf.NetworkDefinition{Timestamp: time.Now(), Registration: reg, Nodes: Nodes, CMIX: grp, E2E: grp}*/ - return *retNDF -} - -// ------------------------------------ MOCK GATEWAYS ---------------------------------------------------------------- - -// Blank struct implementing ServerHandler interface for testing purposes (Passing to StartServer) -type GatewayHandler struct { - LastReceivedMessage pb.Slot -} - -func (m *GatewayHandler) PollForNotifications(auth *connect.Auth) ([]*id.ID, error) { - - return nil, nil -} - -func (m *GatewayHandler) Poll(*pb.GatewayPoll) (*pb.GatewayPollResponse, error) { - return nil, nil -} - -// Returns message contents for MessageID, or a null/randomized message -// if that ID does not exist of the same size as a regular message -func (m *GatewayHandler) GetMessage(userId *id.ID, - msgId, ipaddr string) (*pb.Slot, error) { - return &pb.Slot{}, nil -} - -// Return any MessageIDs in the globals for this User -func (m *GatewayHandler) CheckMessages(userId *id.ID, - messageID, ipAddress string) ([]string, error) { - return make([]string, 0), nil -} - -// PutMessage adds a message to the outgoing queue and -// calls SendBatch when it's size is the batch size -func (m *GatewayHandler) PutMessage(msg *pb.GatewaySlot, ipaddr string) (*pb.GatewaySlotResponse, error) { - m.LastReceivedMessage = *msg.Message - return &pb.GatewaySlotResponse{ - Accepted: true, - }, nil -} - -func (m *GatewayHandler) ConfirmNonce(message *pb.RequestRegistrationConfirmation, ipaddr string) (*pb.RegistrationConfirmation, error) { - regConfirmation := &pb.RegistrationConfirmation{ - ClientSignedByServer: &messages.RSASignature{}, - } - - return regConfirmation, nil -} - -// Pass-through for Registration Nonce Communication -func (m *GatewayHandler) RequestNonce(message *pb.NonceRequest, ipaddr string) (*pb.Nonce, error) { - dh := getDHPubKey().Bytes() - return &pb.Nonce{ - DHPubKey: dh, - }, nil -} - -//Blank struct that has an error path f -type GatewayHandlerMultipleMessages struct { - LastReceivedMessage []pb.Slot -} - -func (m *GatewayHandlerMultipleMessages) GetMessage(userId *id.ID, - msgId, ipaddr string) (*pb.Slot, error) { - msg := []byte("Hello") - payload, err := e2e.Pad(msg, format.PayloadLen) - if err != nil { - fmt.Println("hello!") - } - return &pb.Slot{ - PayloadA: payload, - PayloadB: payload, - }, nil -} - -func (m *GatewayHandlerMultipleMessages) PollForNotifications(auth *connect.Auth) ([]*id.ID, error) { - return nil, nil -} - -func (s *GatewayHandlerMultipleMessages) Poll(*pb.GatewayPoll) (*pb.GatewayPollResponse, error) { - return nil, nil -} - -// Return any MessageIDs in the globals for this User -func (m *GatewayHandlerMultipleMessages) CheckMessages(userId *id.ID, - messageID, ipaddr string) ([]string, error) { - msgs := []string{"a", "b", "c", "d", "e", "f", "g"} - return msgs, nil -} - -// PutMessage adds a message to the outgoing queue and -// calls SendBatch when it's size is the batch size -func (m *GatewayHandlerMultipleMessages) PutMessage(msg *pb.GatewaySlot, ipaddr string) (*pb.GatewaySlotResponse, error) { - for i := 0; i < BatchSize; i++ { - msg.Message.Index = uint32(i) - m.LastReceivedMessage = append(m.LastReceivedMessage, *msg.Message) - } - return &pb.GatewaySlotResponse{}, nil -} - -func (m *GatewayHandlerMultipleMessages) ConfirmNonce(message *pb.RequestRegistrationConfirmation, ipaddr string) (*pb.RegistrationConfirmation, error) { - return nil, nil -} - -// Pass-through for Registration Nonce Communication -func (m *GatewayHandlerMultipleMessages) RequestNonce(message *pb.NonceRequest, ipaddr string) (*pb.Nonce, error) { - return nil, nil -} - -func getDHPubKey() *cyclic.Int { - cmixGrp := cyclic.NewGroup( - large.NewIntFromString("9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48"+ - "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F"+ - "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5"+ - "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2"+ - "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41"+ - "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE"+ - "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15"+ - "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", 16), - large.NewIntFromString("5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613"+ - "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4"+ - "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472"+ - "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5"+ - "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA"+ - "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71"+ - "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0"+ - "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", 16)) - - dh := cmixGrp.RandomCoprime(cmixGrp.NewMaxInt()) - return cmixGrp.ExpG(dh, cmixGrp.NewMaxInt()) -} - -// --------------------------- MOCK NOTIFICATION BOT ------------------------------------------------------- - -type MockNotificationHandler struct { -} - -func (nb *MockNotificationHandler) RegisterForNotifications(clientToken []byte, auth *connect.Auth) error { - return nil -} - -func (nb *MockNotificationHandler) UnregisterForNotifications(auth *connect.Auth) error { - return nil -} diff --git a/api/mockserver_test.go b/api/mockserver_test.go deleted file mode 100644 index b35ad3efc..000000000 --- a/api/mockserver_test.go +++ /dev/null @@ -1,581 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -// This sets up a dummy/mock server instance for testing purposes -package api - -import ( - "fmt" - jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/network" - "gitlab.com/elixxir/client/storage" - user2 "gitlab.com/elixxir/client/storage/user" - "gitlab.com/elixxir/client/user" - "gitlab.com/elixxir/client/userRegistry" - "gitlab.com/elixxir/comms/gateway" - pb "gitlab.com/elixxir/comms/mixmessages" - "gitlab.com/elixxir/comms/notificationBot" - "gitlab.com/elixxir/comms/registration" - "gitlab.com/xx_network/comms/connect" - "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/ndf" - "os" - "strings" - "testing" - "time" -) - -const NumNodes = 3 -const NumGWs = NumNodes -const RegPort = 5000 -const GWErrorPort = 7800 -const GWsStartPort = 7900 -const PermErrorServerPort = 4000 -const NotificationBotPort = 6500 -const NotificationErrorPort = 6600 - -var RegHandler = MockRegistration{} -var RegComms *registration.Comms -var NDFErrorReg = MockPermNdfErrorCase{} -var ErrorDef *ndf.NetworkDefinition - -const ValidRegCode = "WTROXJ33" -const InvalidRegCode = "INVALID_REG_CODE_" - -var RegGWHandlers = [NumGWs]*GatewayHandler{ - {LastReceivedMessage: pb.Slot{}}, - {LastReceivedMessage: pb.Slot{}}, - {LastReceivedMessage: pb.Slot{}}, -} -var GWComms [NumGWs]*gateway.Comms -var GWErrComms [NumGWs]*gateway.Comms - -var NotificationBotHandler = MockNotificationHandler{} -var NotificationBotComms *notificationBot.Comms - -// Setups general testing params and calls test wrapper -func TestMain(m *testing.M) { - - // Set logging params - jww.SetLogThreshold(jww.LevelTrace) - jww.SetStdoutThreshold(jww.LevelTrace) - os.Exit(testMainWrapper(m)) -} - -//Happy path: test message receiver stating up -func TestClient_StartMessageReceiver_MultipleMessages(t *testing.T) { - // Initialize client with dummy storage - testDef := getNDF() - for i := 0; i < NumNodes; i++ { - gwID := id.NewIdFromString("testGateway", id.Gateway, t) - gw := ndf.Gateway{ - Address: string(fmtAddress(GWErrorPort + i)), - ID: gwID.Marshal(), - } - testDef.Gateways = append(testDef.Gateways, gw) - GWErrComms[i] = gateway.StartGateway(gwID, gw.Address, - &GatewayHandlerMultipleMessages{}, nil, nil) - - } - - testDef.Nodes = def.Nodes - locA := ".ekv-messagereceiver-multiple/a" - storage := DummyStorage{LocationA: locA, StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, ".ekv-messagereceiver-multiple/a", "", testDef) - if err != nil { - t.Errorf("Failed to initialize dummy client: %s", err.Error()) - } - - // InitNetwork to gateways and reg server - err = client.InitNetwork() - - if err != nil { - t.Errorf("Client failed of connect: %+v", err) - } - - err = client.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - client.sessionV2.SetRegState(user.KeyGenComplete) - - // Register with a valid registration code - _, err = client.RegisterWithPermissioning(true, ValidRegCode) - - if err != nil { - t.Errorf("Register failed: %s", err.Error()) - } - - err = client.RegisterWithNodes() - if err != nil && !strings.Contains(err.Error(), "No registration attempted, registration server not known") { - t.Error(err) - } - - err = client.session.StoreSession() - if err != nil { - t.Errorf(err.Error()) - } - - // Login to gateway - _, err = client.Login("password") - - if err != nil { - t.Errorf("Login failed: %s", err.Error()) - } - - cb := func(err error) { - t.Log(err) - } - - err = client.StartMessageReceiver(cb) - if err != nil { - t.Errorf("%+v", err) - } - - time.Sleep(3 * time.Second) - for _, gw := range GWErrComms { - gw.DisconnectAll() - } - -} - -func TestRegister_ValidPrecannedRegCodeReturnsZeroID(t *testing.T) { - // Initialize client with dummy storage - storage := DummyStorage{LocationA: ".ekv-validprecanned0return/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, ".ekv-validprecanned0return/a", "", def) - if err != nil { - t.Errorf("Failed to initialize dummy client: %s", err.Error()) - } - - // InitNetwork to gateways and reg server - err = client.InitNetwork() - - if err != nil { - t.Errorf("Client failed of connect: %+v", err) - } - err = client.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - network.SessionV2.SetRegState(user.KeyGenComplete) - // Register precanned user with all gateways - regRes, err := client.RegisterWithPermissioning(true, ValidRegCode) - - // Verify registration succeeds with valid precanned registration code - if err != nil { - t.Errorf("Registration failed: %s", err.Error()) - } - - if regRes.Cmp(&id.ZeroUser) { - t.Errorf("Invalid registration number received: %v", *regRes) - } - disconnectServers() -} - -// Verify that registering with an invalid registration code will fail -func TestRegister_InvalidPrecannedRegCodeReturnsError(t *testing.T) { - // Initialize client with dummy storage - storage := DummyStorage{LocationA: ".ekv-invalidprecanerr/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, ".ekv-invalidprecanerr/a", "", def) - if err != nil { - t.Errorf("Failed to initialize dummy client: %s", err.Error()) - } - // InitNetwork to gateways and reg server - err = client.InitNetwork() - - if err != nil { - t.Errorf("Client failed of connect: %+v", err) - } - //Generate keys s.t. reg status is prepped for registration - err = client.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - // Register with invalid reg code - uid, err := client.RegisterWithPermissioning(true, InvalidRegCode) - if err == nil { - t.Errorf("Registration worked with invalid registration code! UID: %v", uid) - } - - //Disconnect and shutdown servers - disconnectServers() -} - -//Test that not running generateKeys results in an error. Without running the aforementioned function, -// the registration state should be invalid and it should not run -func TestRegister_InvalidRegState(t *testing.T) { - dstorage := DummyStorage{LocationA: ".ekv-invalidregstate/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&dstorage, ".ekv-invalidregstate/a", "", def) - if err != nil { - t.Errorf("Failed to initialize dummy client: %s", err.Error()) - } - // InitNetwork to gateways and reg server - err = client.InitNetwork() - if err != nil { - t.Errorf("Client failed of connect: %+v", err) - } - //Individually run the helper functions for GenerateKeys, put info into client - privKey, pubKey, err := generateRsaKeys(nil) - if err != nil { - t.Errorf("%+v", err) - } - cmixGrp, e2eGrp := generateGroups(def) - salt, _, usr, err := generateUserInformation(pubKey) - if err != nil { - t.Errorf("%+v", err) - } - e2ePrivKey, e2ePubKey, err := generateE2eKeys(cmixGrp, e2eGrp) - if err != nil { - t.Errorf("%+v", err) - } - cmixPrivKey, cmixPubKey, err := generateCmixKeys(cmixGrp) - - client.session = user.NewSession(nil, "password") - client.sessionV2, _ = storage.Init(".ekv-invalidregstate", "password") - - userData := &user2.UserData{ - ThisUser: usr, - RSAPrivateKey: privKey, - RSAPublicKey: pubKey, - CMIXDHPrivateKey: cmixPrivKey, - CMIXDHPublicKey: cmixPubKey, - E2EDHPrivateKey: e2ePrivKey, - E2EDHPublicKey: e2ePubKey, - CmixGrp: cmixGrp, - E2EGrp: e2eGrp, - Salt: salt, - } - client.sessionV2.CommitUserData(userData) - - // - _, err = client.RegisterWithPermissioning(false, ValidRegCode) - if err == nil { - t.Errorf("Registration worked with invalid registration state!") - } - -} - -func TestRegister_DeletedUserReturnsErr(t *testing.T) { - // Initialize client with dummy storage - storage := DummyStorage{LocationA: ".ekv-deleteusererr/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, ".ekv-deleteusererr/a", "", def) - if err != nil { - t.Errorf("Failed to initialize dummy client: %s", err.Error()) - } - - // InitNetwork to gateways and reg server - err = client.InitNetwork() - - if err != nil { - t.Errorf("Client failed of connect: %+v", err) - } - - // ... - tempUser, _ := userRegistry.Users.GetUser(id.NewIdFromUInt(5, id.User, t)) - userRegistry.Users.DeleteUser(id.NewIdFromUInt(5, id.User, t)) - err = client.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - // Register - _, err = client.RegisterWithPermissioning(true, ValidRegCode) - if err == nil { - t.Errorf("Registration worked with a deleted user: %s", err.Error()) - } - - // ... - userRegistry.Users.UpsertUser(tempUser) - //Disconnect and shutdown servers - disconnectServers() -} - -func TestSend(t *testing.T) { - // Initialize client with dummy storage - storage := DummyStorage{LocationA: ".ekv-sendtest/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, ".ekv-sendtest/a", "", def) - if err != nil { - t.Errorf("Failed to initialize dummy client: %s", err.Error()) - } - - // InitNetwork to gateways and reg server - err = client.InitNetwork() - - if err != nil { - t.Errorf("Client failed of connect: %+v", err) - } - - err = client.GenerateKeys(nil, "password") - network.SessionV2.SetRegState(user.KeyGenComplete) - // Register with a valid registration code - userID, err := client.RegisterWithPermissioning(true, ValidRegCode) - - if err != nil { - t.Errorf("Register failed: %s", err.Error()) - } - - err = client.RegisterWithNodes() - if err != nil { - t.Error(err) - } - - err = client.session.StoreSession() - if err != nil { - t.Errorf(err.Error()) - } - - // Login to gateway - _, err = client.Login("password") - - if err != nil { - t.Errorf("Login failed: %s", err.Error()) - } - - cb := func(err error) { - t.Log(err) - } - - err = client.StartMessageReceiver(cb) - - if err != nil { - t.Errorf("Could not start message reception: %+v", err) - } - - var nodeIds [][]byte - for _, nodes := range client.ndf.Nodes { - nodeIds = append(nodeIds, nodes.ID) - } - - idlist, _ := id.NewIDListFromBytes(nodeIds) - - client.topology = connect.NewCircuit(idlist) - // Test send with invalid sender ID - err = client.Send( - APIMessage{ - SenderID: id.NewIdFromUInt(12, id.User, t), - Payload: []byte("test"), - RecipientID: userID, - }, - ) - - if err != nil { - // TODO: would be nice to catch the sender but we - // don't have the interface/mocking for that. - t.Errorf("error on first message send: %+v", err) - } - - // Test send with valid inputs - err = client.Send(APIMessage{SenderID: userID, Payload: []byte("test"), - RecipientID: client.GetCurrentUser()}) - - if err != nil { - t.Errorf("Error sending message: %v", err) - } - - err = client.Logout(100 * time.Millisecond) - - if err != nil { - t.Errorf("Logout failed: %v", err) - } - disconnectServers() -} - -func TestLogout(t *testing.T) { - // Initialize client with dummy storage - storage := DummyStorage{LocationA: ".ekv-logout/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, ".ekv-logout/a", "", def) - if err != nil { - t.Errorf("Failed to initialize dummy client: %s", err.Error()) - } - // InitNetwork to gateways and reg server - err = client.InitNetwork() - - if err != nil { - t.Errorf("Client failed of connect: %+v", err) - } - - // Logout before logging in should return an error - err = client.Logout(500 * time.Millisecond) - - if err == nil { - t.Errorf("Logout did not throw an error when called on a client that" + - " is not currently logged in.") - } - - err = client.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - network.SessionV2.SetRegState(user.KeyGenComplete) - - // Register with a valid registration code - _, err = client.RegisterWithPermissioning(true, ValidRegCode) - - if err != nil { - t.Errorf("Register failed: %s", err.Error()) - } - - err = client.RegisterWithNodes() - if err != nil { - t.Error(err) - } - - // Login to gateway - _, err = client.Login("password") - - if err != nil { - t.Errorf("Login failed: %s", err.Error()) - } - - cb := func(err error) { - t.Log(err) - } - - err = client.StartMessageReceiver(cb) - - if err != nil { - t.Errorf("Failed to start message reciever: %s", err.Error()) - } - - err = client.Logout(500 * time.Millisecond) - - if err != nil { - t.Errorf("Logout failed: %v", err) - } - - // Logout after logout has been called should return an error - err = client.Logout(500 * time.Millisecond) - - if err == nil { - t.Errorf("Logout did not throw an error when called on a client that" + - " is not currently logged in.") - } - - disconnectServers() -} - -// Handles initialization of mock registration server, -// gateways used for registration and gateway used for session -func testMainWrapper(m *testing.M) int { - - def = getNDF() - ErrorDef = getNDF() - // Start mock registration server and defer its shutdown - def.Registration = ndf.Registration{ - Address: fmtAddress(RegPort), - } - ErrorDef.Registration = ndf.Registration{ - Address: fmtAddress(PermErrorServerPort), - } - - def.Notification = ndf.Notification{ - Address: fmtAddress(NotificationBotPort), - } - - for i := 0; i < NumNodes; i++ { - nId := new(id.ID) - nId[0] = byte(i) - nId.SetType(id.Node) - n := ndf.Node{ - ID: nId[:], - } - def.Nodes = append(def.Nodes, n) - ErrorDef.Nodes = append(ErrorDef.Nodes, n) - } - - startServers(m) - defer testWrapperShutdown() - return m.Run() -} - -func testWrapperShutdown() { - - for _, gw := range GWComms { - gw.Shutdown() - - } - RegComms.Shutdown() - NotificationBotComms.Shutdown() -} - -func fmtAddress(port int) string { return fmt.Sprintf("localhost:%d", port) } - -func getNDF() *ndf.NetworkDefinition { - return &ndf.NetworkDefinition{ - E2E: ndf.Group{ - Prime: "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B" + - "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE" + - "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F" + - "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041" + - "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45" + - "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209" + - "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29" + - "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E" + - "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2" + - "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696" + - "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E" + - "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873" + - "847AEF49F66E43873", - Generator: "2", - }, - CMIX: ndf.Group{ - Prime: "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + - "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + - "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + - "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + - "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + - "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + - "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + - "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", - Generator: "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + - "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + - "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + - "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + - "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + - "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + - "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + - "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", - }, - } -} - -func startServers(m *testing.M) { - regId := new(id.ID) - copy(regId[:], "testServer") - regId.SetType(id.Generic) - RegComms = registration.StartRegistrationServer(regId, def.Registration.Address, &RegHandler, nil, nil) - def.Gateways = make([]ndf.Gateway, 0) - - //Start up gateways - for i, handler := range RegGWHandlers { - - gwID := new(id.ID) - copy(gwID[:], "testGateway") - gwID.SetType(id.Gateway) - gw := ndf.Gateway{ - Address: fmtAddress(GWsStartPort + i), - ID: gwID.Marshal(), - } - - def.Gateways = append(def.Gateways, gw) - GWComms[i] = gateway.StartGateway(gwID, gw.Address, handler, nil, nil) - } - - NotificationBotComms = notificationBot.StartNotificationBot(&id.NotificationBot, def.Notification.Address, &NotificationBotHandler, nil, nil) - -} - -func disconnectServers() { - for _, gw := range GWComms { - gw.DisconnectAll() - - } - RegComms.DisconnectAll() - NotificationBotComms.DisconnectAll() -} diff --git a/api/register.go b/api/register.go deleted file mode 100644 index 82fc53008..000000000 --- a/api/register.go +++ /dev/null @@ -1,285 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -package api - -import ( - "crypto/sha256" - "fmt" - "github.com/pkg/errors" - "gitlab.com/elixxir/client/bots" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/user" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/hash" - "gitlab.com/elixxir/crypto/registration" - "gitlab.com/xx_network/crypto/signature/rsa" - "gitlab.com/xx_network/crypto/tls" - "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/ndf" - "os" - "sync" - "time" -) - -const SaltSize = 32 - -//RegisterWithUDB uses the account's email to register with the UDB for -// User discovery. Must be called after Register and InitNetwork. -// It will fail if the user has already registered with UDB -func (cl *Client) RegisterWithUDB(username string, timeout time.Duration) error { - regState, err := cl.sessionV2.GetRegState() - if err != nil { - return err - } - userData, err := cl.sessionV2.GetUserData() - if err != nil { - return err - } - - if regState != user.PermissioningComplete { - return errors.New("Cannot register with UDB when registration " + - "state is not PermissioningComplete") - } - - if username != "" { - userData.ThisUser.Username = username - cl.sessionV2.CommitUserData(userData) - - globals.Log.INFO.Printf("Registering user as %s with UDB", username) - - valueType := "EMAIL" - - publicKeyBytes := userData.E2EDHPublicKey.Bytes() - err = bots.Register(valueType, username, publicKeyBytes, cl.opStatus, timeout) - if err != nil { - return errors.Errorf("Could not register with UDB: %s", err) - } - globals.Log.INFO.Printf("Registered with UDB!") - } else { - globals.Log.INFO.Printf("Not registering with UDB because no " + - "email found") - } - - //set the registration state - err = cl.sessionV2.SetRegState(user.UDBComplete) - if err != nil { - return errors.Wrap(err, "UDB Registration Failed") - } - - cl.opStatus(globals.REG_SECURE_STORE) - - errStore := cl.session.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( - "UDB Register: could not register due to failed session save"+ - ": %s", errStore.Error())) - return err - } - - return nil -} - -//RegisterWithNodes registers the client with all the nodes within the ndf -func (cl *Client) RegisterWithNodes() error { - - userData, err := cl.sessionV2.GetUserData() - if err != nil { - return err - } - - cl.opStatus(globals.REG_NODE) - session := cl.GetSession() - //Load Cmix keys & group - cmixDHPrivKey := userData.CMIXDHPrivateKey - cmixDHPubKey := userData.CMIXDHPublicKey - cmixGrp := userData.CmixGrp - - //Load the rsa keys - rsaPubKey := userData.RSAPublicKey - rsaPrivKey := userData.RSAPrivateKey - - //Load the user ID - UID := userData.ThisUser.User - usr := userData.ThisUser - //Load the registration signature - regSignature, err := cl.sessionV2.GetRegValidationSig() - if err != nil && !os.IsNotExist(err) { - return errors.Errorf("Failed to get registration signature: %v", - err) - } - - // Storage of the registration signature was broken in previous releases. - // get the signature again from permissioning if it is absent - var regPubKey *rsa.PublicKey - if cl.ndf.Registration.TlsCertificate != "" { - var err error - regPubKey, err = extractPublicKeyFromCert(cl.ndf) - if err != nil { - return err - } - } - - // Storage of the registration signature was broken in previous releases. - // get the signature again from permissioning if it is absent - if !usr.Precan && !rsa.IsValidSignature(regPubKey, regSignature) { - // Or register with the permissioning server and generate user information - regSignature, err := cl.registerWithPermissioning("", userData.RSAPublicKey) - if err != nil { - globals.Log.INFO.Printf(err.Error()) - return err - } - //update the session with the registration - //HACK HACK HACK - sesObj := cl.session.(*user.SessionObj) - err = cl.sessionV2.SetRegValidationSig(regSignature) - if err != nil { - return err - } - - err = sesObj.StoreSession() - - if err != nil { - return err - } - } - - //make the wait group to wait for all node registrations to complete - var wg sync.WaitGroup - errChan := make(chan error, len(cl.ndf.Gateways)) - - registeredNodes, err := cl.sessionV2.GetNodeKeys() - if err != nil { - return err - } - - salt := userData.Salt - - // This variable keeps track of whether there were new registrations - // required, thus requiring the state file to be saved again - newRegistrations := false - - for i := range cl.ndf.Gateways { - localI := i - nodeID, err := id.Unmarshal(cl.ndf.Nodes[i].ID) - if err != nil { - return nil - } - //Register with node if the node has not been registered with already - if _, ok := registeredNodes[nodeID.String()]; !ok { - wg.Add(1) - newRegistrations = true - go func() { - cl.registerWithNode(localI, salt, regSignature, UID, rsaPubKey, rsaPrivKey, - cmixDHPubKey, cmixDHPrivKey, cmixGrp, errChan) - wg.Done() - }() - } - } - wg.Wait() - //See if the registration returned errors at all - var errs error - for len(errChan) > 0 { - err := <-errChan - if errs != nil { - errs = errors.Wrap(errs, err.Error()) - } else { - errs = err - } - - } - //If an error every occurred, return with error - if errs != nil { - cl.opStatus(globals.REG_FAIL) - return errs - } - - // Store the user session if there were changes during node registration - if newRegistrations { - cl.opStatus(globals.REG_SECURE_STORE) - errStore := session.StoreSession() - if errStore != nil { - err := errors.New(fmt.Sprintf( - "Register: could not register due to failed session save"+ - ": %s", errStore.Error())) - return err - } - } - - return nil -} - -//registerWithNode serves as a helper for RegisterWithNodes -// It registers a user with a specific in the client's ndf. -func (cl *Client) registerWithNode(index int, salt, registrationValidationSignature []byte, UID *id.ID, - publicKeyRSA *rsa.PublicKey, privateKeyRSA *rsa.PrivateKey, - cmixPublicKeyDH, cmixPrivateKeyDH *cyclic.Int, - cmixGrp *cyclic.Group, errorChan chan error) { - - gatewayID, err := id.Unmarshal(cl.ndf.Gateways[index].ID) - if err != nil { - errorChan <- err - return - } - - // Initialise blake2b hash for transmission keys and sha256 for reception - // keys - transmissionHash, _ := hash.NewCMixHash() - receptionHash := sha256.New() - - // Request nonce message from gateway - globals.Log.INFO.Printf("Register: Requesting nonce from gateway %v/%v", - index+1, len(cl.ndf.Gateways)) - nonce, dhPub, err := cl.requestNonce(salt, registrationValidationSignature, cmixPublicKeyDH, - publicKeyRSA, privateKeyRSA, gatewayID) - - if err != nil { - errMsg := fmt.Sprintf("Register: Failed requesting nonce from gateway: %+v", err) - errorChan <- errors.New(errMsg) - return - } - - // Load server DH pubkey - serverPubDH := cmixGrp.NewIntFromBytes(dhPub) - - // Confirm received nonce - globals.Log.INFO.Println("Register: Confirming received nonce") - err = cl.confirmNonce(UID.Bytes(), nonce, privateKeyRSA, gatewayID) - if err != nil { - errMsg := fmt.Sprintf("Register: Unable to confirm nonce: %v", err) - errorChan <- errors.New(errMsg) - return - } - nodeID := cl.topology.GetNodeAtIndex(index) - key := user.NodeKeys{ - TransmissionKey: registration.GenerateBaseKey(cmixGrp, - serverPubDH, cmixPrivateKeyDH, transmissionHash), - ReceptionKey: registration.GenerateBaseKey(cmixGrp, serverPubDH, - cmixPrivateKeyDH, receptionHash), - } - cl.sessionV2.PushNodeKey(nodeID, key) -} - -// extractPublicKeyFromCert is a utility function which pulls out the public key from a certificate -func extractPublicKeyFromCert(definition *ndf.NetworkDefinition) (*rsa.PublicKey, error) { - // Load certificate object - cert, err := tls.LoadCertificate(definition.Registration.TlsCertificate) - if err != nil { - return nil, errors.Errorf("Failed to parse certificate: %+v", err) - } - //Extract public key from cert - regPubKey, err := tls.ExtractPublicKey(cert) - if err != nil { - return nil, errors.Errorf("Failed to pull key from cert: %+v", err) - } - - return regPubKey, nil - -} diff --git a/api/register_test.go b/api/register_test.go deleted file mode 100644 index 3f7718340..000000000 --- a/api/register_test.go +++ /dev/null @@ -1,138 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2019 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// -package api - -import ( - "gitlab.com/elixxir/client/network" - user2 "gitlab.com/elixxir/client/storage/user" - "gitlab.com/elixxir/client/user" - "gitlab.com/xx_network/primitives/id" - "testing" -) - -//Test that a registered session may be stored & recovered -func TestRegistrationGob(t *testing.T) { - // Get a Client - storage := DummyStorage{LocationA: ".ekv-registergob/a", StoreA: []byte{'a', 'b', 'c'}} - testClient, err := NewClient(&storage, ".ekv-registergob/a", "", def) - if err != nil { - t.Error(err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Error(err) - } - err = testClient.GenerateKeys(nil, "1234") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - network.SessionV2.SetRegState(user.KeyGenComplete) - - // populate a gob in the store - _, err = testClient.RegisterWithPermissioning(true, "WTROXJ33") - if err != nil { - t.Error(err) - } - - userData, _ := testClient.sessionV2.GetUserData() - - VerifyRegisterGobUser(userData.ThisUser, t) - - disconnectServers() -} - -//Happy path for a non precen user -func TestClient_Register(t *testing.T) { - //Make mock client - storage := DummyStorage{LocationA: ".ekv-clientregister/a", StoreA: []byte{'a', 'b', 'c'}} - testClient, err := NewClient(&storage, ".ekv-clientregister/a", "", def) - - if err != nil { - t.Error(err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Error(err) - } - - err = testClient.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - // fixme please (and all other places where this call is above RegisterWithPermissioning in tests) - testClient.sessionV2.SetRegState(user.KeyGenComplete) - // populate a gob in the store - _, err = testClient.RegisterWithPermissioning(true, "WTROXJ33") - if err != nil { - t.Error(err) - } - - err = testClient.RegisterWithNodes() - if err != nil { - t.Error(err) - } - - userData, _ := testClient.sessionV2.GetUserData() - - VerifyRegisterGobUser(userData.ThisUser, t) - - disconnectServers() -} - -//Verify the user from the session make in the registration above matches expected user -func VerifyRegisterGobUser(curUser *user2.User, t *testing.T) { - - expectedUser := id.NewIdFromUInt(5, id.User, t) - - if !curUser.User.Cmp(expectedUser) { - t.Errorf("Incorrect User ID; \n expected: %q \n recieved: %q", - expectedUser, curUser.User) - } -} - -// Verify that a valid precanned user can register -func TestRegister_ValidRegParams___(t *testing.T) { - // Initialize client with dummy storage - storage := DummyStorage{LocationA: ".ekv-validregparams/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&storage, ".ekv-validregparams/a", "", def) - if err != nil { - t.Errorf("Failed to initialize dummy client: %s", err.Error()) - } - - // InitNetwork to gateways and reg server - err = client.InitNetwork() - - if err != nil { - t.Errorf("Client failed of connect: %+v", err) - } - - err = client.GenerateKeys(nil, "") - if err != nil { - t.Errorf("%+v", err) - } - - network.SessionV2.SetRegState(user.KeyGenComplete) - // Register precanned user with all gateways - regRes, err := client.RegisterWithPermissioning(false, ValidRegCode) - if err != nil { - t.Errorf("Registration failed: %s", err.Error()) - } - - if *regRes == *&id.ZeroUser { - t.Errorf("Invalid registration number received: %+v", *regRes) - } - err = client.RegisterWithNodes() - if err != nil { - t.Error(err) - } - - //Disconnect and shutdown servers - disconnectServers() -} diff --git a/bindings/client.go b/bindings/client.go deleted file mode 100644 index 8a20c261a..000000000 --- a/bindings/client.go +++ /dev/null @@ -1,497 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2019 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -package bindings - -import ( - "crypto/rand" - "errors" - "fmt" - "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/api" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/parse" - "gitlab.com/elixxir/client/user" - "gitlab.com/elixxir/crypto/csprng" - "gitlab.com/xx_network/primitives/id" - "io" - "math/big" - "strings" - "time" -) - -type Client struct { - client *api.Client - statusCallback ConnectionStatusCallback -} - -// Returns listener handle as a string. -// You can use it to delete the listener later. -// Please ensure userId has the correct length (256 bits) -// User IDs are informally big endian. If you want compatibility with the demo -// user names, set the last byte and leave all other bytes zero for userId. -// If you pass the zero user ID (256 bits of zeroes) to Listen() you will hear -// messages sent from all users. -// If you pass the zero type (just zero) to Listen() you will hear messages of -// all types. -func (cl *Client) Listen(userId []byte, messageType int32, newListener Listener) (string, error) { - typedUserId, err := id.Unmarshal(userId) - if err != nil { - return "", err - } - - listener := &listenerProxy{proxy: newListener} - - return cl.client.Listen(typedUserId, messageType, listener), nil -} - -// Pass the listener handle that Listen() returned to delete the listener -func (cl *Client) StopListening(listenerHandle string) { - cl.client.StopListening(listenerHandle) -} - -func FormatTextMessage(message string) []byte { - return api.FormatTextMessage(message) -} - -// Initializes the client by registering a storage mechanism and a reception -// callback. -// For the mobile interface, one must be provided -// The loc can be empty, it is only necessary if the passed storage interface -// requires it to be passed via "SetLocation" -// -// Parameters: storage implements Storage. -// Implement this interface to store the user session data locally. -// You must give us something for this parameter. -// -// loc is a string. If you're using DefaultStorage for your storage, -// this would be the filename of the file that you're storing the user -// session in. -func NewClient(storage Storage, locA, locB string, ndfStr, ndfPubKey string) (*Client, error) { - globals.Log.INFO.Printf("Binding call: NewClient()") - if storage == nil { - return nil, errors.New("could not init client: Storage was nil") - } - - ndf := api.VerifyNDF(ndfStr, ndfPubKey) - - proxy := &storageProxy{boundStorage: storage} - - cl, err := api.NewClient(globals.Storage(proxy), locA, locB, ndf) - - return &Client{client: cl}, err -} - -func NewClient_deprecated(storage Storage, locA, locB string, ndfStr, ndfPubKey string, - csc ConnectionStatusCallback) (*Client, error) { - - return &Client{client: nil, statusCallback: csc}, nil -} - -func (cl *Client) EnableDebugLogs() { - globals.Log.INFO.Printf("Binding call: EnableDebugLogs()") - globals.Log.SetStdoutThreshold(jwalterweatherman.LevelDebug) - globals.Log.SetLogThreshold(jwalterweatherman.LevelDebug) -} - -// Connects to gateways and registration server (if needed) -// using tls filepaths to create credential information -// for connection establishment -func (cl *Client) InitNetwork() error { - globals.Log.INFO.Printf("Binding call: InitNetwork()") - return cl.client.InitNetwork() -} - -// Sets a callback which receives a strings describing the current status of -// Registration or UDB Registration, or UDB Search -func (cl *Client) SetOperationProgressCallback(rpcFace OperationProgressCallback) { - rpc := func(i int) { - rpcFace.Callback(i) - } - cl.client.SetOperationProgressCallback(rpc) -} - -// Generate Keys generates the user identity for the network and stores it -func (cl *Client) GenerateKeys(password string) error { - - globals.Log.INFO.Printf("Binding call: GenerateKeys()\n" + - " Password: ********") - return cl.client.GenerateKeys(nil, password) -} - -// Registers user and returns the User ID bytes. -// Returns null if registration fails and error -// If preCan set to true, registration is attempted assuming a pre canned user -// registrationCode is a one time use string -// registrationAddr is the address of the registration server -// gwAddressesList is CSV of gateway addresses -// grp is the CMIX group needed for keys generation in JSON string format -func (cl *Client) RegisterWithPermissioning(preCan bool, registrationCode string) ([]byte, error) { - - globals.Log.INFO.Printf("Binding call: RegisterWithPermissioning()\n"+ - " preCan: %v\n registrationCode: %s\n "+ - " Password: ********", preCan, registrationCode) - UID, err := cl.client.RegisterWithPermissioning(preCan, registrationCode) - - if err != nil { - return id.ZeroUser[:], err - } - - return UID[:], nil -} - -// Registers user with all nodes it has not been registered with. -// Returns error if registration fails -func (cl *Client) RegisterWithNodes() error { - globals.Log.INFO.Printf("Binding call: RegisterWithNodes()") - err := cl.client.RegisterWithNodes() - return err -} - -// Register with UDB uses the account's email to register with the UDB for -// User discovery. Must be called after Register and InitNetwork. -// It will fail if the user has already registered with UDB -func (cl *Client) RegisterWithUDB(username string, timeoutMS int) error { - globals.Log.INFO.Printf("Binding call: RegisterWithUDB()\n") - return cl.client.RegisterWithUDB(username, time.Duration(timeoutMS)*time.Millisecond) -} - -// Logs in the user based on User ID and returns the nickname of that user. -// Returns an empty string and an error -// UID is a uint64 BigEndian serialized into a byte slice -func (cl *Client) Login(UID []byte, password string) ([]byte, error) { - globals.Log.INFO.Printf("Binding call: Login()\n"+ - " UID: %v\n Password: ********", UID) - - uid, err := cl.client.Login(password) - - if uid == nil { - return make([]byte, 0), err - } - - return (*uid)[:], err -} - -func (cl *Client) GetUsername() string { - globals.Log.INFO.Printf("Binding call: GetUsername()") - - return cl.client.GetUsername() -} - -func (cl *Client) GetUserID() []byte { - globals.Log.INFO.Printf("Binding call: GetUserID()") - - return cl.client.GetCurrentUser().Bytes() -} - -type MessageReceiverCallback interface { - Callback(err error) -} - -// Starts the polling of the external servers. -// Must be done after listeners are set up. -func (cl *Client) StartMessageReceiver(mrc MessageReceiverCallback) error { - globals.Log.INFO.Printf("Binding call: StartMessageReceiver()") - return cl.client.StartMessageReceiver(mrc.Callback) -} - -func (cl *Client) StartMessageReceiver_deprecated() error { - receiverCallback := func(err error) { - cl.backoff(0) - } - - err := cl.client.StartMessageReceiver(receiverCallback) - if err != nil { - return err - } - return nil -} - -func (cl *Client) backoff(backoffCount int) { - receiverCallback := func(err error) { - cl.backoff(backoffCount + 1) - } - - // Compute backoff time - var delay time.Duration - var block = false - if backoffCount > 15 { - delay = time.Hour - block = true - } - wait := 2 ^ backoffCount - if wait > 180 { - wait = 180 - } - jitter, _ := rand.Int(csprng.NewSystemRNG(), big.NewInt(1000)) - delay = time.Second*time.Duration(wait) + time.Millisecond*time.Duration(jitter.Int64()) - - cl.statusCallback.Callback(0, int(delay.Seconds())) - - // Start timer, or stop if max attempts reached - timer := time.NewTimer(delay) - if block { - timer.Stop() - } - - select { - case <-timer.C: - backoffCount = 0 - } - - // attempt to start the message receiver - cl.statusCallback.Callback(1, 0) - err := cl.client.StartMessageReceiver(receiverCallback) - if err != nil { - cl.statusCallback.Callback(0, 0) - } - cl.statusCallback.Callback(2, 0) -} - -// Overwrites the username in registration. Only succeeds if the client -// has registered with permissioning but not UDB -func (cl *Client) ChangeUsername(un string) error { - globals.Log.INFO.Printf("Binding call: ChangeUsername()\n"+ - " username: %s", un) - regState, err := cl.client.GetSessionV2().GetRegState() - if err != nil { - return errors.New(fmt.Sprintf("Could not get reg state: %v", err)) - } - if regState != user.PermissioningComplete { - return errors.New("Can only change username during " + - "PermissioningComplete registration state") - } - return cl.client.ChangeUsername(un) -} - -// gets the curent registration status. they cane be: -// 0 - NotStarted -// 1 - PermissioningComplete -// 2 - UDBComplete -func (cl *Client) GetRegState() int64 { - globals.Log.INFO.Printf("Binding call: GetRegState()") - regState, err := cl.client.GetSessionV2().GetRegState() - if err != nil { - globals.Log.ERROR.Printf("GetRegState(): %+v", err) - } - return int64(regState) -} - -// Registers user with all nodes it has not been registered with. -// Returns error if registration fails -func (cl *Client) StorageIsEmpty() bool { - globals.Log.INFO.Printf("Binding call: StorageIsEmpty()") - return cl.client.GetSession().StorageIsEmpty() -} - -// Sends a message structured via the message interface -// Automatically serializes the message type before the rest of the payload -// Returns an error if either sender or recipient are too short -// the encrypt bool tell the client if it should send and e2e encrypted message -// or not. If true, and there is no keying relationship with the user specified -// in the message object, then it will return an error. If using precanned -// users encryption must be set to false. -func (cl *Client) Send(m Message, encrypt bool) (int64, error) { - globals.Log.INFO.Printf("Binding call: Send()\n"+ - "Sender: %v\n"+ - "Payload: %v\n"+ - "Recipient: %v\n"+ - "MessageTye: %v", m.GetSender(), m.GetPayload(), - m.GetRecipient(), m.GetMessageType()) - - sender, err := id.Unmarshal(m.GetSender()) - if err != nil { - return 0, err - } - recipient, err := id.Unmarshal(m.GetRecipient()) - if err != nil { - return 0, err - } - - var cryptoType parse.CryptoType - if encrypt { - cryptoType = parse.E2E - } else { - cryptoType = parse.Unencrypted - } - - return time.Now().UnixNano(), cl.client.Send(&parse.Message{ - TypedBody: parse.TypedBody{ - MessageType: m.GetMessageType(), - Body: m.GetPayload(), - }, - InferredType: cryptoType, - Sender: sender, - Receiver: recipient, - }) -} - -//a version of the send function which does not return a timestamp for use -//on iOS -func (cl *Client) SendNoTimestamp(m Message, encrypt bool) error { - _, err := cl.Send(m, encrypt) - return err -} - -// Logs the user out, saving the state for the system and clearing all data -// from RAM -func (cl *Client) Logout() error { - globals.Log.INFO.Printf("Binding call: Logout()\n") - return cl.client.Logout(500 * time.Millisecond) -} - -// Get the version string from the locally built client repository -func GetLocalVersion() string { - globals.Log.INFO.Printf("Binding call: GetLocalVersion()\n") - return api.GetLocalVersion() -} - -// Get the version string from the registration server -// You need to connect to gateways for this to be populated. -// For the client to function, the local version must be compatible with this -// version. If that's not the case, check out the git tag corresponding to the -// client release version returned here. -func (cl *Client) GetRemoteVersion() string { - globals.Log.INFO.Printf("Binding call: GetRemoteVersion()\n") - return cl.GetRemoteVersion() -} - -// Turns off blocking transmission so multiple messages can be sent -// simultaneously -func (cl *Client) DisableBlockingTransmission() { - globals.Log.INFO.Printf("Binding call: DisableBlockingTransmission()\n") - cl.client.DisableBlockingTransmission() -} - -// Sets the minimum amount of time, in ms, between message transmissions -// Just for testing, probably to be removed in production -func (cl *Client) SetRateLimiting(limit int) { - globals.Log.INFO.Printf("Binding call: SetRateLimiting()\n"+ - " limit: %v", limit) - cl.client.SetRateLimiting(uint32(limit)) -} - -// SearchForUser searches for the user with the passed username. -// returns state on the search callback. A timeout in ms is required. -// A recommended timeout is 2 minutes or 120000 -func (cl *Client) SearchForUser(username string, - cb SearchCallback, timeoutMS int) { - - globals.Log.INFO.Printf("Binding call: SearchForUser()\n"+ - " username: %v\n"+ - " timeout: %v\n", username, timeoutMS) - - proxy := &searchCallbackProxy{cb} - cl.client.SearchForUser(username, proxy, time.Duration(timeoutMS)*time.Millisecond) -} - -// DeleteContact deletes the contact at the given userID. returns the emails -// of that contact if possible -func (cl *Client) DeleteContact(uid []byte) (string, error) { - globals.Log.INFO.Printf("Binding call: DeleteContact()\n"+ - " uid: %v\n", uid) - u, err := id.Unmarshal(uid) - if err != nil { - return "", err - } - - return cl.client.DeleteUser(u) -} - -// Nickname lookup API -// Non-blocking, once the API call completes, the callback function -// passed as argument is called -func (cl *Client) LookupNick(user []byte, - cb NickLookupCallback) error { - proxy := &nickCallbackProxy{cb} - userID, err := id.Unmarshal(user) - if err != nil { - return err - } - cl.client.LookupNick(userID, proxy) - return nil -} - -// Parses a passed message. Allows a message to be parsed using the internal parser -// across the Bindings -func ParseMessage(message []byte) (Message, error) { - return api.ParseMessage(message) -} - -func (s *storageProxy) SetLocation(locationA, locationB string) error { - return s.boundStorage.SetLocation(locationA, locationB) -} - -func (s *storageProxy) GetLocation() (string, string) { - locsStr := s.boundStorage.GetLocation() - locs := strings.Split(locsStr, ",") - - if len(locs) == 2 { - return locs[0], locs[1] - } else { - return locsStr, locsStr + "-2" - } -} - -func (s *storageProxy) SaveA(data []byte) error { - return s.boundStorage.SaveA(data) -} - -func (s *storageProxy) LoadA() []byte { - return s.boundStorage.LoadA() -} - -func (s *storageProxy) SaveB(data []byte) error { - return s.boundStorage.SaveB(data) -} - -func (s *storageProxy) LoadB() []byte { - return s.boundStorage.LoadB() -} - -func (s *storageProxy) IsEmpty() bool { - return s.boundStorage.IsEmpty() -} - -type Writer interface{ io.Writer } - -func SetLogOutput(w Writer) { - api.SetLogOutput(w) -} - -// Call this to get the session data without getting Save called from the Go side -func (cl *Client) GetSessionData() ([]byte, error) { - return cl.client.GetSessionData() -} - -//LoadEncryptedSession: Spits out the encrypted session file in text -func (cl *Client) LoadEncryptedSession() (string, error) { - globals.Log.INFO.Printf("Binding call: LoadEncryptedSession()") - return cl.client.LoadEncryptedSession() -} - -//WriteToSession: Writes to file the replacement string -func (cl *Client) WriteToSession(replacement string, storage globals.Storage) error { - globals.Log.INFO.Printf("Binding call: WriteToSession") - return cl.client.WriteToSessionFile(replacement, storage) -} - -func (cl *Client) InitListeners() error { - globals.Log.INFO.Printf("Binding call: InitListeners") - return cl.client.InitListeners() -} - -// RegisterForNotifications sends a message to notification bot indicating it -// is registering for notifications -func (cl *Client) RegisterForNotifications(notificationToken []byte) error { - return cl.client.RegisterForNotifications(notificationToken) -} - -// UnregisterForNotifications sends a message to notification bot indicating it -// no longer wants to be registered for notifications -func (cl *Client) UnregisterForNotifications() error { - return cl.client.UnregisterForNotifications() -} diff --git a/bindings/client_test.go b/bindings/client_test.go deleted file mode 100644 index 2bc5073ac..000000000 --- a/bindings/client_test.go +++ /dev/null @@ -1,914 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -package bindings - -import ( - "bytes" - "crypto" - crand "crypto/rand" - "encoding/base64" - "encoding/json" - "fmt" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/network" - "gitlab.com/elixxir/client/network/keyExchange" - "gitlab.com/elixxir/client/parse" - "gitlab.com/elixxir/client/storage" - "gitlab.com/elixxir/client/user" - "gitlab.com/elixxir/comms/gateway" - pb "gitlab.com/elixxir/comms/mixmessages" - "gitlab.com/elixxir/comms/registration" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/large" - "gitlab.com/xx_network/comms/connect" - "gitlab.com/xx_network/comms/messages" - "gitlab.com/xx_network/crypto/signature/rsa" - "gitlab.com/xx_network/primitives/id" - "gitlab.com/xx_network/primitives/ndf" - "math/rand" - "os" - "reflect" - "sync" - "testing" - "time" -) - -const NumNodes = 3 -const NumGWs = NumNodes -const GWsStartPort = 7950 -const RegPort = 5100 -const ValidRegCode = "WTROXJ33" - -var RegHandler = MockRegistration{} -var RegComms *registration.Comms - -var GWComms [NumGWs]*gateway.Comms - -var def *ndf.NetworkDefinition - -type MockRegistration struct { -} - -func (i *MockRegistration) RegisterUser(registrationCode, test string) (hash []byte, err error) { - return nil, nil -} - -func (i *MockRegistration) RegisterNode(ID *id.ID, ServerAddr, ServerTlsCert, - GatewayAddr, GatewayTlsCert, RegistrationCode string) error { - return nil -} - -func (i *MockRegistration) GetCurrentClientVersion() (string, error) { - return globals.SEMVER, nil -} - -func (i *MockRegistration) PollNdf(clientNdfHash []byte, - auth *connect.Auth) ([]byte, - error) { - ndfJson, _ := json.Marshal(def) - return ndfJson, nil -} - -func (i *MockRegistration) Poll(*pb.PermissioningPoll, *connect.Auth, string) (*pb.PermissionPollResponse, error) { - return nil, nil -} - -func (i *MockRegistration) CheckRegistration(msg *pb.RegisteredNodeCheck) (*pb.RegisteredNodeConfirmation, error) { - return nil, nil -} - -// Setups general testing params and calls test wrapper -func TestMain(m *testing.M) { - network.SessionV2, _ = storage.Init(".ekvbindings/a", "test") - os.Exit(testMainWrapper(m)) -} - -// Make sure NewClient returns an error when called incorrectly. -func TestNewClientNil(t *testing.T) { - - ndfStr, pubKey := getNDFJSONStr(def, t) - - _, err := NewClient(nil, ".ekv-bindings-newclientnil/a", "", ndfStr, pubKey) - if err == nil { - t.Errorf("NewClient returned nil on invalid (nil, nil) input!") - } - - _, err = NewClient(nil, ".ekv-bindings-newclientnil2/a", "", "", "hello") - if err == nil { - t.Errorf("NewClient returned nil on invalid (nil, 'hello') input!") - } -} - -//Happy path: tests creation of valid client -func TestNewClient(t *testing.T) { - d := DummyStorage{LocationA: "Blah", StoreA: []byte{'a', 'b', 'c'}} - - ndfStr, pubKey := getNDFJSONStr(def, t) - - client, err := NewClient(&d, ".ekv-bindings-testnewclient/a", "", ndfStr, pubKey) - if err != nil { - t.Errorf("NewClient returned error: %v", err) - } else if client == nil { - t.Errorf("NewClient returned nil Client object") - } - for _, gw := range GWComms { - gw.DisconnectAll() - } -} - -//Happy Path: Register with permissioning -func TestRegister(t *testing.T) { - - ndfStr, pubKey := getNDFJSONStr(def, t) - - d := DummyStorage{LocationA: ".ekv-bindings-testreg/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&d, ".ekv-bindings-testreg/a", "", ndfStr, pubKey) - if err != nil { - t.Errorf("Failed to marshal group JSON: %s", err) - } - - err = client.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = client.GenerateKeys("") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - network.SessionV2.SetRegState(user.KeyGenComplete) - - regRes, err := client.RegisterWithPermissioning(true, ValidRegCode) - if err != nil { - t.Errorf("Registration failed: %s", err.Error()) - } - if len(regRes) == 0 { - t.Errorf("Invalid registration number received: %v", regRes) - } - for _, gw := range GWComms { - gw.DisconnectAll() - } -} - -type DummyReceptionCallback struct{} - -func (*DummyReceptionCallback) Callback(error) { - return -} - -//Error path: Changing username should panic before registration has happened -func TestClient_ChangeUsername_ErrorPath(t *testing.T) { - defer func() { - if r := recover(); r != nil { - return - } - }() - ndfStr, pubKey := getNDFJSONStr(def, t) - - d := DummyStorage{LocationA: ".ekv-bindings-changeusername-err/a", StoreA: []byte{'a', 'b', 'c'}} - - testClient, err := NewClient(&d, ".ekv-bindings-changeusername-err/a", "", ndfStr, pubKey) - if err != nil { - t.Errorf("Failed to marshal group JSON: %s", err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = testClient.ChangeUsername("josh420") - if err == nil { - t.Error("Expected error path, should not be able to change username before" + - "regState PermissioningComplete") - } -} - -//Happy path: should have no errors when changing username -func TestClient_ChangeUsername(t *testing.T) { - ndfStr, pubKey := getNDFJSONStr(def, t) - - d := DummyStorage{LocationA: ".ekv-bindings-changeuser/a", StoreA: []byte{'a', 'b', 'c'}} - - testClient, err := NewClient(&d, ".ekv-bindings-changeuser/a", "", ndfStr, pubKey) - if err != nil { - t.Errorf("Failed to marshal group JSON: %s", err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = testClient.client.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - regRes, err := testClient.RegisterWithPermissioning(false, ValidRegCode) - if err != nil { - t.Errorf("%+v", err) - } - if len(regRes) == 0 { - t.Errorf("Invalid registration number received: %v", regRes) - } - - err = testClient.ChangeUsername("josh420") - if err != nil { - t.Errorf("Unexpected error, should have changed username: %v", err) - } - -} - -func TestClient_StorageIsEmpty(t *testing.T) { - ndfStr, pubKey := getNDFJSONStr(def, t) - - d := DummyStorage{LocationA: ".ekv-bindings-emptystorage/a", StoreA: []byte{'a', 'b', 'c'}} - - testClient, err := NewClient(&d, ".ekv-bindings-emptystorage/a", "", ndfStr, pubKey) - if err != nil { - t.Errorf("Failed to marshal group JSON: %s", err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = testClient.client.GenerateKeys(nil, "") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - regRes, err := testClient.RegisterWithPermissioning(false, ValidRegCode) - if len(regRes) == 0 { - t.Errorf("Invalid registration number received: %v", regRes) - } - - if testClient.StorageIsEmpty() { - t.Errorf("Unexpected empty storage!") - } -} - -//Error path: Have added no contacts, so deleting a contact should fail -func TestDeleteUsername_EmptyContactList(t *testing.T) { - ndfStr, pubKey := getNDFJSONStr(def, t) - - d := DummyStorage{LocationA: ".ekv-bindings-emptycontacts/a", StoreA: []byte{'a', 'b', 'c'}} - - testClient, err := NewClient(&d, ".ekv-bindings-emptycontacts/a", "", ndfStr, pubKey) - if err != nil { - t.Errorf("Failed to marshal group JSON: %s", err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = testClient.client.GenerateKeys(nil, "") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - regRes, err := testClient.RegisterWithPermissioning(false, ValidRegCode) - if len(regRes) == 0 { - t.Errorf("Invalid registration number received: %v", regRes) - } - //Attempt to delete a contact from an empty contact list - _, err = testClient.DeleteContact([]byte("typo")) - if err != nil { - return - } - t.Errorf("Expected error path, but did not get error on deleting a contact." + - "Contact list should be empty") -} - -//Happy path: Tests regState gets properly updated along the registration codepath -func TestClient_GetRegState(t *testing.T) { - ndfStr, pubKey := getNDFJSONStr(def, t) - - d := DummyStorage{LocationA: ".ekv-bindings-getregstate/a", StoreA: []byte{'a', 'b', 'c'}} - testClient, err := NewClient(&d, ".ekv-bindings-getregstate/a", "", ndfStr, pubKey) - if err != nil { - t.Errorf("Failed to marshal group JSON: %s", err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = testClient.client.GenerateKeys(nil, "") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - network.SessionV2.SetRegState(user.KeyGenComplete) - - // Register with a valid registration code - _, err = testClient.RegisterWithPermissioning(true, ValidRegCode) - - if err != nil { - t.Errorf("Register with permissioning failed: %s", err.Error()) - } - - regState, _ := network.SessionV2.GetRegState() - if regState != int64(user.PermissioningComplete) { - t.Errorf("Unexpected reg state: Expected PermissioningComplete (%d), recieved: %d", - user.PermissioningComplete, testClient.GetRegState()) - } - - network.SessionV2.SetRegValidationSig([]byte("test")) - - err = testClient.RegisterWithNodes() - if err != nil { - t.Errorf("Register with nodes failed: %v", err.Error()) - } -} - -//Happy path: send unencrypted message -func TestClient_Send(t *testing.T) { - ndfStr, pubKey := getNDFJSONStr(def, t) - - d := DummyStorage{LocationA: ".ekv-bindings-send/a", StoreA: []byte{'a', 'b', 'c'}} - testClient, err := NewClient(&d, ".ekv-bindings-send/a", "", ndfStr, pubKey) - - if err != nil { - t.Errorf("Failed to marshal group JSON: %s", err) - } - - err = testClient.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = testClient.client.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - network.SessionV2.SetRegState(user.KeyGenComplete) - - // Register with a valid registration code - userID, err := testClient.RegisterWithPermissioning(true, ValidRegCode) - - if err != nil { - t.Errorf("Register with permissioning failed: %s", err.Error()) - } - - err = testClient.RegisterWithNodes() - if err != nil { - t.Errorf("Register with nodes failed: %v", err.Error()) - } - - // Login to gateway - _, err = testClient.Login(userID, "password") - - if err != nil { - t.Errorf("Login failed: %s", err.Error()) - } - - err = testClient.StartMessageReceiver(&DummyReceptionCallback{}) - - if err != nil { - t.Errorf("Could not start message reception: %+v", err) - } - - receiverID := id.NewIdFromBytes(userID, t) - receiverID.SetType(id.User) - // Test send with invalid sender ID - _, err = testClient.Send( - mockMesssage{ - Sender: id.NewIdFromUInt(12, id.User, t), - TypedBody: parse.TypedBody{Body: []byte("test")}, - Receiver: receiverID, - }, false) - - if err != nil { - // TODO: would be nice to catch the sender but we - // don't have the interface/mocking for that. - t.Errorf("error on first message send: %+v", err) - } - - // Test send with valid inputs - _, err = testClient.Send( - mockMesssage{ - Sender: id.NewIdFromBytes(userID, t), - TypedBody: parse.TypedBody{Body: []byte("test")}, - Receiver: testClient.client.GetCurrentUser(), - }, false) - - if err != nil { - t.Errorf("Error sending message: %v", err) - } - - err = testClient.Logout() - - if err != nil { - t.Errorf("Logout failed: %v", err) - } - disconnectServers() -} - -func TestLoginLogout(t *testing.T) { - - ndfStr, pubKey := getNDFJSONStr(def, t) - - d := DummyStorage{LocationA: ".ekv-bindings-loginlogout/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&d, ".ekv-bindings-loginlogout/a", "", ndfStr, pubKey) - if err != nil { - t.Errorf("Error starting client: %+v", err) - } - // InitNetwork to gateway - err = client.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = client.client.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - network.SessionV2.SetRegState(user.KeyGenComplete) - regRes, err := client.RegisterWithPermissioning(true, ValidRegCode) - loginRes, err2 := client.Login(regRes, "password") - if err2 != nil { - t.Errorf("Login failed: %s", err2.Error()) - } - if len(loginRes) == 0 { - t.Errorf("Invalid login received: %v", loginRes) - } - - err = client.StartMessageReceiver(&DummyReceptionCallback{}) - if err != nil { - t.Errorf("Could not start message reciever: %+v", err) - } - time.Sleep(200 * time.Millisecond) - err3 := client.Logout() - if err3 != nil { - t.Errorf("Logoutfailed: %s", err3.Error()) - } - for _, gw := range GWComms { - gw.DisconnectAll() - } -} - -type MockListener bool - -func (m *MockListener) Hear(msg Message, isHeardElsewhere bool) { - *m = true -} - -// Proves that a message can be received by a listener added with the bindings -func TestListen(t *testing.T) { - - ndfStr, pubKey := getNDFJSONStr(def, t) - - d := DummyStorage{LocationA: ".ekv-testlisten/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&d, ".ekv-testlisten/a", "", ndfStr, pubKey) - // InitNetwork to gateway - err = client.InitNetwork() - - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = client.client.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - network.SessionV2.SetRegState(user.KeyGenComplete) - regRes, _ := client.RegisterWithPermissioning(true, ValidRegCode) - _, err = client.Login(regRes, "password") - - if err != nil { - t.Errorf("Could not log in: %+v", err) - } - - listener := MockListener(false) - client.Listen(id.ZeroUser[:], int32(keyExchange.Type_NO_TYPE), &listener) - client.client.GetSwitchboard().Speak(&parse.Message{ - TypedBody: parse.TypedBody{ - MessageType: 0, - Body: []byte("stuff"), - }, - Sender: &id.ZeroUser, - Receiver: client.client.GetCurrentUser(), - }) - time.Sleep(time.Second) - if !listener { - t.Error("Message not received") - } - for _, gw := range GWComms { - gw.DisconnectAll() - } -} - -func TestStopListening(t *testing.T) { - - ndfStr, pubKey := getNDFJSONStr(def, t) - - d := DummyStorage{LocationA: ".ekv-teststoplistening/a", StoreA: []byte{'a', 'b', 'c'}} - client, err := NewClient(&d, ".ekv-teststoplistening/a", "", ndfStr, pubKey) - if err != nil { - t.Errorf("Failed to create client: %+v", err) - } - - // InitNetwork to gateway - err = client.InitNetwork() - if err != nil { - t.Errorf("Could not connect: %+v", err) - } - - err = client.client.GenerateKeys(nil, "password") - if err != nil { - t.Errorf("Could not generate Keys: %+v", err) - } - - network.SessionV2.SetRegState(user.KeyGenComplete) - regRes, _ := client.RegisterWithPermissioning(true, ValidRegCode) - - _, err = client.Login(regRes, "password") - - if err != nil { - t.Errorf("Could not log in: %+v", err) - } - - listener := MockListener(false) - handle, err := client.Listen(id.ZeroUser[:], int32(keyExchange.Type_NO_TYPE), &listener) - if err != nil { - t.Fatal(err) - } - client.StopListening(handle) - client.client.GetSwitchboard().Speak(&parse.Message{ - TypedBody: parse.TypedBody{ - MessageType: 0, - Body: []byte("stuff"), - }, - Sender: &id.ZeroUser, - Receiver: &id.ZeroUser, - }) - if listener { - t.Error("Message was received after we stopped listening for it") - } -} - -type MockWriter struct { - lastMessage []byte -} - -func (mw *MockWriter) Write(msg []byte) (int, error) { - mw.lastMessage = msg - return len(msg), nil -} - -func TestSetLogOutput(t *testing.T) { - mw := &MockWriter{} - SetLogOutput(mw) - msg := "Test logging message" - globals.Log.CRITICAL.Print(msg) - if !bytes.Contains(mw.lastMessage, []byte(msg)) { - t.Errorf("Mock writer didn't get the logging message") - } -} - -func TestParse(t *testing.T) { - ms := parse.Message{} - ms.Body = []byte{0, 1, 2} - ms.MessageType = int32(keyExchange.Type_NO_TYPE) - ms.Receiver = &id.ZeroUser - ms.Sender = &id.ZeroUser - - 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) - } - -} - -func getNDFJSONStr(def *ndf.NetworkDefinition, t *testing.T) (string, string) { - ndfBytes, err := json.Marshal(def) - - if err != nil { - t.Errorf("Could not JSON the NDF: %+v", err) - } - - // Load tls private key - privKey, err := 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")) - if err != nil || privKey == nil { - t.Error("Failed to load privKey\n") - } - - // Sign the NDF - rsaHash := crypto.SHA256.New() - rsaHash.Write(ndfBytes) - signature, _ := rsa.Sign( - crand.Reader, privKey, crypto.SHA256, rsaHash.Sum(nil), nil) - - // Compose network definition string - ndfStr := string(ndfBytes) + "\n" + base64.StdEncoding.EncodeToString(signature) + "\n" - - return ndfStr, "-----BEGIN CERTIFICATE-----\nMIIGHTCCBAWgAwIBAgIUOcAn9cpH+hyRH8/UfqtbFDoSxYswDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJQ2xhcmVt\nb250MRAwDgYDVQQKDAdFbGl4eGlyMRQwEgYDVQQLDAtEZXZlbG9wbWVudDEZMBcG\nA1UEAwwQZ2F0ZXdheS5jbWl4LnJpcDEfMB0GCSqGSIb3DQEJARYQYWRtaW5AZWxp\neHhpci5pbzAeFw0xOTA4MTYwMDQ4MTNaFw0yMDA4MTUwMDQ4MTNaMIGSMQswCQYD\nVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCUNsYXJlbW9udDEQMA4GA1UE\nCgwHRWxpeHhpcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxGTAXBgNVBAMMEGdhdGV3\nYXkuY21peC5yaXAxHzAdBgkqhkiG9w0BCQEWEGFkbWluQGVsaXh4aXIuaW8wggIi\nMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7Dkb6VXFn4cdpU0xh6ji0nTDQ\nUyT9DSNW9I3jVwBrWfqMc4ymJuonMZbuqK+cY2l+suS2eugevWZrtzujFPBRFp9O\n14Jl3fFLfvtjZvkrKbUMHDHFehascwzrp3tXNryiRMmCNQV55TfITVCv8CLE0t1i\nbiyOGM9ZWYB2OjXt59j76lPARYww5qwC46vS6+3Cn2Yt9zkcrGeskWEFa2VttHqF\n910TP+DZk2R5C7koAh6wZYK6NQ4S83YQurdHAT51LKGrbGehFKXq6/OAXCU1JLi3\nkW2PovTb6MZuvxEiRmVAONsOcXKu7zWCmFjuZZwfRt2RhnpcSgzfrarmsGM0LZh6\nJY3MGJ9YdPcVGSz+Vs2E4zWbNW+ZQoqlcGeMKgsIiQ670g0xSjYICqldpt79gaET\n9PZsoXKEmKUaj6pq1d4qXDk7s63HRQazwVLGBdJQK8qX41eCdR8VMKbrCaOkzD5z\ngnEu0jBBAwdMtcigkMIk1GRv91j7HmqwryOBHryLi6NWBY3tjb4So9AppDQB41SH\n3SwNenAbNO1CXeUqN0hHX6I1bE7OlbjqI7tXdrTllHAJTyVVjenPel2ApMXp+LVR\ndDbKtwBiuM6+n+z0I7YYerxN1gfvpYgcXm4uye8dfwotZj6H2J/uSALsU2v9UHBz\nprdrLSZk2YpozJb+CQIDAQABo2kwZzAdBgNVHQ4EFgQUDaTvG7SwgRQ3wcYx4l+W\nMcZjX7owHwYDVR0jBBgwFoAUDaTvG7SwgRQ3wcYx4l+WMcZjX7owDwYDVR0TAQH/\nBAUwAwEB/zAUBgNVHREEDTALgglmb28uY28udWswDQYJKoZIhvcNAQELBQADggIB\nADKz0ST0uS57oC4rT9zWhFqVZkEGh1x1XJ28bYtNUhozS8GmnttV9SnJpq0EBCm/\nr6Ub6+Wmf60b85vCN5WDYdoZqGJEBjGGsFzl4jkYEE1eeMfF17xlNUSdt1qLCE8h\nU0glr32uX4a6nsEkvw1vo1Liuyt+y0cOU/w4lgWwCqyweu3VuwjZqDoD+3DShVzX\n8f1p7nfnXKitrVJt9/uE+AtAk2kDnjBFbRxCfO49EX4Cc5rADUVXMXm0itquGBYp\nMbzSgFmsMp40jREfLYRRzijSZj8tw14c2U9z0svvK9vrLCrx9+CZQt7cONGHpr/C\n/GIrP/qvlg0DoLAtjea73WxjSCbdL3Nc0uNX/ymXVHdQ5husMCZbczc9LYdoT2VP\nD+GhkAuZV9g09COtRX4VP09zRdXiiBvweiq3K78ML7fISsY7kmc8KgVH22vcXvMX\nCgGwbrxi6QbQ80rWjGOzW5OxNFvjhvJ3vlbOT6r9cKZGIPY8IdN/zIyQxHiim0Jz\noavr9CPDdQefu9onizsmjsXFridjG/ctsJxcUEqK7R12zvaTxu/CVYZbYEUFjsCe\nq6ZAACiEJGvGeKbb/mSPvGs2P1kS70/cGp+P5kBCKqrm586FB7BcafHmGFrWhT3E\nLOUYkOV/gADT2hVDCrkPosg7Wb6ND9/mhCVVhf4hLGRh\n-----END CERTIFICATE-----\n" -} - -// Handles initialization of mock registration server, -// gateways used for registration and gateway used for session -func testMainWrapper(m *testing.M) int { - - def = getNDF() - - // Initialize permissioning server - // TODO(nan) We shouldn't need to start registration servers twice, right? - pAddr := def.Registration.Address - regId := new(id.ID) - copy(regId[:], "testRegServer") - regId.SetType(id.Generic) - RegComms = registration.StartRegistrationServer(regId, pAddr, - &RegHandler, nil, nil) - - // Start mock gateways used by registration and defer their shutdown (may not be needed) - //the ports used are colliding between tests in GoLand when running full suite, this is a dumb fix - bump := rand.Intn(10) * 10 - for i := 0; i < NumGWs; i++ { - gwId := new(id.ID) - copy(gwId[:], "testGateway") - gwId.SetType(id.Gateway) - - gw := ndf.Gateway{ - ID: gwId.Marshal(), - Address: fmtAddress(GWsStartPort + i + bump), - } - - def.Gateways = append(def.Gateways, gw) - GWComms[i] = gateway.StartGateway(gwId, gw.Address, - &GatewayHandler{}, nil, nil) - } - - // Start mock registration server and defer its shutdown - def.Registration = ndf.Registration{ - Address: fmtAddress(RegPort), - } - RegComms = registration.StartRegistrationServer(regId, def.Registration.Address, - &RegHandler, nil, nil) - - for i := 0; i < NumNodes; i++ { - nId := new(id.ID) - nId[0] = byte(i) - nId.SetType(id.Node) - n := ndf.Node{ - ID: nId[:], - } - def.Nodes = append(def.Nodes, n) - } - - defer testWrapperShutdown() - return m.Run() -} - -func testWrapperShutdown() { - for _, gw := range GWComms { - gw.Shutdown() - } - RegComms.Shutdown() - -} - -func fmtAddress(port int) string { return fmt.Sprintf("localhost:%d", port) } - -func getNDF() *ndf.NetworkDefinition { - return &ndf.NetworkDefinition{ - E2E: ndf.Group{ - Prime: "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B" + - "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE" + - "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F" + - "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041" + - "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45" + - "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209" + - "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29" + - "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E" + - "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2" + - "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696" + - "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E" + - "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873" + - "847AEF49F66E43873", - Generator: "2", - }, - CMIX: ndf.Group{ - Prime: "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + - "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + - "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + - "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + - "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + - "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + - "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + - "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", - Generator: "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + - "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + - "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + - "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + - "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + - "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + - "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + - "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", - }, - Registration: ndf.Registration{ - Address: fmt.Sprintf("0.0.0.0:%d", 5000+rand.Intn(1000)), - TlsCertificate: "", - }, - } -} - -// Mock dummy storage interface for testing. -type DummyStorage struct { - LocationA string - LocationB string - StoreA []byte - StoreB []byte - mutex sync.Mutex -} - -func (d *DummyStorage) IsEmpty() bool { - return d.StoreA == nil && d.StoreB == nil -} - -func (d *DummyStorage) SetLocation(lA, lB string) error { - d.LocationA = lA - d.LocationB = lB - return nil -} - -func (d *DummyStorage) GetLocation() string { - return fmt.Sprintf("%s,%s", d.LocationA, d.LocationB) -} - -func (d *DummyStorage) SaveA(b []byte) error { - d.StoreA = make([]byte, len(b)) - copy(d.StoreA, b) - return nil -} - -func (d *DummyStorage) SaveB(b []byte) error { - d.StoreB = make([]byte, len(b)) - copy(d.StoreB, b) - return nil -} - -func (d *DummyStorage) Lock() { - d.mutex.Lock() -} - -func (d *DummyStorage) Unlock() { - d.mutex.Unlock() -} - -func (d *DummyStorage) LoadA() []byte { - return d.StoreA -} - -func (d *DummyStorage) LoadB() []byte { - return d.StoreB -} - -type mockMesssage struct { - parse.TypedBody - // The crypto type is inferred from the message's contents - InferredType parse.CryptoType - Sender *id.ID - Receiver *id.ID - Nonce []byte - Timestamp time.Time -} - -// Returns the message's sender ID -func (m mockMesssage) GetSender() []byte { - return m.Sender.Bytes() -} - -// Returns the message payload -// Parse this with protobuf/whatever according to the type of the message -func (m mockMesssage) GetPayload() []byte { - return m.TypedBody.Body -} - -// Returns the message's recipient ID -func (m mockMesssage) GetRecipient() []byte { - return m.Receiver.Bytes() -} - -// Returns the message's type -func (m mockMesssage) GetMessageType() int32 { - return m.TypedBody.MessageType -} - -// Returns the message's timestamp in seconds since unix epoc -func (m mockMesssage) GetTimestamp() int64 { - return m.Timestamp.Unix() -} - -// Returns the message's timestamp in ns since unix epoc -func (m mockMesssage) GetTimestampNano() int64 { - return m.Timestamp.UnixNano() -} - -func disconnectServers() { - for _, gw := range GWComms { - gw.DisconnectAll() - - } - RegComms.DisconnectAll() -} - -// ------------------------------------ MOCK GATEWAYS ---------------------------------------------------------------- - -// Blank struct implementing ServerHandler interface for testing purposes (Passing to StartServer) -type GatewayHandler struct { - LastReceivedMessage pb.Slot -} - -func (m *GatewayHandler) PollForNotifications(auth *connect.Auth) ([]*id.ID, error) { - - return nil, nil -} - -func (m *GatewayHandler) Poll(*pb.GatewayPoll) (*pb.GatewayPollResponse, error) { - return nil, nil -} - -// Returns message contents for MessageID, or a null/randomized message -// if that ID does not exist of the same size as a regular message -func (m *GatewayHandler) GetMessage(userId *id.ID, - msgId, ipaddr string) (*pb.Slot, error) { - return &pb.Slot{}, nil -} - -// Return any MessageIDs in the globals for this User -func (m *GatewayHandler) CheckMessages(userId *id.ID, - messageID, ipAddress string) ([]string, error) { - return make([]string, 0), nil -} - -// PutMessage adds a message to the outgoing queue and -// calls SendBatch when it's size is the batch size -func (m *GatewayHandler) PutMessage(msg *pb.GatewaySlot, ipaddr string) (*pb.GatewaySlotResponse, error) { - m.LastReceivedMessage = *msg.Message - return &pb.GatewaySlotResponse{ - Accepted: true, - }, nil -} - -func (m *GatewayHandler) ConfirmNonce(message *pb.RequestRegistrationConfirmation, ipaddr string) (*pb.RegistrationConfirmation, error) { - regConfirmation := &pb.RegistrationConfirmation{ - ClientSignedByServer: &messages.RSASignature{}, - } - - return regConfirmation, nil -} - -// Pass-through for Registration Nonce Communication -func (m *GatewayHandler) RequestNonce(message *pb.NonceRequest, ipaddr string) (*pb.Nonce, error) { - dh := getDHPubKey().Bytes() - return &pb.Nonce{ - DHPubKey: dh, - }, nil -} - -func getDHPubKey() *cyclic.Int { - cmixGrp := cyclic.NewGroup( - large.NewIntFromString("9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48"+ - "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F"+ - "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5"+ - "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2"+ - "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41"+ - "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE"+ - "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15"+ - "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", 16), - large.NewIntFromString("5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613"+ - "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4"+ - "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472"+ - "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5"+ - "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA"+ - "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71"+ - "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0"+ - "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", 16)) - - dh := cmixGrp.RandomCoprime(cmixGrp.NewMaxInt()) - return cmixGrp.ExpG(dh, cmixGrp.NewMaxInt()) -} diff --git a/bots/README.md b/bots/README.md deleted file mode 100644 index f759d6a55..000000000 --- a/bots/README.md +++ /dev/null @@ -1 +0,0 @@ -Use this module to write code for working with different cMix bots diff --git a/bots/bots.go b/bots/bots.go deleted file mode 100644 index 089e1e93d..000000000 --- a/bots/bots.go +++ /dev/null @@ -1,122 +0,0 @@ -package bots - -import ( - "gitlab.com/elixxir/client/cmixproto" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/network" - "gitlab.com/elixxir/client/network/keyExchange" - "gitlab.com/elixxir/client/parse" - "gitlab.com/elixxir/client/storage" - "gitlab.com/elixxir/client/user" - "gitlab.com/elixxir/primitives/switchboard" - "gitlab.com/xx_network/comms/connect" - "gitlab.com/xx_network/primitives/id" -) - -var session user.Session -var sessionV2 storage.Session -var topology *connect.Circuit -var comms network.Communications -var transmissionHost *connect.Host - -type channelResponseListener chan string - -func (l *channelResponseListener) Hear(msg switchboard.Item, isHeardElsewhere bool, i ...interface{}) { - m := msg.(*parse.Message) - *l <- string(m.Body) -} - -var pushKeyResponseListener channelResponseListener -var getKeyResponseListener channelResponseListener -var registerResponseListener channelResponseListener -var searchResponseListener channelResponseListener -var nicknameResponseListener channelResponseListener - -// Nickname request listener -type nickReqListener struct { - MyNick string -} - -// Nickname listener simply replies with message containing user's nick -func (l *nickReqListener) Hear(msg switchboard.Item, isHeardElsewhere bool, i ...interface{}) { - m := msg.(*parse.Message) - nick := l.MyNick - resp := parse.Pack(&parse.TypedBody{ - MessageType: int32(cmixproto.Type_NICKNAME_RESPONSE), - Body: []byte(nick), - }) - globals.Log.DEBUG.Printf("Sending nickname response to user %v", *m.Sender) - sendCommand(m.Sender, resp) -} - -var nicknameRequestListener nickReqListener - -// InitBots is called internally by the Login API -func InitBots(s user.Session, s2 storage.Session, m network.Communications, - top *connect.Circuit, host *connect.Host) { - - userData, err := s2.GetUserData() - if err != nil { - globals.Log.FATAL.Panicf("Could not load userdata: %+v", err) - } - - userNick := userData.ThisUser.Username - - // FIXME: these all need to be used in non-blocking threads if we are - // going to do it this way... - msgBufSize := 100 - pushKeyResponseListener = make(channelResponseListener, msgBufSize) - getKeyResponseListener = make(channelResponseListener, msgBufSize) - registerResponseListener = make(channelResponseListener, msgBufSize) - searchResponseListener = make(channelResponseListener, msgBufSize) - nicknameRequestListener = nickReqListener{ - MyNick: userNick, - } - nicknameResponseListener = make(channelResponseListener, msgBufSize) - - session = s - sessionV2 = s2 - topology = top - comms = m - transmissionHost = host - - l := m.GetSwitchboard() - - l.Register(&id.UDB, int32(keyExchange.Type_UDB_PUSH_KEY_RESPONSE), - &pushKeyResponseListener) - l.Register(&id.UDB, int32(keyExchange.Type_UDB_GET_KEY_RESPONSE), - &getKeyResponseListener) - l.Register(&id.UDB, int32(keyExchange.Type_UDB_REGISTER_RESPONSE), - ®isterResponseListener) - l.Register(&id.UDB, int32(keyExchange.Type_UDB_SEARCH_RESPONSE), - &searchResponseListener) - l.Register(&id.ZeroUser, - int32(cmixproto.Type_NICKNAME_REQUEST), &nicknameRequestListener) - l.Register(&id.ZeroUser, - int32(cmixproto.Type_NICKNAME_RESPONSE), &nicknameResponseListener) -} - -// sendCommand sends a command to the udb. This doesn't block. -// Callers that need to wait on a response should implement waiting with a -// listener. -func sendCommand(botID *id.ID, command []byte) error { - return comms.SendMessage(session, topology, botID, - parse.Unencrypted, command, transmissionHost) -} - -// Nickname Lookup function -func LookupNick(user *id.ID) (string, error) { - globals.Log.DEBUG.Printf("Sending nickname request to user %v", *user) - msg := parse.Pack(&parse.TypedBody{ - MessageType: int32(cmixproto.Type_NICKNAME_REQUEST), - Body: []byte{}, - }) - - err := sendCommand(user, msg) - if err != nil { - return "", err - } - - nickResponse := <-nicknameResponseListener - return nickResponse, nil -} diff --git a/bots/bots_test.go b/bots/bots_test.go deleted file mode 100644 index 6dd35b682..000000000 --- a/bots/bots_test.go +++ /dev/null @@ -1,290 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2019 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -// Package bot functions for working with the user discovery bot (UDB) -package bots - -import ( - "encoding/base64" - "encoding/binary" - "fmt" - "github.com/pkg/errors" - jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/cmixproto" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/parse" - "gitlab.com/elixxir/client/storage" - user2 "gitlab.com/elixxir/client/storage/user" - "gitlab.com/elixxir/client/user" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/large" - "gitlab.com/elixxir/primitives/format" - "gitlab.com/elixxir/primitives/switchboard" - "gitlab.com/xx_network/comms/connect" - "gitlab.com/xx_network/primitives/id" - "os" - "strings" - "testing" - "time" -) - -var ListenCh chan *format.Message - -type dummyMessaging struct { - listener chan *format.Message - switchboard *switchboard.Switchboard -} - -// SendMessage to the server -func (d *dummyMessaging) SendMessage(sess user.Session, - topology *connect.Circuit, - recipientID *id.ID, - cryptoType parse.CryptoType, - message []byte, transmissionHost *connect.Host) error { - jww.INFO.Printf("Sending: %s", string(message)) - return nil -} - -// SendMessage without partitions to the server -func (d *dummyMessaging) SendMessageNoPartition(sess user.Session, - topology *connect.Circuit, - recipientID *id.ID, - cryptoType parse.CryptoType, - message []byte, transmissionHost *connect.Host) error { - jww.INFO.Printf("Sending: %s", string(message)) - return nil -} - -// MessageReceiver thread to get new messages -func (d *dummyMessaging) MessageReceiver(session user.Session, - delay time.Duration, transmissionHost *connect.Host, callback func(error)) { -} - -// MessageReceiver thread to get new messages -func (d *dummyMessaging) GetSwitchboard() *switchboard.Switchboard { - return d.switchboard -} - -var pubKeyBits string -var keyFingerprint string -var pubKey []byte - -func TestMain(m *testing.M) { - u := &user2.User{ - User: new(id.ID), - Username: "Bernie", - } - binary.BigEndian.PutUint64(u.User[:], 18) - u.User.SetType(id.User) - - cmixGrp, e2eGrp := getGroups() - - fakeSession := user.NewSession(&globals.RamStorage{}, "password") - fakeSession2 := storage.InitTestingSession(m) - fakeSession2.CommitUserData(&user2.UserData{ - ThisUser: &user2.User{ - User: u.User, - Username: u.Username, - }, - CmixGrp: cmixGrp, - E2EGrp: e2eGrp, - }) - fakeComm := &dummyMessaging{ - listener: ListenCh, - switchboard: switchboard.NewSwitchboard(), - } - h := connect.Host{} - nodeID := new(id.ID) - nodeID.SetType(id.Node) - topology := connect.NewCircuit([]*id.ID{nodeID}) - - InitBots(fakeSession, *fakeSession2, fakeComm, topology, &h) - - // Make the reception channels buffered for this test - // which overwrites the channels registered in InitBots - pushKeyResponseListener = make(channelResponseListener, 100) - getKeyResponseListener = make(channelResponseListener, 100) - registerResponseListener = make(channelResponseListener, 100) - searchResponseListener = make(channelResponseListener, 100) - - pubKeyBits = "S8KXBczy0jins9uS4LgBPt0bkFl8t00MnZmExQ6GcOcu8O7DKgAsNzLU7a+gMTbIsS995IL/kuFF8wcBaQJBY23095PMSQ/nMuetzhk9HdXxrGIiKBo3C/n4SClpq4H+PoF9XziEVKua8JxGM2o83KiCK3tNUpaZbAAElkjueY7wuD96h4oaA+WV5Nh87cnIZ+fAG0uLve2LSHZ0FBZb3glOpNAOv7PFWkvN2BO37ztOQCXTJe72Y5ReoYn7nWVNxGUh0ilal+BRuJt1GZ7whOGDRE0IXfURIoK2yjyAnyZJWWMhfGsL5S6iL4aXUs03mc8BHKRq3HRjvTE10l3YFA==" - pubKey, _ = base64.StdEncoding.DecodeString(pubKeyBits) - - keyFingerprint = fingerprint(pubKey) - - os.Exit(m.Run()) -} - -// TestRegister smoke tests the registration functionality. -func TestRegister(t *testing.T) { - // Send response messages from fake UDB in advance - pushKeyResponseListener <- fmt.Sprintf("PUSHKEY COMPLETE %s", keyFingerprint) - registerResponseListener <- "REGISTRATION COMPLETE" - - dummyRegState := func(int) { - return - } - err := Register("EMAIL", "rick@elixxir.io", pubKey, dummyRegState, 30*time.Second) - if err != nil { - t.Errorf("Registration failure: %s", err.Error()) - } - // Send response messages from fake UDB in advance - pushKeyResponseListener <- fmt.Sprintf("PUSHKEY Failed: Could not push key %s becasue key already exists", keyFingerprint) - err = Register("EMAIL", "rick@elixxir.io", pubKey, dummyRegState, 30*time.Second) - if err == nil { - t.Errorf("Registration duplicate did not fail") - } -} - -// TestSearch smoke tests the search function -func TestSearch(t *testing.T) { - publicKeyString := base64.StdEncoding.EncodeToString(pubKey) - - // Send response messages from fake UDB in advance - searchResponseListener <- "blah@elixxir.io FOUND UR69db14ZyicpZVqJ1HFC5rk9UZ8817aV6+VHmrJpGc= AAAAAAAAABoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD 8oKh7TYG4KxQcBAymoXPBHSD/uga9pX3Mn/jKhvcD8M=" - getKeyResponseListener <- fmt.Sprintf("GETKEY %s %s", keyFingerprint, - publicKeyString) - - dummySearchState := func(int) { - return - } - - searchedUser, err := Search("EMAIL", "blah@elixxir.io", - dummySearchState, 30*time.Second) - if err != nil { - t.Fatalf("Error on Search: %s", err.Error()) - } - if !searchedUser.Id.Cmp(id.NewIdFromUInt(26, id.User, t)) { - t.Errorf("Search did not return user ID 26! returned %s", searchedUser) - } - //Test the timeout capabilities - searchedUser, err = Search("EMAIL", "blah@elixxir.io", dummySearchState, 1*time.Millisecond) - if err == nil { - t.Fatal("udb search timeout should have caused error") - } - if strings.Compare(err.Error(), "UDB search timeout exceeded on user lookup") != 0 { - t.Errorf("error: %v", err) - } -} - -// messages using switchboard -// Test LookupNick function -func TestNicknameFunctions(t *testing.T) { - // Test receiving a nickname request - userData, _ := sessionV2.GetUserData() - curUser := userData.ThisUser.User - - msg := &parse.Message{ - Sender: curUser, - TypedBody: parse.TypedBody{ - MessageType: int32(cmixproto.Type_NICKNAME_REQUEST), - Body: []byte{}, - }, - InferredType: parse.Unencrypted, - Receiver: curUser, - } - comms.GetSwitchboard().Speak(msg) - - // Test nickname lookup - - // send response to switchboard - msg = &parse.Message{ - Sender: curUser, - TypedBody: parse.TypedBody{ - MessageType: int32(cmixproto.Type_NICKNAME_RESPONSE), - Body: []byte(userData.ThisUser.Username), - }, - InferredType: parse.Unencrypted, - Receiver: curUser, - } - comms.GetSwitchboard().Speak(msg) - // AFter sending the message, perform the lookup to read it - nick, err := LookupNick(curUser) - if err != nil { - t.Errorf("Error on LookupNick: %s", err.Error()) - } - if nick != userData.ThisUser.Username { - t.Errorf("LookupNick returned wrong value. Expected %s,"+ - " Got %s", userData.ThisUser.Username, nick) - } -} - -type errorMessaging struct{} - -// SendMessage that just errors out -func (e *errorMessaging) SendMessage(sess user.Session, - topology *connect.Circuit, - recipientID *id.ID, - cryptoType parse.CryptoType, - message []byte, transmissionHost *connect.Host) error { - return errors.New("This is an error") -} - -// SendMessage no partition that just errors out -func (e *errorMessaging) SendMessageNoPartition(sess user.Session, - topology *connect.Circuit, - recipientID *id.ID, - cryptoType parse.CryptoType, - message []byte, transmissionHost *connect.Host) error { - return errors.New("This is an error") -} - -// MessageReceiver thread to get new messages -func (e *errorMessaging) MessageReceiver(session user.Session, - delay time.Duration, transmissionHost *connect.Host, callback func(error)) { -} - -func (e *errorMessaging) GetSwitchboard() *switchboard.Switchboard { - return nil -} - -// Test LookupNick returns error on sending problem -func TestLookupNick_error(t *testing.T) { - userData, _ := sessionV2.GetUserData() - // Replace comms with errorMessaging - comms = &errorMessaging{} - _, err := LookupNick(userData.ThisUser.User) - if err == nil { - t.Errorf("LookupNick should have returned an error") - } -} - -func getGroups() (cmixGrp *cyclic.Group, e2eGrp *cyclic.Group) { - - cmixPrime := "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + - "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + - "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + - "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" + - "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" + - "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" + - "15728E5A8AACAA68FFFFFFFFFFFFFFFF" - - e2ePrime := "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B" + - "7A8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3DD2AE" + - "DF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E7861575E745D31F" + - "8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC6ADC718DD2A3E041" + - "023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C4A530E8FFB1BC51DADDF45" + - "3B0B2717C2BC6669ED76B4BDD5C9FF558E88F26E5785302BEDBCA23EAC5ACE9209" + - "6EE8A60642FB61E8F3D24990B8CB12EE448EEF78E184C7242DD161C7738F32BF29" + - "A841698978825B4111B4BC3E1E198455095958333D776D8B2BEEED3A1A1A221A6E" + - "37E664A64B83981C46FFDDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F2" + - "78DE8014A47323631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696" + - "015CB79C3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E" + - "6319BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC35873" + - "847AEF49F66E43873" - - cmixGrp = cyclic.NewGroup(large.NewIntFromString(cmixPrime, 16), - large.NewIntFromUInt(2)) - - e2eGrp = cyclic.NewGroup(large.NewIntFromString(e2ePrime, 16), - large.NewIntFromUInt(2)) - - return -} diff --git a/bots/userDiscovery.go b/bots/userDiscovery.go deleted file mode 100644 index 8803f9ab5..000000000 --- a/bots/userDiscovery.go +++ /dev/null @@ -1,284 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2019 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -// Package bot functions for working with the user discovery bot (UDB) -package bots - -import ( - "bytes" - "crypto/sha256" - "encoding/base64" - "fmt" - "github.com/pkg/errors" - "gitlab.com/elixxir/client/globals" - "gitlab.com/elixxir/client/network/keyExchange" - "gitlab.com/elixxir/client/parse" - "gitlab.com/elixxir/client/storage" - "gitlab.com/elixxir/crypto/hash" - "gitlab.com/xx_network/primitives/id" - "strings" - "time" -) - -var pushkeyExpected = "PUSHKEY COMPLETE" - -// Register sends a registration message to the UDB. It does this by sending 2 -// PUSHKEY messages to the UDB, then calling UDB's REGISTER command. -// If any of the commands fail, it returns an error. -// valueType: Currently only "EMAIL" -func Register(valueType, value string, publicKey []byte, regStatus func(int), timeout time.Duration) error { - globals.Log.DEBUG.Printf("Running register for %v, %v, %q", valueType, - value, publicKey) - - registerTimeout := time.NewTimer(timeout) - - var err error - if valueType == "EMAIL" { - value, err = hashAndEncode(strings.ToLower(value)) - if err != nil { - return fmt.Errorf("could not hash and encode email %s: %+v", value, err) - } - } - - keyFP := fingerprint(publicKey) - - regStatus(globals.UDB_REG_PUSHKEY) - // push key and error if it already exists - err = pushKey(keyFP, publicKey) - - if err != nil { - return errors.Wrap(err, "Could not PUSHKEY") - } - - var response string - - // wait for the response to submitting the key against the timeout. - // discard responses from other searches - submitted := false - - for !submitted { - select { - case response = <-pushKeyResponseListener: - if strings.Contains(response, keyFP) { - if strings.Contains(response, pushkeyExpected) { - submitted = true - } else { - err := errors.New(response) - return errors.Wrap(err, "PushKey failed") - } - } - case <-registerTimeout.C: - return errors.New("UDB register timeout exceeded on key submission") - } - } - - //send the user information to udb - msgBody := parse.Pack(&parse.TypedBody{ - MessageType: int32(keyExchange.Type_UDB_REGISTER), - Body: []byte(fmt.Sprintf("%s %s %s", valueType, value, keyFP)), - }) - - regStatus(globals.UDB_REG_PUSHUSER) - - // Send register command - // Send register command - err = sendCommand(&id.UDB, msgBody) - if err != nil { - return errors.Wrap(err, "Could not Push User") - } - - // wait for the response to submitting the key against the timeout. - // discard responses from other searches - complete := false - - for !complete { - select { - case response = <-registerResponseListener: - expected := "REGISTRATION COMPLETE" - unavalibleReg := "Can not register with existing email" - if strings.Contains(response, expected) { - complete = true - } else if strings.Contains(response, value) && strings.Contains(response, unavalibleReg) { - return errors.New("Cannot register with existing username") - } - case <-registerTimeout.C: - return errors.New("UDB register timeout exceeded on user submission") - } - } - - return nil -} - -// Search returns a userID and public key based on the search criteria -// it accepts a valueType of EMAIL and value of an e-mail address, and -// returns a map of userid -> public key -func Search(valueType, value string, searchStatus func(int), timeout time.Duration) (*storage.Contact, error) { - globals.Log.DEBUG.Printf("Running search for %v, %v", valueType, value) - - searchTimeout := time.NewTimer(timeout) - email := value - var err error - if valueType == "EMAIL" { - value, err = hashAndEncode(strings.ToLower(value)) - if err != nil { - return nil, fmt.Errorf("could not hash and encode email %s: %+v", value, err) - } - } - - searchStatus(globals.UDB_SEARCH_LOOK) - - msgBody := parse.Pack(&parse.TypedBody{ - MessageType: int32(keyExchange.Type_UDB_SEARCH), - Body: []byte(fmt.Sprintf("%s %s", valueType, value)), - }) - err = sendCommand(&id.UDB, msgBody) - if err != nil { - return nil, err - } - - var response string - - // wait for the response to searching for the value against the timeout. - // discard responses from other searches - found := false - - for !found { - select { - case response = <-searchResponseListener: - empty := fmt.Sprintf("SEARCH %s NOTFOUND", value) - if response == empty { - return nil, nil - } - if strings.Contains(response, value) { - found = true - } - case <-searchTimeout.C: - return nil, errors.New("UDB search timeout exceeded on user lookup") - } - } - - // While search returns more than 1 result, we only process the first - cMixUID, keyFP, err := parseSearch(response) - if err != nil { - return nil, err - } - - searchStatus(globals.UDB_SEARCH_GETKEY) - - // Get the full key and decode it - msgBody = parse.Pack(&parse.TypedBody{ - MessageType: int32(keyExchange.Type_UDB_GET_KEY), - Body: []byte(keyFP), - }) - err = sendCommand(&id.UDB, msgBody) - if err != nil { - return nil, err - } - - // wait for the response to searching for the key against the timeout. - // discard responses from other searches - found = false - for !found { - select { - case response = <-getKeyResponseListener: - if strings.Contains(response, keyFP) { - found = true - } - case <-searchTimeout.C: - return nil, errors.New("UDB search timeout exceeded on key lookup") - } - } - - publicKey := parseGetKey(response) - - return &storage.Contact{ - Id: cMixUID, - PublicKey: publicKey, - Email: email, - }, nil -} - -func hashAndEncode(s string) (string, error) { - buf := new(bytes.Buffer) - encoder := base64.NewEncoder(base64.StdEncoding, buf) - - sha := sha256.New() - sha.Write([]byte(s)) - hashed := sha.Sum(nil) - - _, err := encoder.Write(hashed) - if err != nil { - err = errors.New(fmt.Sprintf("Error base64 encoding string %s: %+v", s, err)) - return "", err - } - - err = encoder.Close() - if err != nil { - err = errors.New(fmt.Sprintf("Error closing encoder: %+v", err)) - return "", err - } - - return buf.String(), nil -} - -// parseSearch parses the responses from SEARCH. It returns the user's id and -// the user's public key fingerprint -func parseSearch(msg string) (*id.ID, string, error) { - globals.Log.DEBUG.Printf("Parsing search response: %v", msg) - resParts := strings.Split(msg, " ") - if len(resParts) != 5 { - return &id.ZeroUser, "", errors.WithMessagef(errors.New("Invalid response from search"), ": %s", msg) - } - - cMixUIDBytes, err := base64.StdEncoding.DecodeString(resParts[3]) - if err != nil { - return &id.ZeroUser, "", errors.WithMessagef(errors.New("Couldn't parse search cMix UID"), ": %s", msg) - } - cMixUID, err := id.Unmarshal(cMixUIDBytes) - if err != nil { - return &id.ZeroUser, "", err - } - - return cMixUID, resParts[4], nil -} - -// parseGetKey parses the responses from GETKEY. It returns the -// corresponding public key. -func parseGetKey(msg string) []byte { - resParts := strings.Split(msg, " ") - if len(resParts) != 3 { - globals.Log.WARN.Printf("Invalid response from GETKEY: %s", msg) - return nil - } - keymat, err := base64.StdEncoding.DecodeString(resParts[2]) - if err != nil || len(keymat) == 0 { - globals.Log.WARN.Printf("Couldn't decode GETKEY keymat: %s", msg) - return nil - } - return keymat -} - -// pushKey uploads the users' public key -func pushKey(keyFP string, publicKey []byte) error { - publicKeyString := base64.StdEncoding.EncodeToString(publicKey) - globals.Log.DEBUG.Printf("Running pushkey for %v, %v, %v", id.UDB, keyFP, - publicKeyString) - - pushKeyMsg := fmt.Sprintf("%s %s", keyFP, publicKeyString) - - return sendCommand(&id.UDB, parse.Pack(&parse.TypedBody{ - MessageType: int32(keyExchange.Type_UDB_PUSH_KEY), - Body: []byte(pushKeyMsg), - })) -} - -// fingerprint generates the same fingerprint that the udb should generate -// TODO: Maybe move this helper to crypto module? -func fingerprint(publicKey []byte) string { - h, _ := hash.NewCMixHash() // why does this return an err and not panic? - h.Write(publicKey) - return base64.StdEncoding.EncodeToString(h.Sum(nil)) -} diff --git a/userRegistry/regCode.go b/userRegistry/regCode.go deleted file mode 100644 index 8cb936dbc..000000000 --- a/userRegistry/regCode.go +++ /dev/null @@ -1,21 +0,0 @@ -package userRegistry - -import ( - "encoding/base32" - "gitlab.com/xx_network/primitives/id" - "golang.org/x/crypto/blake2b" -) - -const RegCodeLen = 5 - -func RegistrationCode(id *id.ID) string { - return base32.StdEncoding.EncodeToString(userHash(id)) -} - -func userHash(id *id.ID) []byte { - h, _ := blake2b.New256(nil) - h.Write(id.Marshal()) - huid := h.Sum(nil) - huid = huid[len(huid)-RegCodeLen:] - return huid -} diff --git a/userRegistry/user.go b/userRegistry/user.go deleted file mode 100644 index 25c533055..000000000 --- a/userRegistry/user.go +++ /dev/null @@ -1,161 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2019 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -package userRegistry - -import ( - "crypto/sha256" - "encoding/binary" - "gitlab.com/elixxir/client/globals" - user2 "gitlab.com/elixxir/client/storage/user" - "gitlab.com/elixxir/client/user" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/xx_network/primitives/id" -) - -// Globally instantiated Registry -var Users Registry - -const NumDemoUsers = 40 - -var DemoUserNicks = []string{"David", "Payments", "UDB", "Jim", "Ben", "Steph", - "Rick", "Jake", "Niamh", "Stephanie", "Mario", "Jono", "Amanda", - "Margaux", "Kevin", "Bruno", "Konstantino", "Bernardo", "Tigran", - "Kate", "Will", "Katie", "Bryan"} -var DemoChannelNames = []string{"#General", "#Engineering", "#Lunch", - "#Random"} - -func InitUserRegistry(grp *cyclic.Group) { - Users = newRegistry(grp) -} - -// Interface for User Registry operations -type Registry interface { - NewUser(id *id.ID, nickname string) *user2.User - DeleteUser(id *id.ID) - GetUser(id *id.ID) (user *user2.User, ok bool) - UpsertUser(user *user2.User) - CountUsers() int - LookupUser(hid string) (uid *id.ID, ok bool) - LookupKeys(uid *id.ID) (*user.NodeKeys, bool) -} - -type UserMap struct { - // Map acting as the User Registry containing User -> ID mapping - userCollection map[id.ID]*user2.User - // Increments sequentially for User.ID values - idCounter uint64 - // Temporary map acting as a lookup table for demo user registration codes - // Key type is string because keys must implement == and []byte doesn't - userLookup map[string]*id.ID - //Temporary placed to store the keys for each user - keysLookup map[id.ID]*user.NodeKeys -} - -// newRegistry creates a new Registry interface -func newRegistry(grp *cyclic.Group) Registry { - if len(DemoChannelNames) > 10 || len(DemoUserNicks) > 30 { - globals.Log.ERROR.Print("Not enough demo users have been hardcoded.") - } - userUserIdMap := make(map[id.ID]*user2.User) - userRegCodeMap := make(map[string]*id.ID) - nk := make(map[id.ID]*user.NodeKeys) - - // Deterministically create NumDemoUsers users - // TODO Replace this with real user registration/discovery - for i := uint64(1); i <= NumDemoUsers; i++ { - currentID := new(id.ID) - binary.BigEndian.PutUint64(currentID[:], i) - currentID.SetType(id.User) - newUsr := new(user2.User) - nodeKey := new(user.NodeKeys) - - // Generate user parameters - newUsr.User = currentID - newUsr.Precan = true - // TODO We need a better way to generate base/recursive keys - h := sha256.New() - h.Write([]byte(string(40000 + i))) - nodeKey.TransmissionKey = grp.NewIntFromBytes(h.Sum(nil)) - h = sha256.New() - h.Write([]byte(string(60000 + i))) - nodeKey.ReceptionKey = grp.NewIntFromBytes(h.Sum(nil)) - - // Add user to collection and lookup table - userUserIdMap[*newUsr.User] = newUsr - // Detect collisions in the registration code - if _, ok := userRegCodeMap[RegistrationCode(newUsr.User)]; ok { - globals.Log.ERROR.Printf( - "Collision in demo user list creation at %v. "+ - "Please fix ASAP (include more bits to the reg code.", i) - } - userRegCodeMap[RegistrationCode(newUsr.User)] = newUsr.User - nk[*newUsr.User] = nodeKey - } - - // Channels have been hardcoded to users starting with 31 - for i := 0; i < len(DemoUserNicks); i++ { - currentID := new(id.ID) - binary.BigEndian.PutUint64(currentID[:], uint64(i)+1) - currentID.SetType(id.User) - userUserIdMap[*currentID].Username = DemoUserNicks[i] - } - - for i := 0; i < len(DemoChannelNames); i++ { - currentID := new(id.ID) - binary.BigEndian.PutUint64(currentID[:], uint64(i)+31) - currentID.SetType(id.User) - userUserIdMap[*currentID].Username = DemoChannelNames[i] - } - - // With an underlying UserMap data structure - return Registry(&UserMap{userCollection: userUserIdMap, - idCounter: uint64(NumDemoUsers), - userLookup: userRegCodeMap, - keysLookup: nk}) -} - -// NewUser creates a new User object with default fields and given address. -func (m *UserMap) NewUser(id *id.ID, username string) *user2.User { - return &user2.User{User: id, Username: username} -} - -// GetUser returns a user with the given ID from userCollection -// and a boolean for whether the user exists -func (m *UserMap) GetUser(id *id.ID) (user *user2.User, ok bool) { - user, ok = m.userCollection[*id] - user = user.DeepCopy() - return -} - -// DeleteContactKeys deletes a user with the given ID from userCollection. -func (m *UserMap) DeleteUser(id *id.ID) { - // If key does not exist, do nothing - delete(m.userCollection, *id) -} - -// UpsertUser inserts given user into userCollection or update the user if it -// already exists (Upsert operation). -func (m *UserMap) UpsertUser(user *user2.User) { - m.userCollection[*user.User] = user -} - -// CountUsers returns a count of the users in userCollection -func (m *UserMap) CountUsers() int { - return len(m.userCollection) -} - -// LookupUser returns the user id corresponding to the demo registration code -func (m *UserMap) LookupUser(hid string) (*id.ID, bool) { - uid, ok := m.userLookup[hid] - return uid, ok -} - -// LookupKeys returns the keys for the given user from the temporary key map -func (m *UserMap) LookupKeys(uid *id.ID) (*user.NodeKeys, bool) { - nk, t := m.keysLookup[*uid] - return nk, t -} diff --git a/userRegistry/user_test.go b/userRegistry/user_test.go deleted file mode 100644 index 9252882b2..000000000 --- a/userRegistry/user_test.go +++ /dev/null @@ -1,134 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright © 2019 Privategrity Corporation / -// / -// All rights reserved. / -//////////////////////////////////////////////////////////////////////////////// - -package userRegistry - -import ( - "crypto/sha256" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/large" - "gitlab.com/xx_network/primitives/id" - "testing" -) - -// TestUserRegistry tests the constructors/getters/setters -// surrounding the User struct and the Registry interface -func TestUserRegistry(t *testing.T) { - InitUserRegistry(InitGroup()) - // Test if CountUsers correctly counts the hard-coded demo users - if Users.CountUsers() != NumDemoUsers { - t.Errorf("CountUsers: Start size of userRegistry not zero!") - } - // Test the integration of the LookupUser, UserHash and GetUser functions - for i := 0; i < len(DemoUserNicks); i++ { - currentID := id.NewIdFromUInt(uint64(i+1), id.User, t) - reg, ok := Users.LookupUser(RegistrationCode(currentID)) - if !ok { - t.Errorf("Couldn't lookup user %q with code %v", *currentID, - RegistrationCode(currentID)) - } - usr, ok := Users.GetUser(reg) - if !ok { - t.Logf("Reg codes of both: %v, %v", RegistrationCode(reg), - RegistrationCode(currentID)) - t.Errorf("Couldn't get user %q corresponding to user %q", - *reg, *currentID) - } - if usr.Username != DemoUserNicks[i] { - t.Errorf("Nickname incorrectly set. Expected: %v Actual: %v", - DemoUserNicks[i], usr.Username) - } - } - // Test the NewUser function - newID := id.NewIdFromUInt(2002, id.User, t) - usr := Users.NewUser(newID, "Will I am") - - if usr.Username != "Will I am" { - t.Errorf("User name should be 'Will I am', but is %v instead", usr.Username) - } - - // Test that UpsertUser successfully adds a user to the usermap - userCount := Users.CountUsers() - Users.UpsertUser(usr) - if Users.CountUsers() != userCount+1 { - t.Errorf("Upsert did not add a new user. User count is incorrect") - } - newUsr, suc := Users.GetUser(newID) - if !suc { - t.Errorf("Upsert did not add the test user correctly. " + - "The ID was not found by GetUser.") - } - if newUsr.Username != "Will I am" { - t.Errorf("Upsert did not add the test user correctly. "+ - "The set nickname was incorrect. Expected: Will I am, "+ - "Actual: %v", newUsr.Username) - } - - // Initialize group - grp := InitGroup() - - // Test LookupKeys - keys, suc := Users.LookupKeys(id.NewIdFromUInt(1, id.User, t)) - if !suc { - t.Errorf("LookupKeys failed to find a valid user.") - } - h := sha256.New() - h.Write([]byte(string(40001))) - key := grp.NewIntFromBytes(h.Sum(nil)) - if keys.TransmissionKey.Text(16) != key.Text(16) { - t.Errorf("LookupKeys returned an incorrect key. "+ - "Expected:%v \nActual%v", key.Text(16), - keys.TransmissionKey.Text(16)) - } - - // Test delete user - Users.DeleteUser(id.NewIdFromUInt(2, id.User, t)) - - _, ok := Users.GetUser(id.NewIdFromUInt(2, id.User, t)) - if ok { - t.Errorf("User %v has not been deleted succesfully!", usr.Username) - } -} - -// Doesn't actually do any testing, but can print the registration codes for -// the first several users -func TestPrintRegCodes(t *testing.T) { - for i := 1; i <= NumDemoUsers; i++ { - currentID := id.NewIdFromUInt(uint64(i), id.User, t) - t.Logf("%v:\t%v", i, RegistrationCode(currentID)) - } -} - -// InitGroup sets up the cryptographic constants for cMix -func InitGroup() *cyclic.Group { - - base := 16 - - pString := "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + - "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + - "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + - "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + - "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + - "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + - "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + - "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B" - - gString := "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + - "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + - "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + - "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + - "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + - "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + - "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + - "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7" - - p := large.NewIntFromString(pString, base) - g := large.NewIntFromString(gString, base) - - grp := cyclic.NewGroup(p, g) - - return grp -} -- GitLab