From 753863600cf5fa7233d311eb87f6a94bc256c5d9 Mon Sep 17 00:00:00 2001 From: Jono Wenger <jono@elixxir.io> Date: Tue, 3 May 2022 16:24:39 +0000 Subject: [PATCH] Replace usage of manager with interface and add services --- api/client.go | 5 + api/precan.go | 9 +- api/user.go | 27 +- bindings/group.go | 4 +- bindings/ud.go | 24 +- cmd/group.go | 16 +- cmd/ud.go | 410 +++++++++++++++-------------- cmix/remoteFilters.go | 4 +- go.mod | 2 +- go.sum | 4 + groupChat/group.go | 13 +- groupChat/groupStore/group.go | 22 +- groupChat/groupStore/store_test.go | 32 +-- groupChat/makeGroup.go | 6 +- groupChat/makeGroup_test.go | 24 +- groupChat/manager.go | 70 +++-- groupChat/manager_test.go | 97 ++++--- groupChat/messageReceive.go | 23 +- groupChat/processor.go | 25 ++ groupChat/receive.go | 63 +++-- groupChat/receiveRequest.go | 16 +- groupChat/receiveRequest_test.go | 8 +- groupChat/send.go | 44 ++-- groupChat/sendRequests.go | 14 +- groupChat/sendRequests_test.go | 24 +- groupChat/send_test.go | 25 +- groupChat/service.go | 35 +++ groupChat/utils_test.go | 12 +- interfaces/networkManager.go | 9 +- single/request.go | 2 - storage/user/cryptographic.go | 4 +- ud/interfaces.go | 4 + ud/manager.go | 10 + ud/register.go | 2 +- ud/search.go | 3 +- xxmutils/restoreContacts.go | 23 +- 36 files changed, 647 insertions(+), 468 deletions(-) create mode 100644 groupChat/processor.go create mode 100644 groupChat/service.go diff --git a/api/client.go b/api/client.go index 97241cf29..7c23d024a 100644 --- a/api/client.go +++ b/api/client.go @@ -716,6 +716,11 @@ func (c *Client) GetE2EHandler() e2e.Handler { return c.e2e } +// GetEventReporter returns the event reporter +func (c *Client) GetEventReporter() event.Reporter { + return c.events +} + // GetBackup returns a pointer to the backup container so that the backup can be // set and triggered. func (c *Client) GetBackup() *backup.Backup { diff --git a/api/precan.go b/api/precan.go index f85210df1..a563faa23 100644 --- a/api/precan.go +++ b/api/precan.go @@ -9,6 +9,7 @@ package api import ( "encoding/binary" + "gitlab.com/elixxir/crypto/diffieHellman" "math/rand" "github.com/cloudflare/circl/dh/sidh" @@ -33,10 +34,7 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, prng := rand.New(rand.NewSource(int64(precannedID))) prime := e2e.GetPBytes() keyLen := len(prime) - e2eKeyBytes, err := csprng.GenerateInGroup(prime, keyLen, prng) - if err != nil { - jww.FATAL.Panicf(err.Error()) - } + e2eKey := diffieHellman.GeneratePrivateKey(keyLen, e2e, prng) // Salt, UID, etc gen salt := make([]byte, SaltSize) @@ -57,7 +55,8 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, ReceptionID: &userID, ReceptionSalt: salt, Precanned: true, - E2eDhPrivateKey: e2e.NewIntFromBytes(e2eKeyBytes), + E2eDhPrivateKey: e2eKey, + E2eDhPublicKey: diffieHellman.GeneratePublicKey(e2eKey, e2e), TransmissionRSA: rsaKey, ReceptionRSA: rsaKey, } diff --git a/api/user.go b/api/user.go index 5913185b4..f0538a1a9 100644 --- a/api/user.go +++ b/api/user.go @@ -8,6 +8,7 @@ package api import ( + "gitlab.com/elixxir/crypto/diffieHellman" "regexp" "runtime" "strings" @@ -33,10 +34,10 @@ func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.Info { // CMIX Keygen var transmissionRsaKey, receptionRsaKey *rsa.PrivateKey + var e2eKey *cyclic.Int + var transmissionSalt, receptionSalt []byte - var e2eKeyBytes, transmissionSalt, receptionSalt []byte - - e2eKeyBytes, transmissionSalt, receptionSalt, + transmissionSalt, receptionSalt, e2eKey, transmissionRsaKey, receptionRsaKey = createKeys(rng, e2e) // Salt, UID, etc gen @@ -85,13 +86,14 @@ func createNewUser(rng *fastRNG.StreamGenerator, cmix, ReceptionSalt: receptionSalt, ReceptionRSA: receptionRsaKey, Precanned: false, - E2eDhPrivateKey: e2e.NewIntFromBytes(e2eKeyBytes), + E2eDhPrivateKey: e2eKey, + E2eDhPublicKey: diffieHellman.GeneratePublicKey(e2eKey, e2e), } } func createKeys(rng *fastRNG.StreamGenerator, - e2e *cyclic.Group) (e2eKeyBytes, - transmissionSalt, receptionSalt []byte, + e2e *cyclic.Group) ( + transmissionSalt, receptionSalt []byte, e2eKey *cyclic.Int, transmissionRsaKey, receptionRsaKey *rsa.PrivateKey) { wg := sync.WaitGroup{} @@ -101,9 +103,7 @@ func createKeys(rng *fastRNG.StreamGenerator, defer wg.Done() var err error rngStream := rng.GetStream() - prime := e2e.GetPBytes() - keyLen := len(prime) - e2eKeyBytes, err = csprng.GenerateInGroup(prime, keyLen, + e2eKey = diffieHellman.GeneratePrivateKey(len(e2e.GetPBytes()), e2e, rngStream) rngStream.Close() if err != nil { @@ -148,10 +148,8 @@ func createNewVanityUser(rng csprng.Source, cmix, // DH Keygen prime := e2e.GetPBytes() keyLen := len(prime) - e2eKeyBytes, err := csprng.GenerateInGroup(prime, keyLen, rng) - if err != nil { - jww.FATAL.Panicf(err.Error()) - } + + e2eKey := diffieHellman.GeneratePrivateKey(keyLen, e2e, rng) // RSA Keygen (4096 bit defaults) transmissionRsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen) @@ -261,6 +259,7 @@ func createNewVanityUser(rng csprng.Source, cmix, ReceptionSalt: receptionSalt, ReceptionRSA: receptionRsaKey, Precanned: false, - E2eDhPrivateKey: e2e.NewIntFromBytes(e2eKeyBytes), + E2eDhPrivateKey: e2eKey, + E2eDhPublicKey: diffieHellman.GeneratePublicKey(e2eKey, e2e), } } diff --git a/bindings/group.go b/bindings/group.go index 3fce2e43b..761796628 100644 --- a/bindings/group.go +++ b/bindings/group.go @@ -20,7 +20,7 @@ import ( // GroupChat object contains the group chat manager. type GroupChat struct { - m *gc.Manager + m gc.GroupChat } // GroupRequestFunc contains a function callback that is called when a group @@ -48,7 +48,7 @@ func NewGroupManager(client *Client, requestFunc GroupRequestFunc, // Create a new group chat manager // TODO: Need things from storage, services, etc? - m, err := gc.NewManager(&client.api, requestCallback, receiveCallback) + m, err := gc.NewManager(client.api, requestCallback, receiveCallback) if err != nil { return nil, err } diff --git a/bindings/ud.go b/bindings/ud.go index 23195fd75..ea8f5390a 100644 --- a/bindings/ud.go +++ b/bindings/ud.go @@ -41,8 +41,8 @@ func NewUserDiscovery(client *Client, username string) (*UserDiscovery, error) { stream := client.api.GetRng().GetStream() defer stream.Close() m, err := udPackage.NewManager(client.api.GetNetworkInterface(), - client.api.GetE2e(), client.api.NetworkFollowerStatus, - client.api.GetEventManager(), + client.api.GetE2EHandler(), client.api.NetworkFollowerStatus, + client.api.GetEventReporter(), client.api.GetComms(), client.api.GetStorage(), stream, username, client.api.GetStorage().GetKV()) @@ -60,7 +60,7 @@ func NewUserDiscovery(client *Client, username string) (*UserDiscovery, error) { // instantiation of the manager by NewUserDiscovery. func LoadUserDiscovery(client *Client) (*UserDiscovery, error) { m, err := udPackage.LoadManager(client.api.GetNetworkInterface(), - client.api.GetE2e(), client.api.GetEventManager(), + client.api.GetE2EHandler(), client.api.GetEventReporter(), client.api.GetComms(), client.api.GetStorage(), client.api.GetStorage().GetKV()) @@ -119,7 +119,11 @@ func NewUserDiscoveryFromBackup(client *Client, "registered phone number") } - m, err := udPackage.NewManagerFromBackup(client.api.GetNetworkInterface(), client.api.GetE2e(), client.api.NetworkFollowerStatus, client.api.GetEventManager(), client.api.GetComms(), client.api.GetStorage(), emailFact, phoneFact, client.api.GetStorage().GetKV()) + m, err := udPackage.NewManagerFromBackup(client.api.GetNetworkInterface(), + client.api.GetE2EHandler(), client.api.NetworkFollowerStatus, + client.api.GetEventReporter(), client.api.GetComms(), + client.api.GetStorage(), emailFact, phoneFact, + client.api.GetStorage().GetKV()) if err != nil { return nil, errors.WithMessage(err, "Failed to create User Discovery Manager") @@ -228,8 +232,8 @@ func (ud UserDiscovery) Search(client *Client, } rids, _, err := udPackage.Search( - client.api.GetNetworkInterface(), client.api.GetEventManager(), - stream, client.api.GetE2e().GetGroup(), udContact, + client.api.GetNetworkInterface(), client.api.GetEventReporter(), + stream, client.api.GetE2EHandler().GetGroup(), udContact, cb, factList, p) if err != nil { @@ -285,8 +289,8 @@ func (ud UserDiscovery) SearchSingle(client *Client, f string, callback SingleSe } rids, _, err := udPackage.Search(client.api.GetNetworkInterface(), - client.api.GetEventManager(), - stream, client.api.GetE2e().GetGroup(), udContact, + client.api.GetEventReporter(), + stream, client.api.GetE2EHandler().GetGroup(), udContact, cb, []fact.Fact{fObj}, p) if err != nil { @@ -361,7 +365,7 @@ func (ud UserDiscovery) Lookup(client *Client, } rid, _, err := udPackage.Lookup(client.api.GetNetworkInterface(), - stream, client.api.GetE2e().GetGroup(), + stream, client.api.GetE2EHandler().GetGroup(), udContact, cb, uid, p) @@ -447,7 +451,7 @@ func (ud UserDiscovery) MultiLookup(client *Client, stream := client.api.GetRng().GetStream() defer stream.Close() _, _, err := udPackage.Lookup(client.api.GetNetworkInterface(), - stream, client.api.GetE2e().GetGroup(), + stream, client.api.GetE2EHandler().GetGroup(), udContact, cb, localID, p) if err != nil { results <- lookupResponse{ diff --git a/cmd/group.go b/cmd/group.go index df0c3902b..1f7e11408 100644 --- a/cmd/group.go +++ b/cmd/group.go @@ -112,7 +112,7 @@ var groupCmd = &cobra.Command{ // initGroupManager creates a new group chat manager and starts the process // service. -func initGroupManager(client *api.Client) (*groupChat.Manager, +func initGroupManager(client *api.Client) (groupChat.GroupChat, chan groupChat.MessageReceive, chan groupStore.Group) { recChan := make(chan groupChat.MessageReceive, 10) receiveCb := func(msg groupChat.MessageReceive) { @@ -138,7 +138,7 @@ func initGroupManager(client *api.Client) (*groupChat.Manager, // createGroup creates a new group with the provided name and sends out requests // to the list of user IDs found at the given file path. -func createGroup(name, msg []byte, filePath string, gm *groupChat.Manager) { +func createGroup(name, msg []byte, filePath string, gm groupChat.GroupChat) { userIdStrings := ReadLines(filePath) userIDs := make([]*id.ID, 0, len(userIdStrings)) for _, userIdStr := range userIdStrings { @@ -160,7 +160,7 @@ func createGroup(name, msg []byte, filePath string, gm *groupChat.Manager) { } // resendRequests resends group requests for the group ID. -func resendRequests(groupIdString string, gm *groupChat.Manager) { +func resendRequests(groupIdString string, gm groupChat.GroupChat) { groupID, _ := parseRecipient(groupIdString) rids, status, err := gm.ResendRequest(groupID) if err != nil { @@ -176,7 +176,7 @@ func resendRequests(groupIdString string, gm *groupChat.Manager) { // joinGroup joins a group when a request is received on the group request // channel. func joinGroup(reqChan chan groupStore.Group, timeout time.Duration, - gm *groupChat.Manager) { + gm groupChat.GroupChat) { jww.INFO.Print("Waiting for group request to be received.") fmt.Println("Waiting for group request to be received.") @@ -198,7 +198,7 @@ func joinGroup(reqChan chan groupStore.Group, timeout time.Duration, } // leaveGroup leaves the group. -func leaveGroup(groupIdString string, gm *groupChat.Manager) { +func leaveGroup(groupIdString string, gm groupChat.GroupChat) { groupID, _ := parseRecipient(groupIdString) jww.INFO.Printf("Leaving group %s.", groupID) @@ -212,7 +212,7 @@ func leaveGroup(groupIdString string, gm *groupChat.Manager) { } // sendGroup send the message to the group. -func sendGroup(groupIdString string, msg []byte, gm *groupChat.Manager) { +func sendGroup(groupIdString string, msg []byte, gm groupChat.GroupChat) { groupID, _ := parseRecipient(groupIdString) jww.INFO.Printf("Sending to group %s message %q", groupID, msg) @@ -249,7 +249,7 @@ func messageWait(numMessages uint, timeout time.Duration, } // listGroups prints a list of all groups. -func listGroups(gm *groupChat.Manager) { +func listGroups(gm groupChat.GroupChat) { for i, gid := range gm.GetGroups() { jww.INFO.Printf("Group %d: %s", i, gid) } @@ -258,7 +258,7 @@ func listGroups(gm *groupChat.Manager) { } // showGroup prints all the information of the group. -func showGroup(groupIdString string, gm *groupChat.Manager) { +func showGroup(groupIdString string, gm groupChat.GroupChat) { groupID, _ := parseRecipient(groupIdString) grp, ok := gm.GetGroup(groupID) diff --git a/cmd/ud.go b/cmd/ud.go index 9a7466373..431f774f3 100644 --- a/cmd/ud.go +++ b/cmd/ud.go @@ -10,6 +10,13 @@ package cmd import ( "fmt" + "gitlab.com/elixxir/client/single" + "gitlab.com/elixxir/client/ud" + "gitlab.com/elixxir/client/xxmutils" + "gitlab.com/elixxir/primitives/fact" + "gitlab.com/xx_network/primitives/utils" + "strings" + "time" "github.com/spf13/cobra" jww "github.com/spf13/jwalterweatherman" @@ -26,12 +33,12 @@ var udCmd = &cobra.Command{ Short: "Register for and search users using the xx network user discovery service.", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - // client := initClient() + client := initClient() - // // get user and save contact to file - // user := client.GetUser() - // jww.INFO.Printf("User: %s", user.ReceptionID) - // writeContact(user.GetContact()) + // get user and save contact to file + user := client.GetUser() + jww.INFO.Printf("User: %s", user.ReceptionID) + writeContact(user.GetContact()) // // Set up reception handler // swBoard := client.GetSwitchboard() @@ -57,194 +64,211 @@ var udCmd = &cobra.Command{ // }) // } - // err := client.StartNetworkFollower(50 * time.Millisecond) - // if err != nil { - // jww.FATAL.Panicf("%+v", err) - // } - - // // Wait until connected or crash on timeout - // connected := make(chan bool, 10) - // client.GetHealth().AddChannel(connected) - // waitUntilConnected(connected) - - // // Make single-use manager and start receiving process - // singleMng := old.NewManager(client) - // err = client.AddService(singleMng.StartProcesses) - // if err != nil { - // jww.FATAL.Panicf("Failed to add single use process: %+v", err) - // } - - // // Make user discovery manager - // userDiscoveryMgr, err := ud.NewManager(client, singleMng) - // if err != nil { - // jww.FATAL.Panicf("Failed to create new UD manager: %+v", err) - // } - - // userToRegister := viper.GetString("register") - // if userToRegister != "" { - // err = userDiscoveryMgr.Register(userToRegister) - // if err != nil { - // fmt.Printf("Failed to register user %s: %s\n", - // userToRegister, err.Error()) - // jww.FATAL.Panicf("Failed to register user %s: %+v", userToRegister, err) - // } - // } - - // var newFacts fact.FactList - // phone := viper.GetString("addphone") - // if phone != "" { - // f, err := fact.NewFact(fact.Phone, phone) - // if err != nil { - // jww.FATAL.Panicf("Failed to create new fact: %+v", err) - // } - // newFacts = append(newFacts, f) - // } - - // email := viper.GetString("addemail") - // if email != "" { - // f, err := fact.NewFact(fact.Email, email) - // if err != nil { - // jww.FATAL.Panicf("Failed to create new fact: %+v", err) - // } - // newFacts = append(newFacts, f) - // } - - // for i := 0; i < len(newFacts); i++ { - // r, err := userDiscoveryMgr.SendRegisterFact(newFacts[i]) - // if err != nil { - // fmt.Printf("Failed to register fact: %s\n", - // newFacts[i]) - // jww.FATAL.Panicf("Failed to send register fact: %+v", err) - // } - // // TODO Store the code? - // jww.INFO.Printf("Fact Add Response: %+v", r) - // } - - // confirmID := viper.GetString("confirm") - // if confirmID != "" { - // err = userDiscoveryMgr.SendConfirmFact(confirmID, confirmID) - // if err != nil { - // fmt.Printf("Couldn't confirm fact: %s\n", - // err.Error()) - // jww.FATAL.Panicf("%+v", err) - // } - // } - - // // Handle lookup (verification) process - // // Note: Cryptographic verification occurs above the bindings layer - // lookupIDStr := viper.GetString("lookup") - // if lookupIDStr != "" { - // lookupID, _ := parseRecipient(lookupIDStr) - // //if !ok { - // // jww.FATAL.Panicf("Could not parse recipient: %s", lookupIDStr) - // //} - // err = userDiscoveryMgr.Lookup(lookupID, - // func(newContact contact.Contact, err error) { - // if err != nil { - // jww.FATAL.Panicf("UserDiscovery Lookup error: %+v", err) - // } - // printContact(newContact) - // }, 30*time.Second) - - // if err != nil { - // jww.WARN.Printf("Failed UD lookup: %+v", err) - // } - - // time.Sleep(31 * time.Second) - // } - - // if viper.GetString("batchadd") != "" { - // idListFile, err := utils.ReadFile(viper.GetString("batchadd")) - // if err != nil { - // fmt.Printf("BATCHADD: Couldn't read file: %s\n", - // err.Error()) - // jww.FATAL.Panicf("BATCHADD: Couldn't read file: %+v", err) - // } - // restored, _, _, err := xxmutils.RestoreContactsFromBackup( - // idListFile, client, userDiscoveryMgr, nil) - // if err != nil { - // jww.FATAL.Panicf("%+v", err) - // } - // for i := 0; i < len(restored); i++ { - // uid := restored[i] - // for !client.HasAuthenticatedChannel(uid) { - // time.Sleep(time.Second) - // } - // jww.INFO.Printf("Authenticated channel established for %s", uid) - // } - // } - // usernameSearchStr := viper.GetString("searchusername") - // emailSearchStr := viper.GetString("searchemail") - // phoneSearchStr := viper.GetString("searchphone") - - // var facts fact.FactList - // if usernameSearchStr != "" { - // f, err := fact.NewFact(fact.Username, usernameSearchStr) - // if err != nil { - // jww.FATAL.Panicf("Failed to create new fact: %+v", err) - // } - // facts = append(facts, f) - // } - // if emailSearchStr != "" { - // f, err := fact.NewFact(fact.Email, emailSearchStr) - // if err != nil { - // jww.FATAL.Panicf("Failed to create new fact: %+v", err) - // } - // facts = append(facts, f) - // } - // if phoneSearchStr != "" { - // f, err := fact.NewFact(fact.Phone, phoneSearchStr) - // if err != nil { - // jww.FATAL.Panicf("Failed to create new fact: %+v", err) - // } - // facts = append(facts, f) - // } - - // userToRemove := viper.GetString("remove") - // if userToRemove != "" { - // f, err := fact.NewFact(fact.Username, userToRemove) - // if err != nil { - // jww.FATAL.Panicf( - // "Failed to create new fact: %+v", err) - // } - // err = userDiscoveryMgr.RemoveUser(f) - // if err != nil { - // fmt.Printf("Couldn't remove user %s\n", - // userToRemove) - // jww.FATAL.Panicf( - // "Failed to remove user %s: %+v", - // userToRemove, err) - // } - // fmt.Printf("Removed user from discovery: %s\n", - // userToRemove) - // } - - // if len(facts) == 0 { - // err = client.StopNetworkFollower() - // if err != nil { - // jww.WARN.Print(err) - // } - // return - // } - - // err = userDiscoveryMgr.Search(facts, - // func(contacts []contact.Contact, err error) { - // if err != nil { - // jww.FATAL.Panicf("%+v", err) - // } - // for _, c := range contacts { - // printContact(c) - // } - // }, 90*time.Second) - // if err != nil { - // jww.FATAL.Panicf("%+v", err) - // } - - // time.Sleep(91 * time.Second) - // err = client.StopNetworkFollower() - // if err != nil { - // jww.WARN.Print(err) - // } + err := client.StartNetworkFollower(50 * time.Millisecond) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + + // Wait until connected or crash on timeout + connected := make(chan bool, 10) + client.GetNetworkInterface().AddHealthCallback( + func(isconnected bool) { + connected <- isconnected + }) + waitUntilConnected(connected) + + // Make user discovery manager + stream := client.GetRng().GetStream() + defer stream.Close() + userToRegister := viper.GetString("register") + userDiscoveryMgr, err := ud.NewManager(client.GetNetworkInterface(), + client.GetE2EHandler(), client.NetworkFollowerStatus, + client.GetEventReporter(), + client.GetComms(), client.GetStorage(), + stream, + userToRegister, client.GetStorage().GetKV()) + if err != nil { + if strings.Contains(err.Error(), ud.IsRegisteredErr) { + userDiscoveryMgr, err = ud.LoadManager(client.GetNetworkInterface(), + client.GetE2EHandler(), client.GetEventReporter(), + client.GetComms(), + client.GetStorage(), client.GetStorage().GetKV()) + if err != nil { + jww.FATAL.Panicf("Failed to load UD manager: %+v", err) + } + } else { + jww.FATAL.Panicf("Failed to create new UD manager: %+v", err) + + } + } + + var newFacts fact.FactList + phone := viper.GetString("addphone") + if phone != "" { + f, err := fact.NewFact(fact.Phone, phone) + if err != nil { + jww.FATAL.Panicf("Failed to create new fact: %+v", err) + } + newFacts = append(newFacts, f) + } + + email := viper.GetString("addemail") + if email != "" { + f, err := fact.NewFact(fact.Email, email) + if err != nil { + jww.FATAL.Panicf("Failed to create new fact: %+v", err) + } + newFacts = append(newFacts, f) + } + + for i := 0; i < len(newFacts); i++ { + r, err := userDiscoveryMgr.SendRegisterFact(newFacts[i]) + if err != nil { + fmt.Printf("Failed to register fact: %s\n", + newFacts[i]) + jww.FATAL.Panicf("Failed to send register fact: %+v", err) + } + // TODO Store the code? + jww.INFO.Printf("Fact Add Response: %+v", r) + } + + confirmID := viper.GetString("confirm") + if confirmID != "" { + err = userDiscoveryMgr.ConfirmFact(confirmID, confirmID) + if err != nil { + fmt.Printf("Couldn't confirm fact: %s\n", + err.Error()) + jww.FATAL.Panicf("%+v", err) + } + } + + udContact, err := userDiscoveryMgr.GetContact() + if err != nil { + fmt.Printf("Failed to get user discovery contact object: %+v", err) + jww.FATAL.Printf("Failed to get user discovery contact object: %+v", err) + } + + // Handle lookup (verification) process + // Note: Cryptographic verification occurs above the bindings layer + lookupIDStr := viper.GetString("lookup") + if lookupIDStr != "" { + lookupID, _ := parseRecipient(lookupIDStr) + //if !ok { + // jww.FATAL.Panicf("Could not parse recipient: %s", lookupIDStr) + //} + + cb := func(newContact contact.Contact, err error) { + if err != nil { + jww.FATAL.Panicf("UserDiscovery Lookup error: %+v", err) + } + printContact(newContact) + } + _, _, err = ud.Lookup(client.GetNetworkInterface(), + stream, client.GetE2EHandler().GetGroup(), + udContact, cb, lookupID, single.GetDefaultRequestParams()) + if err != nil { + jww.WARN.Printf("Failed UD lookup: %+v", err) + } + + time.Sleep(31 * time.Second) + } + + if viper.GetString("batchadd") != "" { + idListFile, err := utils.ReadFile(viper.GetString("batchadd")) + if err != nil { + fmt.Printf("BATCHADD: Couldn't read file: %s\n", + err.Error()) + jww.FATAL.Panicf("BATCHADD: Couldn't read file: %+v", err) + } + restored, _, _, err := xxmutils.RestoreContactsFromBackup( + idListFile, client, userDiscoveryMgr, nil) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + for i := 0; i < len(restored); i++ { + uid := restored[i] + for !client.HasAuthenticatedChannel(uid) { + time.Sleep(time.Second) + } + jww.INFO.Printf("Authenticated channel established for %s", uid) + } + } + usernameSearchStr := viper.GetString("searchusername") + emailSearchStr := viper.GetString("searchemail") + phoneSearchStr := viper.GetString("searchphone") + + var facts fact.FactList + if usernameSearchStr != "" { + f, err := fact.NewFact(fact.Username, usernameSearchStr) + if err != nil { + jww.FATAL.Panicf("Failed to create new fact: %+v", err) + } + facts = append(facts, f) + } + if emailSearchStr != "" { + f, err := fact.NewFact(fact.Email, emailSearchStr) + if err != nil { + jww.FATAL.Panicf("Failed to create new fact: %+v", err) + } + facts = append(facts, f) + } + if phoneSearchStr != "" { + f, err := fact.NewFact(fact.Phone, phoneSearchStr) + if err != nil { + jww.FATAL.Panicf("Failed to create new fact: %+v", err) + } + facts = append(facts, f) + } + + userToRemove := viper.GetString("remove") + if userToRemove != "" { + f, err := fact.NewFact(fact.Username, userToRemove) + if err != nil { + jww.FATAL.Panicf( + "Failed to create new fact: %+v", err) + } + err = userDiscoveryMgr.PermanentDeleteAccount(f) + if err != nil { + fmt.Printf("Couldn't remove user %s\n", + userToRemove) + jww.FATAL.Panicf( + "Failed to remove user %s: %+v", + userToRemove, err) + } + fmt.Printf("Removed user from discovery: %s\n", + userToRemove) + } + + if len(facts) == 0 { + err = client.StopNetworkFollower() + if err != nil { + jww.WARN.Print(err) + } + return + } + + cb := func(contacts []contact.Contact, err error) { + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + for _, c := range contacts { + printContact(c) + } + } + + _, _, err = ud.Search(client.GetNetworkInterface(), + client.GetEventReporter(), + stream, client.GetE2EHandler().GetGroup(), + udContact, cb, facts, single.GetDefaultRequestParams()) + if err != nil { + jww.FATAL.Panicf("%+v", err) + } + + time.Sleep(91 * time.Second) + err = client.StopNetworkFollower() + if err != nil { + jww.WARN.Print(err) + } }, } diff --git a/cmix/remoteFilters.go b/cmix/remoteFilters.go index 45afbd1a3..37cf100e6 100644 --- a/cmix/remoteFilters.go +++ b/cmix/remoteFilters.go @@ -25,10 +25,10 @@ func NewRemoteFilter(data *mixmessages.ClientBloom) *RemoteFilter { type RemoteFilter struct { data *mixmessages.ClientBloom - filter *bloom.Ring + filter *bloom.Bloom } -func (rf *RemoteFilter) GetFilter() *bloom.Ring { +func (rf *RemoteFilter) GetFilter() *bloom.Bloom { if rf.filter == nil { var err error diff --git a/go.mod b/go.mod index 412d59c59..5cc7bdbc9 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/spf13/cobra v1.1.1 github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/viper v1.7.1 - gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 + gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f gitlab.com/elixxir/comms v0.0.4-0.20220323190139-9ed75f3a8b2c gitlab.com/elixxir/crypto v0.0.7-0.20220425192911-a23209a58073 gitlab.com/elixxir/ekv v0.1.7 diff --git a/go.sum b/go.sum index 449abdbda..b2b24d4d7 100644 --- a/go.sum +++ b/go.sum @@ -274,6 +274,8 @@ github.com/zeebo/pcg v1.0.0 h1:dt+dx+HvX8g7Un32rY9XWoYnd0NmKmrIzpHF7qiTDj0= github.com/zeebo/pcg v1.0.0/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228 h1:Gi6rj4mAlK0BJIk1HIzBVMjWNjIUfstrsXC2VqLYPcA= gitlab.com/elixxir/bloomfilter v0.0.0-20200930191214-10e9ac31b228/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k= +gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f h1:yXGvNBqzZwAhDYlSnxPRbgor6JWoOt1Z7s3z1O9JR40= +gitlab.com/elixxir/bloomfilter v0.0.0-20211222005329-7d931ceead6f/go.mod h1:H6jztdm0k+wEV2QGK/KYA+MY9nj9Zzatux/qIvDDv3k= gitlab.com/elixxir/comms v0.0.4-0.20220308183624-c2183e687a03 h1:4eNjO3wCyHgxpGeq2zgDb5SsdTcQaG5IZjBOuEL6KgM= gitlab.com/elixxir/comms v0.0.4-0.20220308183624-c2183e687a03/go.mod h1:4yMdU+Jee5W9lqkZGHJAuipEhW7FloT0eyVEFUJza+E= gitlab.com/elixxir/comms v0.0.4-0.20220323190139-9ed75f3a8b2c h1:ajjTw08YjRjl3HvtBNGtoCWhOg8k8upqmTweH18wkC4= @@ -283,6 +285,8 @@ gitlab.com/elixxir/crypto v0.0.3/go.mod h1:ZNgBOblhYToR4m8tj4cMvJ9UsJAUKq+p0gCp0 gitlab.com/elixxir/crypto v0.0.7-0.20220222221347-95c7ae58da6b/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10= gitlab.com/elixxir/crypto v0.0.7-0.20220309234716-1ba339865787 h1:+qmsWov412+Yn7AKUhTbOcDgAydNXlNLPmFpO2W5LwY= gitlab.com/elixxir/crypto v0.0.7-0.20220309234716-1ba339865787/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10= +gitlab.com/elixxir/crypto v0.0.7-0.20220317172048-3de167bd9406 h1:PRA8OJMXuy9JZmUuZ442AIE/tWY7HisqezyLNhpZZ9w= +gitlab.com/elixxir/crypto v0.0.7-0.20220317172048-3de167bd9406/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10= gitlab.com/elixxir/crypto v0.0.7-0.20220325215559-7489d68d7714 h1:epnov8zyFWod14MUNtGHSbZCVSkZjN4NvoiBs1TgEV8= gitlab.com/elixxir/crypto v0.0.7-0.20220325215559-7489d68d7714/go.mod h1:tD6XjtQh87T2nKZL5I/pYPck5M2wLpkZ1Oz7H/LqO10= gitlab.com/elixxir/crypto v0.0.7-0.20220325224306-705ce59288bb h1:WdlmG+KPaM2Pjo1EFiFFPYEVSMV64Di1CitQnXGWBOQ= diff --git a/groupChat/group.go b/groupChat/group.go index 8878a62cd..80f98edc0 100644 --- a/groupChat/group.go +++ b/groupChat/group.go @@ -21,6 +21,7 @@ package groupChat import ( gs "gitlab.com/elixxir/client/groupChat/groupStore" + "gitlab.com/elixxir/crypto/group" "gitlab.com/xx_network/primitives/id" "time" ) @@ -52,7 +53,8 @@ type GroupChat interface { // Send sends a message to all GroupChat members using Client.SendManyCMIX. // The send fails if the message is too long. Returns the ID of the round // sent on and the timestamp of the message send. - Send(groupID *id.ID, message []byte) (id.Round, time.Time, error) + Send(groupID *id.ID, tag string, message []byte) ( + id.Round, time.Time, group.MessageID, error) // GetGroups returns a list of all registered GroupChat IDs. GetGroups() []*id.ID @@ -63,6 +65,15 @@ type GroupChat interface { // NumGroups returns the number of groups the user is a part of. NumGroups() int + + /* ===== Services ======================================================= */ + + // AddService adds a service for all group chat partners of the given tag, + // which will call back on the given processor. + AddService(g gs.Group, tag string, p Processor) + + // RemoveService removes all services for the given tag. + RemoveService(g gs.Group, tag string, p Processor) } // RequestCallback is called when a GroupChat request is received. diff --git a/groupChat/groupStore/group.go b/groupChat/groupStore/group.go index 28b9555e3..2c7d3e917 100644 --- a/groupChat/groupStore/group.go +++ b/groupChat/groupStore/group.go @@ -244,17 +244,17 @@ func (g Group) GoString() string { idString = g.ID.String() } - str := make([]string, 9) - - str[0] = "Name:" + fmt.Sprintf("%q", g.Name) - str[1] = "ID:" + idString - str[2] = "Key:" + g.Key.String() - str[3] = "IdPreimage:" + g.IdPreimage.String() - str[4] = "KeyPreimage:" + g.KeyPreimage.String() - str[5] = "InitMessage:" + fmt.Sprintf("%q", g.InitMessage) - str[6] = "Created:" + g.Created.String() - str[7] = "Members:" + g.Members.String() - str[8] = "DhKeys:" + g.DhKeys.GoString() + str := []string{ + "Name:" + fmt.Sprintf("%q", g.Name), + "ID:" + idString, + "Key:" + g.Key.String(), + "IdPreimage:" + g.IdPreimage.String(), + "KeyPreimage:" + g.KeyPreimage.String(), + "InitMessage:" + fmt.Sprintf("%q", g.InitMessage), + "Created:" + g.Created.String(), + "Members:" + g.Members.String(), + "DhKeys:" + g.DhKeys.GoString(), + } return "{" + strings.Join(str, ", ") + "}" } diff --git a/groupChat/groupStore/store_test.go b/groupChat/groupStore/store_test.go index e19b3928b..2f52d9a31 100644 --- a/groupChat/groupStore/store_test.go +++ b/groupChat/groupStore/store_test.go @@ -24,7 +24,7 @@ import ( // Unit test of NewStore. func TestNewStore(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) expectedStore := &Store{ @@ -90,7 +90,7 @@ func TestNewStore(t *testing.T) { func TestNewOrLoadStore(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) store, err := NewOrLoadStore(kv, user) @@ -126,7 +126,7 @@ func TestNewOrLoadStore(t *testing.T) { // Unit test of LoadStore. func TestLoadStore(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) store, err := NewStore(kv, user) @@ -162,7 +162,7 @@ func TestLoadStore(t *testing.T) { // Error path: show that LoadStore returns an error when no group store can be // found in storage. func TestLoadStore_GetError(t *testing.T) { - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(rand.New(rand.NewSource(42))) expectedErr := strings.SplitN(kvGetGroupListErr, "%", 2)[0] @@ -177,7 +177,7 @@ func TestLoadStore_GetError(t *testing.T) { // Error path: show that loadStore returns an error when no group can be found // in storage. func Test_loadStore_GetGroupError(t *testing.T) { - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(rand.New(rand.NewSource(42))) var idList []byte for i := 0; i < 10; i++ { @@ -249,7 +249,7 @@ func TestStore_Len(t *testing.T) { // Unit test of Store.Add. func TestStore_Add(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) store, err := NewStore(kv, user) @@ -281,7 +281,7 @@ func TestStore_Add(t *testing.T) { // groups. func TestStore_Add_MapFullError(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) expectedErr := strings.SplitN(maxGroupsErr, "%", 2)[0] @@ -309,7 +309,7 @@ func TestStore_Add_MapFullError(t *testing.T) { // that is already in the map. func TestStore_Add_GroupExistsError(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) expectedErr := strings.SplitN(groupExistsErr, "%", 2)[0] @@ -334,7 +334,7 @@ func TestStore_Add_GroupExistsError(t *testing.T) { // Unit test of Store.Remove. func TestStore_Remove(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) store, err := NewStore(kv, user) @@ -374,7 +374,7 @@ func TestStore_Remove(t *testing.T) { // given ID is found in the map. func TestStore_Remove_RemoveGroupNotInMemoryError(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) expectedErr := strings.SplitN(groupRemoveErr, "%", 2)[0] @@ -423,7 +423,7 @@ func TestStore_GroupIDs(t *testing.T) { // Unit test of Store.Get. func TestStore_Get(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) store, err := NewStore(kv, user) @@ -451,7 +451,7 @@ func TestStore_Get(t *testing.T) { // Error path: shows that Store.Get return false if no group is found. func TestStore_Get_NoGroupError(t *testing.T) { - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(rand.New(rand.NewSource(42))) store, err := NewStore(kv, user) @@ -469,7 +469,7 @@ func TestStore_Get_NoGroupError(t *testing.T) { // Unit test of Store.GetByKeyFp. func TestStore_GetByKeyFp(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) store, err := NewStore(kv, user) @@ -502,7 +502,7 @@ func TestStore_GetByKeyFp(t *testing.T) { // Error path: shows that Store.GetByKeyFp return false if no group is found. func TestStore_GetByKeyFp_NoGroupError(t *testing.T) { prng := rand.New(rand.NewSource(42)) - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(prng) store, err := NewStore(kv, user) @@ -523,7 +523,7 @@ func TestStore_GetByKeyFp_NoGroupError(t *testing.T) { // Unit test of Store.GetUser. func TestStore_GetUser(t *testing.T) { - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) user := randMember(rand.New(rand.NewSource(42))) store, err := NewStore(kv, user) @@ -539,7 +539,7 @@ func TestStore_GetUser(t *testing.T) { // Unit test of Store.SetUser. func TestStore_SetUser(t *testing.T) { - kv := versioned.NewKV(make(ekv.Memstore)) + kv := versioned.NewKV(ekv.MakeMemstore()) prng := rand.New(rand.NewSource(42)) oldUser := randMember(prng) newUser := randMember(prng) diff --git a/groupChat/makeGroup.go b/groupChat/makeGroup.go index 32be2b831..e7bee9697 100644 --- a/groupChat/makeGroup.go +++ b/groupChat/makeGroup.go @@ -50,7 +50,7 @@ const ( // each member of the groupChat to add them to the groupChat. It blocks until // all the groupChat requests are sent. Returns an error if at least one request // to a member fails to send. -func (m Manager) MakeGroup(membership []*id.ID, name, msg []byte) (gs.Group, +func (m *manager) MakeGroup(membership []*id.ID, name, msg []byte) (gs.Group, []id.Round, RequestStatus, error) { // Return an error if the message is too long if len(msg) > MaxInitMessageSize { @@ -81,7 +81,7 @@ func (m Manager) MakeGroup(membership []*id.ID, name, msg []byte) (gs.Group, g := gs.NewGroup( name, groupID, groupKey, idPreimage, keyPreimage, msg, created, mem, dkl) - jww.DEBUG.Printf("Created new group %q with ID %s and %d members %s", + jww.DEBUG.Printf("[GC] Created new group %q with ID %s and %d members %s", g.Name, g.ID, len(g.Members), g.Members) // Send all group requests @@ -96,7 +96,7 @@ func (m Manager) MakeGroup(membership []*id.ID, name, msg []byte) (gs.Group, // buildMembership retrieves the contact object for each member ID and creates a // new membership from them. The caller is set as the leader. For a member to be // added, the group leader must have an authenticated channel with the member. -func (m Manager) buildMembership(members []*id.ID) (group.Membership, +func (m *manager) buildMembership(members []*id.ID) (group.Membership, gs.DhKeyList, error) { // Return an error if the membership list has too few or too many members if len(members) < group.MinParticipants { diff --git a/groupChat/makeGroup_test.go b/groupChat/makeGroup_test.go index a9541b844..7ccccf4fa 100644 --- a/groupChat/makeGroup_test.go +++ b/groupChat/makeGroup_test.go @@ -25,8 +25,8 @@ import ( "testing" ) -// Tests that Manager.MakeGroup adds a group and returns the expected status. -func TestManager_MakeGroup(t *testing.T) { +// Tests that manager.MakeGroup adds a group and returns the expected status. +func Test_manager_MakeGroup(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t) memberIDs, members, dkl := addPartners(m, t) @@ -76,7 +76,7 @@ func TestManager_MakeGroup(t *testing.T) { // Error path: make sure an error and the correct status is returned when the // message is too large. -func TestManager_MakeGroup_MaxMessageSizeError(t *testing.T) { +func Test_manager_MakeGroup_MaxMessageSizeError(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t) expectedErr := fmt.Sprintf( @@ -96,7 +96,7 @@ func TestManager_MakeGroup_MaxMessageSizeError(t *testing.T) { // Error path: make sure an error and the correct status is returned when the // membership list is too small. -func TestManager_MakeGroup_MembershipSizeError(t *testing.T) { +func Test_manager_MakeGroup_MembershipSizeError(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t) expectedErr := fmt.Sprintf( @@ -117,7 +117,7 @@ func TestManager_MakeGroup_MembershipSizeError(t *testing.T) { // Error path: make sure an error and the correct status is returned when adding // a group failed because the user is a part of too many groups already. -func TestManager_MakeGroup_AddGroupError(t *testing.T) { +func Test_manager_MakeGroup_AddGroupError(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, gs.MaxGroupChats, 0, nil, nil, t) memberIDs, _, _ := addPartners(m, t) @@ -130,8 +130,8 @@ func TestManager_MakeGroup_AddGroupError(t *testing.T) { } } -// Unit test of Manager.buildMembership. -func TestManager_buildMembership(t *testing.T) { +// Unit test of manager.buildMembership. +func Test_manager_buildMembership(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManager(prng, t) memberIDs, expected, expectedDKL := addPartners(m, t) @@ -154,7 +154,7 @@ func TestManager_buildMembership(t *testing.T) { // Error path: an error is returned when the number of members in the membership // list is too few. -func TestManager_buildMembership_MinParticipantsError(t *testing.T) { +func Test_manager_buildMembership_MinParticipantsError(t *testing.T) { m, _ := newTestManager(rand.New(rand.NewSource(42)), t) memberIDs := make([]*id.ID, group.MinParticipants-1) expectedErr := fmt.Sprintf( @@ -169,7 +169,7 @@ func TestManager_buildMembership_MinParticipantsError(t *testing.T) { // Error path: an error is returned when the number of members in the membership // list is too many. -func TestManager_buildMembership_MaxParticipantsError(t *testing.T) { +func Test_manager_buildMembership_MaxParticipantsError(t *testing.T) { m, _ := newTestManager(rand.New(rand.NewSource(42)), t) memberIDs := make([]*id.ID, group.MaxParticipants+1) expectedErr := fmt.Sprintf( @@ -183,7 +183,7 @@ func TestManager_buildMembership_MaxParticipantsError(t *testing.T) { } // Error path: error returned when a partner cannot be found -func TestManager_buildMembership_GetPartnerContactError(t *testing.T) { +func Test_manager_buildMembership_GetPartnerContactError(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManager(prng, t) memberIDs, _, _ := addPartners(m, t) @@ -200,7 +200,7 @@ func TestManager_buildMembership_GetPartnerContactError(t *testing.T) { } // Error path: error returned when a member ID appears twice on the list. -func TestManager_buildMembership_DuplicateContactError(t *testing.T) { +func Test_manager_buildMembership_DuplicateContactError(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManager(prng, t) memberIDs, _, _ := addPartners(m, t) @@ -281,7 +281,7 @@ func TestRequestStatus_Message(t *testing.T) { // addPartners returns a list of user IDs and their matching membership and adds // them as partners. -func addPartners(m *Manager, t *testing.T) ([]*id.ID, group.Membership, +func addPartners(m *manager, t *testing.T) ([]*id.ID, group.Membership, gs.DhKeyList) { memberIDs := make([]*id.ID, 10) members := group.Membership{m.gs.GetUser()} diff --git a/groupChat/manager.go b/groupChat/manager.go index 19c4de8bb..9b018013e 100644 --- a/groupChat/manager.go +++ b/groupChat/manager.go @@ -36,37 +36,36 @@ const ( leaveGroupErr = "failed to leave group %s: %+v" ) -// GroupCmix is a subset of the cmix.Client interface containing only the methods needed by GroupChat +// GroupCmix is a subset of the cmix.Client interface containing only the +// methods needed by GroupChat type GroupCmix interface { SendMany(messages []cmix.TargetedCmixMessage, p cmix.CMIXParams) ( id.Round, []ephemeral.Id, error) - AddService(clientID *id.ID, newService message.Service, - response message.Processor) - DeleteService(clientID *id.ID, toDelete message.Service, - processor message.Processor) + AddService( + clientID *id.ID, newService message.Service, response message.Processor) + DeleteService( + clientID *id.ID, toDelete message.Service, processor message.Processor) GetMaxMessageLength() int } -// GroupE2e is a subset of the e2e.Handler interface containing only the methods needed by GroupChat +// GroupE2e is a subset of the e2e.Handler interface containing only the methods +// needed by GroupChat type GroupE2e interface { SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, params e2e.Params) ([]id.Round, crypto.MessageID, time.Time, error) - RegisterListener(senderID *id.ID, - messageType catalog.MessageType, + RegisterListener(senderID *id.ID, messageType catalog.MessageType, newListener receive.Listener) receive.ListenerID AddService(tag string, processor message.Processor) error - AddPartner(partnerID *id.ID, - partnerPubKey, myPrivKey *cyclic.Int, - partnerSIDHPubKey *sidh.PublicKey, - mySIDHPrivKey *sidh.PrivateKey, sendParams, - receiveParams session.Params) (partner.Manager, error) + AddPartner(partnerID *id.ID, partnerPubKey, myPrivKey *cyclic.Int, + partnerSIDHPubKey *sidh.PublicKey, mySIDHPrivKey *sidh.PrivateKey, + sendParams, receiveParams session.Params) (partner.Manager, error) GetPartner(partnerID *id.ID) (partner.Manager, error) GetHistoricalDHPubkey() *cyclic.Int GetHistoricalDHPrivkey() *cyclic.Int } -// Manager handles the list of groups a user is a part of. -type Manager struct { +// manager handles the list of groups a user is a part of. +type manager struct { e2e GroupE2e receptionId *id.ID @@ -82,7 +81,7 @@ type Manager struct { // NewManager creates a new group chat manager func NewManager(services GroupCmix, e2e GroupE2e, receptionId *id.ID, rng *fastRNG.StreamGenerator, grp *cyclic.Group, kv *versioned.KV, - requestFunc RequestCallback, receiveFunc ReceiveCallback) (*Manager, error) { + requestFunc RequestCallback, receiveFunc ReceiveCallback) (GroupChat, error) { // Load the group chat storage or create one if one does not exist gStore, err := gs.NewOrLoadStore( @@ -92,7 +91,7 @@ func NewManager(services GroupCmix, e2e GroupE2e, receptionId *id.ID, } // Define the manager object - m := &Manager{ + m := &manager{ e2e: e2e, rng: rng, receptionId: receptionId, @@ -104,7 +103,8 @@ func NewManager(services GroupCmix, e2e GroupE2e, receptionId *id.ID, } // Register listener for incoming e2e group chat requests - e2e.RegisterListener(&id.ZeroUser, catalog.GroupCreationRequest, &requestListener{m: m}) + e2e.RegisterListener( + &id.ZeroUser, catalog.GroupCreationRequest, &requestListener{m}) // Register notifications listener for incoming e2e group chat requests err = e2e.AddService(catalog.GroupRq, nil) @@ -116,11 +116,11 @@ func NewManager(services GroupCmix, e2e GroupE2e, receptionId *id.ID, for _, gId := range m.GetGroups() { g, exists := m.GetGroup(gId) if !exists { - jww.WARN.Printf("Unexpected failure to locate GroupID %s", gId.String()) + jww.WARN.Printf("[GC] Unexpected failure to locate GroupID %s", gId) continue } - m.joinGroup(g) + m.AddService(g, "", nil) } return m, nil @@ -129,28 +129,18 @@ func NewManager(services GroupCmix, e2e GroupE2e, receptionId *id.ID, // JoinGroup adds the group to storage, and enables requisite services. // An error is returned if the user is already part of the group or if the // maximum number of groups have already been joined. -func (m Manager) JoinGroup(g gs.Group) error { +func (m *manager) JoinGroup(g gs.Group) error { if err := m.gs.Add(g); err != nil { return errors.Errorf(joinGroupErr, g.ID, err) } - m.joinGroup(g) - jww.DEBUG.Printf("Joined group %q with ID %s.", g.Name, g.ID) + m.AddService(g, "", nil) + jww.INFO.Printf("[GC] Joined group %q with ID %s.", g.Name, g.ID) return nil } -// joinGroup adds the group services -func (m Manager) joinGroup(g gs.Group) { - newService := message.Service{ - Identifier: g.ID[:], - Tag: catalog.Group, - Metadata: g.ID[:], - } - m.services.AddService(m.receptionId, newService, &receptionProcessor{m: &m, g: g}) -} - // LeaveGroup removes a group from a list of groups the user is a part of. -func (m Manager) LeaveGroup(groupID *id.ID) error { +func (m *manager) LeaveGroup(groupID *id.ID) error { if err := m.gs.Remove(groupID); err != nil { return errors.Errorf(leaveGroupErr, groupID, err) } @@ -161,24 +151,24 @@ func (m Manager) LeaveGroup(groupID *id.ID) error { } m.services.DeleteService(m.receptionId, delService, nil) - jww.DEBUG.Printf("Left group with ID %s.", groupID) + jww.INFO.Printf("[GC] Left group with ID %s.", groupID) return nil } // GetGroups returns a list of all registered groupChat IDs. -func (m Manager) GetGroups() []*id.ID { - jww.DEBUG.Print("Getting list of all groups.") +func (m *manager) GetGroups() []*id.ID { + jww.DEBUG.Print("[GC] Getting list of all groups.") return m.gs.GroupIDs() } // GetGroup returns the group with the matching ID or returns false if none // exist. -func (m Manager) GetGroup(groupID *id.ID) (gs.Group, bool) { - jww.DEBUG.Printf("Getting group with ID %s.", groupID) +func (m *manager) GetGroup(groupID *id.ID) (gs.Group, bool) { + jww.DEBUG.Printf("[GC] Getting group with ID %s.", groupID) return m.gs.Get(groupID) } // NumGroups returns the number of groups the user is a part of. -func (m Manager) NumGroups() int { +func (m *manager) NumGroups() int { return m.gs.Len() } diff --git a/groupChat/manager_test.go b/groupChat/manager_test.go index 95eb62033..098bba443 100644 --- a/groupChat/manager_test.go +++ b/groupChat/manager_test.go @@ -8,6 +8,8 @@ package groupChat import ( + "gitlab.com/elixxir/client/cmix" + "gitlab.com/elixxir/client/e2e" gs "gitlab.com/elixxir/client/groupChat/groupStore" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/group" @@ -20,8 +22,17 @@ import ( "time" ) -// Unit test of Manager.newManager. -func Test_newManager(t *testing.T) { +// Tests that manager adheres to the GroupChat interface. +var _ GroupChat = (*manager)(nil) + +// Tests that GroupCmix adheres to the cmix.Client interface. +var _ GroupCmix = (cmix.Client)(nil) + +// Tests that GroupE2e adheres to the e2e.Handler interface. +var _ GroupE2e = (e2e.Handler)(nil) + +// Unit test of NewManager. +func TestNewManager(t *testing.T) { kv := versioned.NewKV(ekv.MakeMemstore()) user := group.Member{ ID: id.NewIdFromString("userID", id.User, t), @@ -31,18 +42,21 @@ func Test_newManager(t *testing.T) { requestFunc := func(g gs.Group) { requestChan <- g } receiveChan := make(chan MessageReceive) receiveFunc := func(msg MessageReceive) { receiveChan <- msg } - m, err := NewManager(nil, newTestE2eManager(user.DhKey), user.ID, nil, nil, kv, requestFunc, receiveFunc) + gcInt, err := NewManager(nil, newTestE2eManager(user.DhKey), user.ID, nil, nil, + kv, requestFunc, receiveFunc) if err != nil { - t.Errorf("newManager() returned an error: %+v", err) + t.Errorf("NewManager returned an error: %+v", err) } + m := gcInt.(*manager) + if !m.gs.GetUser().Equal(user) { - t.Errorf("newManager() failed to create a store with the correct user."+ + t.Errorf("NewManager failed to create a store with the correct user."+ "\nexpected: %s\nreceived: %s", user, m.gs.GetUser()) } if m.gs.Len() != 0 { - t.Errorf("newManager() failed to create an empty store."+ + t.Errorf("NewManager failed to create an empty store."+ "\nexpected: %d\nreceived: %d", 0, m.gs.Len()) } @@ -63,8 +77,8 @@ func Test_newManager(t *testing.T) { } } -// Tests that Manager.newManager loads a group storage when it exists. -func Test_newManager_LoadStorage(t *testing.T) { +// Tests that NewManager loads a group storage when it exists. +func TestNewManager_LoadStorage(t *testing.T) { prng := rand.New(rand.NewSource(42)) kv := versioned.NewKV(ekv.MakeMemstore()) user := group.Member{ @@ -78,25 +92,29 @@ func Test_newManager_LoadStorage(t *testing.T) { } for i := 0; i < 10; i++ { - err := gStore.Add(newTestGroup(getGroup(), getGroup().NewInt(42), prng, t)) + err := gStore.Add( + newTestGroup(getGroup(), getGroup().NewInt(42), prng, t)) if err != nil { t.Errorf("Failed to add group %d: %+v", i, err) } } - m, err := NewManager(newTestNetworkManager(0, t), newTestE2eManager(user.DhKey), user.ID, nil, nil, kv, nil, nil) + gcInt, err := NewManager(newTestNetworkManager(0, t), + newTestE2eManager(user.DhKey), user.ID, nil, nil, kv, nil, nil) if err != nil { - t.Errorf("newManager() returned an error: %+v", err) + t.Errorf("NewManager returned an error: %+v", err) } + m := gcInt.(*manager) + if !reflect.DeepEqual(gStore, m.gs) { - t.Errorf("newManager() failed to load the expected storage."+ + t.Errorf("NewManager failed to load the expected storage."+ "\nexpected: %+v\nreceived: %+v", gStore, m.gs) } } // Error path: an error is returned when a group cannot be loaded from storage. -func Test_newManager_LoadError(t *testing.T) { +func TestNewManager_LoadError(t *testing.T) { prng := rand.New(rand.NewSource(42)) kv := versioned.NewKV(ekv.MakeMemstore()) user := group.Member{ @@ -120,7 +138,7 @@ func Test_newManager_LoadError(t *testing.T) { _, err = NewManager(nil, newTestE2eManager(user.DhKey), user.ID, nil, nil, kv, nil, nil) if err == nil || !strings.Contains(err.Error(), expectedErr) { - t.Errorf("newManager() did not return the expected error."+ + t.Errorf("NewManager did not return the expected error."+ "\nexpected: %s\nreceived: %+v", expectedErr, err) } } @@ -129,7 +147,7 @@ func Test_newManager_LoadError(t *testing.T) { // user. To fix this test, they need to use different users, which requires // modifying // storage.InitTestingSession. -// func TestManager_StartProcesses(t *testing.T) { +// func Test_manager_StartProcesses(t *testing.T) { // jww.SetLogThreshold(jww.LevelTrace) // jww.SetStdoutThreshold(jww.LevelTrace) // prng := rand.New(rand.NewSource(42)) @@ -270,65 +288,65 @@ func Test_newManager_LoadError(t *testing.T) { // } // } -// Unit test of Manager.JoinGroup. -func TestManager_JoinGroup(t *testing.T) { +// Unit test of manager.JoinGroup. +func Test_manager_JoinGroup(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t) g := newTestGroup(m.grp, m.e2e.GetHistoricalDHPubkey(), prng, t) err := m.JoinGroup(g) if err != nil { - t.Errorf("JoinGroup() returned an error: %+v", err) + t.Errorf("JoinGroup returned an error: %+v", err) } if _, exists := m.gs.Get(g.ID); !exists { - t.Errorf("JoinGroup() failed to add the group %s.", g.ID) + t.Errorf("JoinGroup failed to add the group %s.", g.ID) } } // Error path: an error is returned when a group is joined twice. -func TestManager_JoinGroup_AddErr(t *testing.T) { +func Test_manager_JoinGroup_AddError(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t) expectedErr := strings.SplitN(joinGroupErr, "%", 2)[0] err := m.JoinGroup(g) if err == nil || !strings.Contains(err.Error(), expectedErr) { - t.Errorf("JoinGroup() failed to return the expected error."+ + t.Errorf("JoinGroup failed to return the expected error."+ "\nexpected: %s\nreceived: %+v", expectedErr, err) } } -// Unit test of Manager.LeaveGroup. -func TestManager_LeaveGroup(t *testing.T) { +// Unit test of manager.LeaveGroup. +func Test_manager_LeaveGroup(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t) err := m.LeaveGroup(g.ID) if err != nil { - t.Errorf("LeaveGroup() returned an error: %+v", err) + t.Errorf("LeaveGroup returned an error: %+v", err) } if _, exists := m.GetGroup(g.ID); exists { - t.Error("LeaveGroup() failed to delete the group.") + t.Error("LeaveGroup failed to delete the group.") } } -// Error path: an error is returned when no group with the ID exists -func TestManager_LeaveGroup_NoGroupError(t *testing.T) { +// Error path: an error is returned when no group with the ID exists. +func Test_manager_LeaveGroup_NoGroupError(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t) expectedErr := strings.SplitN(leaveGroupErr, "%", 2)[0] err := m.LeaveGroup(id.NewIdFromString("invalidID", id.Group, t)) if err == nil || !strings.Contains(err.Error(), expectedErr) { - t.Errorf("LeaveGroup() failed to return the expected error."+ + t.Errorf("LeaveGroup failed to return the expected error."+ "\nexpected: %s\nreceived: %+v", expectedErr, err) } } -// Unit test of Manager.GetGroups. -func TestManager_GetGroups(t *testing.T) { +// Unit test of manager.GetGroups. +func Test_manager_GetGroups(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t) @@ -340,36 +358,36 @@ func TestManager_GetGroups(t *testing.T) { } if m.gs.Len() != 0 { - t.Errorf("GetGroups() returned %d IDs, which is %d less than is in "+ + t.Errorf("GetGroups returned %d IDs, which is %d less than is in "+ "memory.", len(list), m.gs.Len()) } } -// Unit test of Manager.GetGroup. -func TestManager_GetGroup(t *testing.T) { +// Unit test of manager.GetGroup. +func Test_manager_GetGroup(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t) testGrp, exists := m.GetGroup(g.ID) if !exists { - t.Error("GetGroup() failed to find a group that should exist.") + t.Error("GetGroup failed to find a group that should exist.") } if !reflect.DeepEqual(g, testGrp) { - t.Errorf("GetGroup() failed to return the expected group."+ + t.Errorf("GetGroup failed to return the expected group."+ "\nexpected: %#v\nreceived: %#v", g, testGrp) } testGrp, exists = m.GetGroup(id.NewIdFromString("invalidID", id.Group, t)) if exists { - t.Errorf("GetGroup() returned a group that should not exist: %#v", testGrp) + t.Errorf("GetGroup returned a group that should not exist: %#v", testGrp) } } -// Unit test of Manager.NumGroups. First a manager is created with 10 groups +// Unit test of manager.NumGroups. First a manager is created with 10 groups // and the initial number is checked. Then the number of groups is checked after // leaving each until the number left is 0. -func TestManager_NumGroups(t *testing.T) { +func Test_manager_NumGroups(t *testing.T) { expectedNum := 10 m, _ := newTestManagerWithStore(rand.New(rand.NewSource(42)), expectedNum, 0, nil, nil, t) @@ -380,10 +398,9 @@ func TestManager_NumGroups(t *testing.T) { _ = m.LeaveGroup(gid) if m.NumGroups() != expectedNum-i { - t.Errorf("NumGroups() failed to return the expected number of "+ + t.Errorf("NumGroups failed to return the expected number of "+ "groups (%d).\nexpected: %d\nreceived: %d", i, expectedNum-i, m.NumGroups()) } } - } diff --git a/groupChat/messageReceive.go b/groupChat/messageReceive.go index e607e7f01..fa883e73e 100644 --- a/groupChat/messageReceive.go +++ b/groupChat/messageReceive.go @@ -31,7 +31,7 @@ type MessageReceive struct { RoundTimestamp time.Time } -// String returns the MessageReceive as readable text. This functions satisfies +// String returns the MessageReceive as readable text. This functions adheres to // the fmt.Stringer interface. func (mr MessageReceive) String() string { groupID := "<nil>" @@ -54,16 +54,17 @@ func (mr MessageReceive) String() string { recipientID = mr.RecipientID.String() } - str := make([]string, 0, 9) - str = append(str, "GroupID:"+groupID) - str = append(str, "ID:"+mr.ID.String()) - str = append(str, "Payload:"+payload) - str = append(str, "SenderID:"+senderID) - str = append(str, "RecipientID:"+recipientID) - str = append(str, "EphemeralID:"+strconv.FormatInt(mr.EphemeralID.Int64(), 10)) - str = append(str, "Timestamp:"+mr.Timestamp.String()) - str = append(str, "RoundID:"+strconv.FormatUint(uint64(mr.RoundID), 10)) - str = append(str, "RoundTimestamp:"+mr.RoundTimestamp.String()) + str := []string{ + "GroupID:" + groupID, + "ID:" + mr.ID.String(), + "Payload:" + payload, + "SenderID:" + senderID, + "RecipientID:" + recipientID, + "EphemeralID:" + strconv.FormatInt(mr.EphemeralID.Int64(), 10), + "Timestamp:" + mr.Timestamp.String(), + "RoundID:" + strconv.FormatUint(uint64(mr.RoundID), 10), + "RoundTimestamp:" + mr.RoundTimestamp.String(), + } return "{" + strings.Join(str, " ") + "}" } diff --git a/groupChat/processor.go b/groupChat/processor.go new file mode 100644 index 000000000..1047889f6 --- /dev/null +++ b/groupChat/processor.go @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +package groupChat + +import ( + "fmt" + "gitlab.com/elixxir/client/cmix/identity/receptionID" + "gitlab.com/elixxir/client/cmix/rounds" + "gitlab.com/elixxir/primitives/format" +) + +type Processor interface { + // Process decrypts and hands off the message to its internal down stream + // message processing system. + Process(decryptedMsg MessageReceive, msg format.Message, + receptionID receptionID.EphemeralIdentity, round rounds.Round) + + // Stringer interface for debugging + fmt.Stringer +} diff --git a/groupChat/receive.go b/groupChat/receive.go index 244883cc3..ac25d9cf6 100644 --- a/groupChat/receive.go +++ b/groupChat/receive.go @@ -26,67 +26,82 @@ const ( newDecryptKeyErr = "failed to generate key for decrypting group payload: %+v" unmarshalInternalMsgErr = "failed to unmarshal group internal message: %+v" unmarshalSenderIdErr = "failed to unmarshal sender ID: %+v" - unmarshalPublicMsgErr = "failed to unmarshal group cMix message contents: %+v" + unmarshalPublicMsgErr = "[GC] Failed to unmarshal group cMix message contents from %d (%s) on round %d: %+v" + getDecryptionKeyErr = "[GC] Unable to get decryption key: %+v" + decryptMsgErr = "[GC] Failed to decrypt group message: %+v" genCryptKeyMacErr = "failed to generate encryption key for group " + "cMix message because MAC verification failed (epoch %d could be off)" ) -// Adheres to cmix.Manager interface for reception processing +// Adheres to message.Processor interface for reception processing. type receptionProcessor struct { - m *Manager + m *manager g gs.Group + p Processor } -// Process incoming group chat messages -func (p *receptionProcessor) Process(message format.Message, receptionID receptionID.EphemeralIdentity, round rounds.Round) { - jww.TRACE.Print("Group message reception received cMix message.") - // Attempt to read the message - roundTimestamp := round.Timestamps[states.QUEUED] +// Process incoming group chat messages. +func (p *receptionProcessor) Process(message format.Message, + receptionID receptionID.EphemeralIdentity, round rounds.Round) { + jww.TRACE.Printf("[GC] Received group message from %d (%s) on round %d.", + receptionID.EphId.Int64(), receptionID.Source, round.ID) // Unmarshal cMix message contents to get public message format pubMsg, err := unmarshalPublicMsg(message.GetContents()) if err != nil { - jww.WARN.Printf("Failed to unmarshal: %+v", errors.Errorf(unmarshalPublicMsgErr, err)) + jww.ERROR.Printf(unmarshalPublicMsgErr, receptionID.EphId.Int64(), + receptionID.Source, round.ID, err) + return } - // Obtain the cryptKey for the public message + // Obtain the decryption key for the public message key, err := getCryptKey(p.g.Key, pubMsg.GetSalt(), message.GetMac(), - pubMsg.GetPayload(), p.g.DhKeys, roundTimestamp) + pubMsg.GetPayload(), p.g.DhKeys, round.Timestamps[states.QUEUED]) if err != nil { - jww.WARN.Printf("Unable to getCryptKey: %+v", err) + jww.ERROR.Printf(getDecryptionKeyErr, err) return } // Decrypt the message payload using the cryptKey - result, err := decryptMessage(p.g, message.GetKeyFP(), key, pubMsg.GetPayload()) + result, err := decryptMessage( + p.g, message.GetKeyFP(), key, pubMsg.GetPayload()) if err != nil { - jww.WARN.Printf("Group message reception failed to read "+ - "cMix message: %+v", err) + jww.ERROR.Printf(decryptMsgErr, err) return } + // Populate remaining fields from the top level result.GroupID = p.g.ID result.RecipientID = receptionID.Source result.EphemeralID = receptionID.EphId result.RoundID = round.ID - result.RoundTimestamp = roundTimestamp + result.RoundTimestamp = round.Timestamps[states.QUEUED] + + jww.DEBUG.Printf("[GC] Received group message with ID %s from sender "+ + "%s in group %q with ID %s at %s.", result.ID, result.SenderID, + p.g.Name, p.g.ID, result.Timestamp) - jww.DEBUG.Printf("Received group message with ID %s from sender "+ - "%s in group %s with ID %s at %s.", result.ID, result.SenderID, p.g.Name, - p.g.ID, result.Timestamp) + // Send the received message on the callback + go p.m.receiveFunc(result) - // If the message was read correctly, send it to the callback - p.m.receiveFunc(result) + // Send the decrypted message and original message to the processor, if one + // is registered + if p.p != nil { + p.p.Process(result, message, receptionID, round) + } } func (p *receptionProcessor) String() string { - return fmt.Sprintf("GroupChatReception(%s)", p.m.receptionId) + if p.p == nil { + return fmt.Sprintf("GroupChatReception(%s)", p.m.receptionId) + } + return fmt.Sprintf("GroupChatReception(%s)-%s", p.m.receptionId, p.p) } // decryptMessage decrypts the group message payload and returns its message ID, // timestamp, sender ID, and message contents. -func decryptMessage(g gs.Group, fingerprint format.Fingerprint, key group.CryptKey, payload []byte) ( - MessageReceive, error) { +func decryptMessage(g gs.Group, fingerprint format.Fingerprint, + key group.CryptKey, payload []byte) (MessageReceive, error) { // Decrypt internal message decryptedPayload := group.Decrypt(key, fingerprint, payload) diff --git a/groupChat/receiveRequest.go b/groupChat/receiveRequest.go index 0d2224cbb..d76744315 100644 --- a/groupChat/receiveRequest.go +++ b/groupChat/receiveRequest.go @@ -27,25 +27,25 @@ const ( // Adheres to receive.Listener interface type requestListener struct { - m *Manager + m *manager } // Hear waits for new group requests to arrive func (l *requestListener) Hear(item receive.Message) { - jww.DEBUG.Print("Group message request received message.") + jww.DEBUG.Print("[GC] Group message request received message.") // Generate the group from the request message g, err := l.m.readRequest(item) if err != nil { - jww.WARN.Printf("Failed to read message as group request: %+v", err) + jww.WARN.Printf( + "[GC] Failed to read message as group request: %+v", err) return } - // Call request callback with the new group if it does not already - // exist + // Call request callback with the new group if it does not already exist if _, exists := l.m.GetGroup(g.ID); !exists { - jww.DEBUG.Printf("Received group request for "+ - "group %s with ID %s.", g.Name, g.ID) + jww.INFO.Printf( + "[GC] Received group request for group %s with ID %s.", g.Name, g.ID) l.m.requestFunc(g) } @@ -58,7 +58,7 @@ func (l *requestListener) Name() string { // readRequest returns the group described in the group request message. An // error is returned if the request is of the wrong type or cannot be read. -func (m *Manager) readRequest(msg receive.Message) (gs.Group, error) { +func (m *manager) readRequest(msg receive.Message) (gs.Group, error) { // Return an error if the message is not of the right type if msg.MessageType != catalog.GroupCreationRequest { return gs.Group{}, errors.New(sendMessageTypeErr) diff --git a/groupChat/receiveRequest_test.go b/groupChat/receiveRequest_test.go index 398de2f49..3dc1f7232 100644 --- a/groupChat/receiveRequest_test.go +++ b/groupChat/receiveRequest_test.go @@ -146,7 +146,7 @@ func TestRequestListener_Hear_BadMessageType(t *testing.T) { } // Unit test of readRequest. -func TestManager_readRequest(t *testing.T) { +func Test_manager_readRequest(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManager(prng, t) @@ -200,7 +200,7 @@ func TestManager_readRequest(t *testing.T) { } // Error path: an error is returned if the message type is incorrect. -func TestManager_readRequest_MessageTypeError(t *testing.T) { +func Test_manager_readRequest_MessageTypeError(t *testing.T) { m, _ := newTestManager(rand.New(rand.NewSource(42)), t) expectedErr := sendMessageTypeErr msg := receive.Message{ @@ -215,7 +215,7 @@ func TestManager_readRequest_MessageTypeError(t *testing.T) { } // Error path: an error is returned if the proto message cannot be unmarshalled. -func TestManager_readRequest_ProtoUnmarshalError(t *testing.T) { +func Test_manager_readRequest_ProtoUnmarshalError(t *testing.T) { expectedErr := strings.SplitN(deserializeMembershipErr, "%", 2)[0] m, _ := newTestManager(rand.New(rand.NewSource(42)), t) @@ -239,7 +239,7 @@ func TestManager_readRequest_ProtoUnmarshalError(t *testing.T) { } // Error path: an error is returned if the membership cannot be deserialized. -func TestManager_readRequest_DeserializeMembershipError(t *testing.T) { +func Test_manager_readRequest_DeserializeMembershipError(t *testing.T) { m, _ := newTestManager(rand.New(rand.NewSource(42)), t) expectedErr := strings.SplitN(protoUnmarshalErr, "%", 2)[0] msg := receive.Message{ diff --git a/groupChat/send.go b/groupChat/send.go index 64796dd35..817eba9cc 100644 --- a/groupChat/send.go +++ b/groupChat/send.go @@ -10,7 +10,6 @@ package groupChat import ( "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/cmix/message" gs "gitlab.com/elixxir/client/groupChat/groupStore" @@ -36,9 +35,10 @@ const ( saltReadLengthErr = "length of generated salt %d != %d required" ) -// Send sends a message to all group members using Client.SendManyCMIX. +// Send sends a message to all group members using Client.SendMany. // The send fails if the message is too long. -func (m *Manager) Send(groupID *id.ID, message []byte) (id.Round, time.Time, group.MessageID, error) { +func (m *manager) Send(groupID *id.ID, tag string, message []byte) ( + id.Round, time.Time, group.MessageID, error) { // Get the relevant group g, exists := m.GetGroup(groupID) @@ -47,17 +47,19 @@ func (m *Manager) Send(groupID *id.ID, message []byte) (id.Round, time.Time, gro errors.Errorf(newNoGroupErr, groupID) } - // get the current time stripped of the monotonic clock + // Get the current time stripped of the monotonic clock timeNow := netTime.Now().Round(0) // Create a cMix message for each group member - groupMessages, err := m.newMessages(g, message, timeNow) + groupMessages, err := m.newMessages(g, tag, message, timeNow) if err != nil { - return 0, time.Time{}, group.MessageID{}, errors.Errorf(newCmixMsgErr, err) + return 0, time.Time{}, group.MessageID{}, + errors.Errorf(newCmixMsgErr, err) } // Obtain message ID - msgId, err := getGroupMessageId(m.grp, groupID, m.receptionId, timeNow, message) + msgId, err := getGroupMessageId( + m.grp, groupID, m.receptionId, timeNow, message) if err != nil { return 0, time.Time{}, group.MessageID{}, err } @@ -71,14 +73,15 @@ func (m *Manager) Send(groupID *id.ID, message []byte) (id.Round, time.Time, gro errors.Errorf(sendManyCmixErr, m.receptionId, groupID, err) } - jww.DEBUG.Printf("Sent message to %d members in group %s at %s.", + jww.DEBUG.Printf("[GC] Sent message to %d members in group %s at %s.", len(groupMessages), groupID, timeNow) return rid, timeNow, msgId, nil } -// newMessages quickly builds messages for all group chat members in multiple threads -func (m *Manager) newMessages(g gs.Group, msg []byte, timestamp time.Time) ( - []cmix.TargetedCmixMessage, error) { +// newMessages quickly builds messages for all group chat members in multiple +// threads. +func (m *manager) newMessages(g gs.Group, tag string, msg []byte, + timestamp time.Time) ([]cmix.TargetedCmixMessage, error) { // Create list of cMix messages messages := make([]cmix.TargetedCmixMessage, 0, len(g.Members)) @@ -93,7 +96,8 @@ func (m *Manager) newMessages(g gs.Group, msg []byte, timestamp time.Time) ( } // Add cMix message to list - cMixMsg, err := newCmixMsg(g, msg, timestamp, member, rng, m.receptionId, m.services.GetMaxMessageLength()) + cMixMsg, err := newCmixMsg(g, tag, msg, timestamp, member, rng, + m.receptionId, m.services.GetMaxMessageLength()) if err != nil { return nil, err } @@ -104,15 +108,16 @@ func (m *Manager) newMessages(g gs.Group, msg []byte, timestamp time.Time) ( } // newCmixMsg generates a new cMix message to be sent to a group member. -func newCmixMsg(g gs.Group, msg []byte, timestamp time.Time, - mem group.Member, rng io.Reader, senderId *id.ID, maxCmixMessageSize int) (cmix.TargetedCmixMessage, error) { +func newCmixMsg(g gs.Group, tag string, msg []byte, timestamp time.Time, + mem group.Member, rng io.Reader, senderId *id.ID, maxCmixMessageSize int) ( + cmix.TargetedCmixMessage, error) { // Initialize targeted message cmixMsg := cmix.TargetedCmixMessage{ Recipient: mem.ID, Service: message.Service{ Identifier: g.ID[:], - Tag: catalog.Group, + Tag: makeServiceTag(tag), Metadata: g.ID[:], }, } @@ -160,13 +165,16 @@ func newCmixMsg(g gs.Group, msg []byte, timestamp time.Time, } // Build the group message ID -func getGroupMessageId(grp *cyclic.Group, groupId, senderId *id.ID, timestamp time.Time, msg []byte) (group.MessageID, error) { +func getGroupMessageId(grp *cyclic.Group, groupId, senderId *id.ID, + timestamp time.Time, msg []byte) (group.MessageID, error) { cmixMsg := format.NewMessage(grp.GetP().ByteLen()) _, intlMsg, err := newMessageParts(cmixMsg.ContentsSize()) if err != nil { - return group.MessageID{}, errors.WithMessage(err, "Failed to make message parts for message ID") + return group.MessageID{}, errors.WithMessage(err, + "Failed to make message parts for message ID") } - return group.NewMessageID(groupId, setInternalPayload(intlMsg, timestamp, senderId, msg)), nil + return group.NewMessageID(groupId, + setInternalPayload(intlMsg, timestamp, senderId, msg)), nil } // newMessageParts generates a public payload message and the internal payload diff --git a/groupChat/sendRequests.go b/groupChat/sendRequests.go index dba1231cd..dca54c2c9 100644 --- a/groupChat/sendRequests.go +++ b/groupChat/sendRequests.go @@ -30,20 +30,20 @@ const ( ) // ResendRequest allows a groupChat request to be sent again. -func (m Manager) ResendRequest(groupID *id.ID) ([]id.Round, RequestStatus, error) { +func (m *manager) ResendRequest(groupID *id.ID) ([]id.Round, RequestStatus, error) { g, exists := m.GetGroup(groupID) if !exists { return nil, NotSent, errors.Errorf(resendGroupIdErr, groupID) } - jww.DEBUG.Printf("Resending group requests for group %s.", groupID) + jww.INFO.Printf("[GC] Resending group requests for group %s.", groupID) return m.sendRequests(g) } // sendRequests sends group requests to each member in the group except for the // leader/sender -func (m Manager) sendRequests(g gs.Group) ([]id.Round, RequestStatus, error) { +func (m *manager) sendRequests(g gs.Group) ([]id.Round, RequestStatus, error) { // Build request message requestMarshaled, err := proto.Marshal(&Request{ Name: g.Name, @@ -106,7 +106,8 @@ func (m Manager) sendRequests(g gs.Group) ([]id.Round, RequestStatus, error) { strings.Join(errs, "\n")) } - jww.DEBUG.Printf("Sent group request to %d members in group %q with ID %s.", + jww.DEBUG.Printf( + "[GC] Sent group request to %d members in group %q with ID %s.", len(g.Members), g.Name, g.ID) // If all sends succeeded, return a list of roundIDs @@ -114,12 +115,13 @@ func (m Manager) sendRequests(g gs.Group) ([]id.Round, RequestStatus, error) { } // sendRequest sends the group request to the user via E2E. -func (m Manager) sendRequest(memberID *id.ID, request []byte) ([]id.Round, error) { +func (m *manager) sendRequest(memberID *id.ID, request []byte) ([]id.Round, error) { p := e2e.GetDefaultParams() p.LastServiceTag = catalog.GroupRq p.DebugTag = "group.Request" - rounds, _, _, err := m.e2e.SendE2E(catalog.GroupCreationRequest, memberID, request, p) + rounds, _, _, err := m.e2e.SendE2E( + catalog.GroupCreationRequest, memberID, request, p) if err != nil { return nil, errors.Errorf(sendE2eErr, memberID, err) } diff --git a/groupChat/sendRequests_test.go b/groupChat/sendRequests_test.go index 6951f49b1..07d2ee545 100644 --- a/groupChat/sendRequests_test.go +++ b/groupChat/sendRequests_test.go @@ -23,8 +23,8 @@ import ( "testing" ) -// Tests that Manager.ResendRequest sends all expected requests successfully. -func TestManager_ResendRequest(t *testing.T) { +// Tests that manager.ResendRequest sends all expected requests successfully. +func Test_manager_ResendRequest(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t) @@ -102,7 +102,7 @@ func TestManager_ResendRequest(t *testing.T) { // Error path: an error is returned when no group with the corresponding group // ID exists. -func TestManager_ResendRequest_GetGroupError(t *testing.T) { +func Test_manager_ResendRequest_GetGroupError(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t) expectedErr := strings.SplitN(resendGroupIdErr, "%", 2)[0] @@ -119,8 +119,8 @@ func TestManager_ResendRequest_GetGroupError(t *testing.T) { } } -// Tests that Manager.sendRequests sends all expected requests successfully. -func TestManager_sendRequests(t *testing.T) { +// Tests that manager.sendRequests sends all expected requests successfully. +func Test_manager_sendRequests(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t) @@ -196,9 +196,9 @@ func TestManager_sendRequests(t *testing.T) { } } -// Tests that Manager.sendRequests returns the correct status when all sends +// Tests that manager.sendRequests returns the correct status when all sends // fail. -func TestManager_sendRequests_SendAllFail(t *testing.T) { +func Test_manager_sendRequests_SendAllFail(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 1, nil, nil, t) expectedErr := fmt.Sprintf(sendRequestAllErr, len(g.Members)-1, "") @@ -225,9 +225,9 @@ func TestManager_sendRequests_SendAllFail(t *testing.T) { } } -// Tests that Manager.sendRequests returns the correct status when some sends +// Tests that manager.sendRequests returns the correct status when some sends // fail. -func TestManager_sendRequests_SendPartialSent(t *testing.T) { +func Test_manager_sendRequests_SendPartialSent(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 2, nil, nil, t) expectedErr := fmt.Sprintf(sendRequestPartialErr, (len(g.Members)-1)/2, @@ -267,8 +267,8 @@ func TestManager_sendRequests_SendPartialSent(t *testing.T) { } } -// Unit test of Manager.sendRequest. -func TestManager_sendRequest(t *testing.T) { +// Unit test of manager.sendRequest. +func Test_manager_sendRequest(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t) @@ -307,7 +307,7 @@ func TestManager_sendRequest(t *testing.T) { } // Error path: an error is returned when SendE2E fails -func TestManager_sendRequest_SendE2eError(t *testing.T) { +func Test_manager_sendRequest_SendE2eError(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 1, nil, nil, t) expectedErr := strings.SplitN(sendE2eErr, "%", 2)[0] diff --git a/groupChat/send_test.go b/groupChat/send_test.go index 72d982329..85eeeb245 100644 --- a/groupChat/send_test.go +++ b/groupChat/send_test.go @@ -17,6 +17,7 @@ import ( "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/states" "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/id/ephemeral" "gitlab.com/xx_network/primitives/netTime" "math/rand" "strings" @@ -24,11 +25,12 @@ import ( "time" ) -func TestManager_Send(t *testing.T) { +func Test_manager_Send(t *testing.T) { receiveChan := make(chan MessageReceive, 100) receiveFunc := func(msg MessageReceive) { receiveChan <- msg } + msgChan := make(chan MessageReceive, 10) prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 1, 0, nil, receiveFunc, t) @@ -36,6 +38,7 @@ func TestManager_Send(t *testing.T) { reception := &receptionProcessor{ m: m, g: g, + p: &testProcessor{msgChan}, } roundId, _, msgId, err := m.Send(g.ID, messageBytes) @@ -54,9 +57,12 @@ func TestManager_Send(t *testing.T) { timestamps := make(map[states.Round]time.Time) timestamps[states.QUEUED] = netTime.Now().Round(0) for _, msg := range messages { - reception.Process(msg, receptionID.EphemeralIdentity{}, rounds.Round{ID: roundId, Timestamps: timestamps}) + reception.Process(msg, receptionID.EphemeralIdentity{ + EphId: ephemeral.Id{1, 2, 3}, Source: &id.ID{4, 5, 6}, + }, + rounds.Round{ID: roundId, Timestamps: timestamps}) select { - case result := <-receiveChan: + case result := <-msgChan: if !result.SenderID.Cmp(m.receptionId) { t.Errorf("Sender mismatch") } @@ -90,7 +96,7 @@ func TestGroup_newCmixMsg_SaltReaderError(t *testing.T) { func TestGroup_newCmixMsg_InternalMsgSizeError(t *testing.T) { expectedErr := strings.SplitN(messageLenErr, "%", 2)[0] - // Create new test Manager and Group + // Create new test manager and Group prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t) @@ -261,3 +267,14 @@ func Test_setPublicPayload(t *testing.T) { encryptedPayload, unmarshalled.GetPayload()) } } + +type testProcessor struct { + msgChan chan MessageReceive +} + +func (tp *testProcessor) Process(decryptedMsg MessageReceive, _ format.Message, + _ receptionID.EphemeralIdentity, _ rounds.Round) { + tp.msgChan <- decryptedMsg +} + +func (tp *testProcessor) String() string { return "testProcessor" } diff --git a/groupChat/service.go b/groupChat/service.go new file mode 100644 index 000000000..63fb600e4 --- /dev/null +++ b/groupChat/service.go @@ -0,0 +1,35 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +//////////////////////////////////////////////////////////////////////////////// + +package groupChat + +import ( + "gitlab.com/elixxir/client/catalog" + "gitlab.com/elixxir/client/cmix/message" + gs "gitlab.com/elixxir/client/groupChat/groupStore" +) + +func (m *manager) AddService(g gs.Group, tag string, p Processor) { + newService := message.Service{ + Identifier: g.ID[:], + Tag: makeServiceTag(tag), + Metadata: g.ID[:], + } + m.services.AddService(m.receptionId, newService, &receptionProcessor{m, g, p}) +} + +func (m *manager) RemoveService(g gs.Group, tag string, p Processor) { + toDelete := message.Service{ + Identifier: g.ID[:], + Tag: makeServiceTag(tag), + } + m.services.DeleteService(g.ID, toDelete, &receptionProcessor{m, g, p}) +} + +func makeServiceTag(tag string) string { + return catalog.Group + "-" + tag +} diff --git a/groupChat/utils_test.go b/groupChat/utils_test.go index 371d03ba3..34b3ed5b4 100644 --- a/groupChat/utils_test.go +++ b/groupChat/utils_test.go @@ -41,9 +41,9 @@ import ( "gitlab.com/xx_network/primitives/netTime" ) -// newTestManager creates a new Manager for testing. -func newTestManager(rng *rand.Rand, t *testing.T) (*Manager, gs.Group) { - m := &Manager{ +// newTestManager creates a new manager for testing. +func newTestManager(rng *rand.Rand, t *testing.T) (*manager, gs.Group) { + m := &manager{ receptionId: id.NewIdFromString("test", id.User, t), rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG), grp: getGroup(), @@ -66,13 +66,13 @@ func newTestManager(rng *rand.Rand, t *testing.T) (*Manager, gs.Group) { return m, g } -// newTestManager creates a new Manager that has groups stored for testing. One +// newTestManager creates a new manager that has groups stored for testing. One // of the groups in the list is also returned. func newTestManagerWithStore(rng *rand.Rand, numGroups int, sendErr int, requestFunc RequestCallback, receiveFunc ReceiveCallback, - t *testing.T) (*Manager, gs.Group) { + t *testing.T) (*manager, gs.Group) { - m := &Manager{ + m := &manager{ receptionId: id.NewIdFromString("test", id.User, t), rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG), grp: getGroup(), diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go index 1315c7d71..2139e9597 100644 --- a/interfaces/networkManager.go +++ b/interfaces/networkManager.go @@ -50,7 +50,7 @@ type NetworkManager interface { id.Round, []ephemeral.Id, error) /*===Message Reception================================================*/ - /* Identities are all network identites which the client is currently + /* Identities are all network identities which the client is currently trying to pick up message on. An identity must be added to receive messages, fake ones will be used to poll the network if none are present. On creation of the network handler, the identity in @@ -132,7 +132,7 @@ type NetworkManager interface { // the given identity DeleteClientTriggers(identity *id.ID) - // TrackTriggers - Registers a callback which will get called + // TrackServices - Registers a callback which will get called // every time triggers change. // It will receive the triggers list every time it is modified. // Will only get callbacks while the Network Follower is running. @@ -163,7 +163,8 @@ type NetworkManager interface { // relationship with NumRegisteredNodes() int - // Triggers the generation of a keying relationship with a given node + // TriggerNodeRegistration triggers the generation of a keying + // relationship with a given node TriggerNodeRegistration(nid *id.ID) /*===Historical Rounds================================================*/ @@ -176,7 +177,7 @@ type NetworkManager interface { // network LookupHistoricalRound(rid id.Round, callback func(info *mixmessages.RoundInfo, - success bool)) error + success bool)) error /*===Sender===========================================================*/ /* The sender handles sending comms to the network. It tracks diff --git a/single/request.go b/single/request.go index 6f2d71ae8..6cb079652 100644 --- a/single/request.go +++ b/single/request.go @@ -212,8 +212,6 @@ func TransmitRequest(recipient contact.Contact, tag string, payload []byte, errors.Errorf(errSendRequest, tag, recipient, err) } - // todo: this is jono's work but there's a send above it, - // probably just WIP code, talk to jono and resolve once tests work roundIDs := make([]id.Round, len(parts)+1) roundIDs[0] = rid for i, part := range parts { diff --git a/storage/user/cryptographic.go b/storage/user/cryptographic.go index 592fc9c23..fd4b73047 100644 --- a/storage/user/cryptographic.go +++ b/storage/user/cryptographic.go @@ -41,7 +41,9 @@ type ciDisk struct { IsPrecanned bool } -func newCryptographicIdentity(transmissionID, receptionID *id.ID, transmissionSalt, receptionSalt []byte, transmissionRsa, receptionRsa *rsa.PrivateKey, +func newCryptographicIdentity(transmissionID, receptionID *id.ID, + transmissionSalt, receptionSalt []byte, + transmissionRsa, receptionRsa *rsa.PrivateKey, isPrecanned bool, kv *versioned.KV) *CryptographicIdentity { ci := &CryptographicIdentity{ diff --git a/ud/interfaces.go b/ud/interfaces.go index 6042ae755..ba5bff8b7 100644 --- a/ud/interfaces.go +++ b/ud/interfaces.go @@ -24,6 +24,10 @@ type E2E interface { // GetReceptionID returns the default IDs GetReceptionID() *id.ID + + // GetHistoricalDHPubkey returns the user's Historical DH + // Public Key + GetHistoricalDHPubkey() *cyclic.Int } // UserInfo is a sub-interface for the user.User object in storage. diff --git a/ud/manager.go b/ud/manager.go index 53e6a37f6..9d60515e5 100644 --- a/ud/manager.go +++ b/ud/manager.go @@ -17,6 +17,12 @@ import ( "time" ) +const ( + IsRegisteredErr = "NewManager is already registered. " + + "NewManager is meant for the first instantiation. Use LoadManager " + + "for all other calls" +) + // Manager is the control structure for the contacting the user discovery service. type Manager struct { // Network is a sub-interface of the cmix.Client interface. It @@ -85,6 +91,10 @@ func NewManager(services CMix, e2e E2E, kv: kv, } + if m.isRegistered() { + return nil, errors.Errorf(IsRegisteredErr) + } + // Initialize store var err error m.store, err = store.NewOrLoadStore(kv) diff --git a/ud/register.go b/ud/register.go index caae813dc..3df8edd64 100644 --- a/ud/register.go +++ b/ud/register.go @@ -25,7 +25,7 @@ func (m *Manager) register(username string, rng csprng.Source, RSAPublicPem: string(rsa.CreatePublicKeyPem(cryptoUser.ReceptionRSA.GetPublic())), IdentityRegistration: &pb.Identity{ Username: username, - DhPubKey: cryptoUser.E2eDhPublicKey.Bytes(), + DhPubKey: m.e2e.GetHistoricalDHPubkey().Bytes(), Salt: cryptoUser.ReceptionSalt, }, UID: cryptoUser.ReceptionID.Marshal(), diff --git a/ud/search.go b/ud/search.go index d432f4756..7061f4cc3 100644 --- a/ud/search.go +++ b/ud/search.go @@ -54,7 +54,8 @@ func Search(services CMix, events event.Reporter, factMap: factMap, } - rndId, ephId, err := single.TransmitRequest(udContact, SearchTag, requestMarshaled, + rndId, ephId, err := single.TransmitRequest(udContact, SearchTag, + requestMarshaled, response, params, services, rng, grp) if err != nil { return []id.Round{}, receptionID.EphemeralIdentity{}, diff --git a/xxmutils/restoreContacts.go b/xxmutils/restoreContacts.go index 6b8afad70..69a09d2e6 100644 --- a/xxmutils/restoreContacts.go +++ b/xxmutils/restoreContacts.go @@ -11,6 +11,7 @@ import ( "encoding/json" "errors" "fmt" + "gitlab.com/elixxir/client/single" "gitlab.com/xx_network/primitives/netTime" "math" "strings" @@ -41,6 +42,11 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client, updatesCb interfaces.RestoreContactsUpdater) ([]*id.ID, []*id.ID, []error, error) { + udContact, err := udManager.GetContact() + if err != nil { + return nil, nil, nil, err + } + var restored, failed []*id.ID var errs []error @@ -93,7 +99,7 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client, rsWg := &sync.WaitGroup{} rsWg.Add(numRoutines) for i := 0; i < numRoutines; i++ { - go LookupContacts(lookupCh, foundCh, failCh, udManager, lcWg) + go LookupContacts(lookupCh, foundCh, failCh, client, udContact, lcWg) go ResetSessions(resetContactCh, restoredCh, failCh, *client, rsWg) } @@ -125,7 +131,6 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client, // Event Processing done := false - var err error = nil for !done { // NOTE: Timer is reset every loop timeoutTimer := time.NewTimer(restoreTimeout) @@ -173,13 +178,13 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *api.Client, // the mobile phone apps and are not intended to be part of the xxDK. It // should be treated as internal functions specific to the phone apps. func LookupContacts(in chan *id.ID, out chan *contact.Contact, - failCh chan failure, udManager *ud.Manager, + failCh chan failure, client *api.Client, udContact contact.Contact, wg *sync.WaitGroup) { defer wg.Done() // Start looking up contacts with user discovery and feed this // contacts channel. for lookupID := range in { - c, err := LookupContact(lookupID, udManager) + c, err := LookupContact(lookupID, client, udContact) if err == nil { out <- c continue @@ -221,7 +226,7 @@ func ResetSessions(in, out chan *contact.Contact, failCh chan failure, // xxDK users should not use this function. This function is used by // the mobile phone apps and are not intended to be part of the xxDK. It // should be treated as internal functions specific to the phone apps. -func LookupContact(userID *id.ID, udManager *ud.Manager) ( +func LookupContact(userID *id.ID, client *api.Client, udContact contact.Contact) ( *contact.Contact, error) { // This is a little wonky, but wait until we get called then // set the result to the contact objects details if there is @@ -240,8 +245,10 @@ func LookupContact(userID *id.ID, udManager *ud.Manager) ( waiter.Lock() // in MS, so 90 seconds - timeout := time.Duration(90 * time.Second) - udManager.Lookup(userID, lookupCB, timeout) + stream := client.GetRng().GetStream() + defer stream.Close() + _, _, err = ud.Lookup(client.GetNetworkInterface(), stream, client.GetE2EHandler().GetGroup(), + udContact, lookupCB, userID, single.GetDefaultRequestParams()) // Now force a wait for callback to exit waiter.Lock() @@ -272,7 +279,7 @@ type failure struct { const stateStoreFmt = "restoreContactsFromBackup/v1/%s" type stateStore struct { - apiStore *storage.Session + apiStore storage.Session // TODO: We could put a syncmap or something here instead of // 1-key-per-id } -- GitLab