diff --git a/api/messenger/backup.go b/api/e2eApi/backup.go similarity index 98% rename from api/messenger/backup.go rename to api/e2eApi/backup.go index a5e73eaaf743030acacea195229e13e409f091e8..c547307fcac9c2f65267a8e32062f3cdd8f5bfc6 100644 --- a/api/messenger/backup.go +++ b/api/e2eApi/backup.go @@ -5,7 +5,7 @@ // LICENSE file // //////////////////////////////////////////////////////////////////////////////// -package messenger +package e2eApi import "sync" diff --git a/api/messenger/backupRestore.go b/api/e2eApi/backupRestore.go similarity index 99% rename from api/messenger/backupRestore.go rename to api/e2eApi/backupRestore.go index d3187f7fcc4b9f4535559351bc2d2ff68c7484ac..809ae8d13abaae38c51214030a5cf52fcc4748bb 100644 --- a/api/messenger/backupRestore.go +++ b/api/e2eApi/backupRestore.go @@ -1,7 +1,7 @@ // FIXME: This is placeholder, there's got to be a better place to put // backup restoration than inside messenger. -package messenger +package e2eApi import ( "github.com/pkg/errors" diff --git a/api/messenger/compress_test.go b/api/e2eApi/compress_test.go similarity index 99% rename from api/messenger/compress_test.go rename to api/e2eApi/compress_test.go index 19a4bcc414c112b9168b5da43b80f8e3d78721bf..052e3bb3d8abd88c1fa6e2c3a7f76c7eb9d9f171 100644 --- a/api/messenger/compress_test.go +++ b/api/e2eApi/compress_test.go @@ -5,7 +5,7 @@ // LICENSE file // /////////////////////////////////////////////////////////////////////////////// -package messenger +package e2eApi import ( "bytes" diff --git a/api/messenger/messenger.go b/api/e2eApi/e2eApi.go similarity index 63% rename from api/messenger/messenger.go rename to api/e2eApi/e2eApi.go index 2677e6fbaf23270e7eb6fc6009266da1638eaade..1b3f5d376edbe739b0ad145ed91be23dab89e2ac 100644 --- a/api/messenger/messenger.go +++ b/api/e2eApi/e2eApi.go @@ -1,8 +1,11 @@ -package messenger +package e2eApi import ( "encoding/binary" "encoding/json" + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/ekv" + "time" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" @@ -18,12 +21,31 @@ import ( type Client struct { *api.Client - auth auth.State - e2e e2e.Handler - backup *Container + auth auth.State + e2e e2e.Handler + backup *Container + e2eIdentity TransmissionIdentity } -func Login(client *api.Client, callbacks auth.Callbacks) (m *Client, err error) { +// Login creates a new e2eApi.Client backed by the api.Client persistent versioned.KV +// If identity == nil, a new TransmissionIdentity will be generated automagically +func Login(client *api.Client, callbacks auth.Callbacks, + identity *TransmissionIdentity) (m *Client, err error) { + return login(client, callbacks, identity, client.GetStorage().GetKV()) +} + +// LoginEphemeral creates a new e2eApi.Client backed by a totally ephemeral versioned.KV +// If identity == nil, a new TransmissionIdentity will be generated automagically +func LoginEphemeral(client *api.Client, callbacks auth.Callbacks, + identity *TransmissionIdentity) (m *Client, err error) { + return login(client, callbacks, identity, versioned.NewKV(ekv.MakeMemstore())) +} + +// LoginLegacy creates a new e2eApi.Client backed by the api.Client persistent versioned.KV +// Uses the pre-generated transmission ID used by api.Client +// This function is designed to maintain backwards compatibility with previous xx messenger designs +// and should not be used for other purposes +func LoginLegacy(client *api.Client, callbacks auth.Callbacks) (m *Client, err error) { m = &Client{ Client: client, backup: &Container{}, @@ -41,6 +63,63 @@ func Login(client *api.Client, callbacks auth.Callbacks) (m *Client, err error) return nil, err } + u := m.Client.GetUser() + m.e2eIdentity = TransmissionIdentity{ + ID: u.TransmissionID, + RSAPrivatePem: u.TransmissionRSA, + Salt: u.TransmissionSalt, + DHKeyPrivate: u.E2eDhPrivateKey, + } + + return m, err +} + +// login creates a new e2eApi.Client backed by the given versioned.KV +func login(client *api.Client, callbacks auth.Callbacks, + identity *TransmissionIdentity, kv *versioned.KV) (m *Client, err error) { + e2eGrp := client.GetStorage().GetE2EGroup() + + // Create new identity automatically if one isn't specified + if identity == nil { + rng := client.GetRng().GetStream() + newIdentity, err := MakeTransmissionIdentity(rng, e2eGrp) + rng.Close() + if err != nil { + return nil, err + } + identity = &newIdentity + client.GetCmix().AddIdentity(identity.ID, time.Time{}, !kv.IsMemStore()) + } + + m = &Client{ + Client: client, + backup: &Container{}, + e2eIdentity: *identity, + } + + //initialize the e2e storage + err = e2e.Init(kv, identity.ID, identity.DHKeyPrivate, e2eGrp, + rekey.GetDefaultEphemeralParams()) + if err != nil { + return nil, err + } + + //load the new e2e storage + m.e2e, err = e2e.Load(kv, + client.GetCmix(), identity.ID, e2eGrp, client.GetRng(), + client.GetEventReporter()) + if err != nil { + return nil, errors.WithMessage(err, "Failed to load a "+ + "newly created e2e store") + } + + m.auth, err = auth.NewState(kv, client.GetCmix(), + m.e2e, client.GetRng(), client.GetEventReporter(), + auth.GetDefaultTemporaryParams(), callbacks, m.backup.TriggerBackup) + if err != nil { + return nil, err + } + return m, err } @@ -52,7 +131,7 @@ func LoadOrInitE2e(client *api.Client) (e2e.Handler, error) { e2eGrp := client.GetStorage().GetE2EGroup() kv := client.GetStorage().GetKV() - //try to load a legacy e2e hander + //try to load a legacy e2e handler e2eHandler, err := e2e.LoadLegacy(kv, client.GetCmix(), usr.ReceptionID, e2eGrp, client.GetRng(), client.GetEventReporter(), rekey.GetDefaultParams()) @@ -61,7 +140,7 @@ func LoadOrInitE2e(client *api.Client) (e2e.Handler, error) { e2eHandler, err = e2e.Load(kv, client.GetCmix(), usr.ReceptionID, e2eGrp, client.GetRng(), client.GetEventReporter()) - //if no new e2e handler exists, initilize an e2e user + //if no new e2e handler exists, initialize an e2e user if err != nil { jww.WARN.Printf("Failed to load e2e instance for %s, "+ "creating a new one", usr.ReceptionID) @@ -102,6 +181,8 @@ func LoadOrInitE2e(client *api.Client) (e2e.Handler, error) { return nil, errors.WithMessage(err, "Failed to load a "+ "newly created e2e store") } + + client.GetCmix().AddIdentity(usr.ReceptionID, time.Time{}, true) } else { jww.INFO.Printf("Loaded a modern e2e instance for %s", usr.ReceptionID) @@ -122,6 +203,11 @@ func (m *Client) GetUser() user.Info { return u } +// GetTransmissionIdentity returns a safe copy of the Client TransmissionIdentity +func (m *Client) GetTransmissionIdentity() TransmissionIdentity { + return m.e2eIdentity.DeepCopy() +} + // ConstructProtoUserFile is a helper function which is used for proto // client testing. This is used for development testing. func (m *Client) ConstructProtoUserFile() ([]byte, error) { @@ -190,7 +276,7 @@ func (m *Client) DeleteContact(partnerId *id.ID) error { // c.e2e.Conversations().Delete(partnerId) // call delete requests to make sure nothing is lingering. - // this is for saftey to ensure the contact can be readded + // this is for safety to ensure the contact can be re-added // in the future _ = m.auth.DeleteRequest(partnerId) diff --git a/api/e2eApi/identity.go b/api/e2eApi/identity.go new file mode 100644 index 0000000000000000000000000000000000000000..dc9874ed6ce12e9e32c16697f8a63599ec1258a8 --- /dev/null +++ b/api/e2eApi/identity.go @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 Privategrity Corporation / +// / +// All rights reserved. / +//////////////////////////////////////////////////////////////////////////////// + +package e2eApi + +import ( + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/diffieHellman" + "gitlab.com/xx_network/crypto/csprng" + "gitlab.com/xx_network/crypto/signature/rsa" + "gitlab.com/xx_network/crypto/xx" + "gitlab.com/xx_network/primitives/id" +) + +type TransmissionIdentity struct { + ID *id.ID + RSAPrivatePem *rsa.PrivateKey + Salt []byte + DHKeyPrivate *cyclic.Int +} + +// MakeTransmissionIdentity generates a new cryptographic identity for receiving messages +func MakeTransmissionIdentity(rng csprng.Source, grp *cyclic.Group) (TransmissionIdentity, error) { + //make RSA Key + rsaKey, err := rsa.GenerateKey(rng, + rsa.DefaultRSABitLen) + if err != nil { + return TransmissionIdentity{}, err + } + + //make salt + salt := make([]byte, 32) + _, err = rng.Read(salt) + + //make dh private key + privKey := diffieHellman.GeneratePrivateKey( + len(grp.GetPBytes()), + grp, rng) + + //make the ID + newId, err := xx.NewID(rsaKey.GetPublic(), + salt, id.User) + if err != nil { + return TransmissionIdentity{}, err + } + + //create the identity object + I := TransmissionIdentity{ + ID: newId, + RSAPrivatePem: rsaKey, + Salt: salt, + DHKeyPrivate: privKey, + } + + return I, nil +} + +// DeepCopy produces a safe copy of a TransmissionIdentity +func (t TransmissionIdentity) DeepCopy() TransmissionIdentity { + saltCopy := make([]byte, len(t.Salt)) + copy(saltCopy, t.Salt) + return TransmissionIdentity{ + ID: t.ID.DeepCopy(), + RSAPrivatePem: t.RSAPrivatePem, + Salt: saltCopy, + DHKeyPrivate: t.DHKeyPrivate.DeepCopy(), + } +} diff --git a/api/messenger/notifications.go b/api/e2eApi/notifications.go similarity index 99% rename from api/messenger/notifications.go rename to api/e2eApi/notifications.go index 380029ebfaf68cdbe9b7310a731f6614b641d136..5a737563951c3d28ba40df7742be430eee731214 100644 --- a/api/messenger/notifications.go +++ b/api/e2eApi/notifications.go @@ -5,7 +5,7 @@ // LICENSE file // /////////////////////////////////////////////////////////////////////////////// -package messenger +package e2eApi import ( "github.com/pkg/errors" diff --git a/api/messenger/precan.go b/api/e2eApi/precan.go similarity index 99% rename from api/messenger/precan.go rename to api/e2eApi/precan.go index 16717bbfa04bb986e9069931da62126e700c5509..09343060746c34f8468a2f9a49d0c91bc7b5e02b 100644 --- a/api/messenger/precan.go +++ b/api/e2eApi/precan.go @@ -1,4 +1,4 @@ -package messenger +package e2eApi import ( "encoding/binary" diff --git a/api/messenger/utils.go b/api/e2eApi/utils.go similarity index 99% rename from api/messenger/utils.go rename to api/e2eApi/utils.go index 6e1ff51fd9be792124e30ee2a4e0487d3598efdc..8ec3be34d0d26701287dd7b356c2ca8a23a9ff76 100644 --- a/api/messenger/utils.go +++ b/api/e2eApi/utils.go @@ -6,7 +6,7 @@ // Provides various utility functions for access over the bindings -package messenger +package e2eApi import ( "bytes" diff --git a/api/identity.go b/api/identity.go deleted file mode 100644 index 2ef5c5bb4cb5bfc468b368ab8d5f1ff4cf25b740..0000000000000000000000000000000000000000 --- a/api/identity.go +++ /dev/null @@ -1,53 +0,0 @@ -package api - -import ( - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/diffieHellman" - "gitlab.com/xx_network/crypto/csprng" - "gitlab.com/xx_network/crypto/signature/rsa" - "gitlab.com/xx_network/crypto/xx" - "gitlab.com/xx_network/primitives/id" -) - -type Identity struct { - ID *id.ID - RSAPrivatePem *rsa.PrivateKey - Salt []byte - DHKeyPrivate *cyclic.Int -} - -// MakeIdentity generates a new cryptographic identity for receiving messages -func MakeIdentity(rng csprng.Source, grp *cyclic.Group) (Identity, error) { - //make RSA Key - rsaKey, err := rsa.GenerateKey(rng, - rsa.DefaultRSABitLen) - if err != nil { - return Identity{}, err - } - - //make salt - salt := make([]byte, 32) - _, err = rng.Read(salt) - - //make dh private key - privkey := diffieHellman.GeneratePrivateKey( - len(grp.GetPBytes()), - grp, rng) - - //make the ID - newId, err := xx.NewID(rsaKey.GetPublic(), - salt, id.User) - if err != nil { - return Identity{}, err - } - - //create the identity object - I := Identity{ - ID: newId, - RSAPrivatePem: rsaKey, - Salt: salt, - DHKeyPrivate: privkey, - } - - return I, nil -} diff --git a/auth/interface.go b/auth/interface.go index e01e5576685fede4971dbcf8ccd542f08a464bb4..97c970f30effbbf484e52808dcd1421265d03a17 100644 --- a/auth/interface.go +++ b/auth/interface.go @@ -96,6 +96,12 @@ type State interface { // VerifyOwnership checks if the received ownership proof is valid VerifyOwnership(received, verified contact.Contact, e2e e2e.Handler) bool + // AddPartnerCallback that overrides the generic auth callback for the given partnerId + AddPartnerCallback(partnerId *id.ID, cb Callbacks) + + // DeletePartnerCallback that overrides the generic auth callback for the given partnerId + DeletePartnerCallback(partnerId *id.ID) + //Closer stops listening to auth io.Closer } diff --git a/auth/partnerCallbacks.go b/auth/partnerCallbacks.go new file mode 100644 index 0000000000000000000000000000000000000000..79264cf16c607d0dfebf2fbbb79b158b80ce35c9 --- /dev/null +++ b/auth/partnerCallbacks.go @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright © 2022 Privategrity Corporation / +// / +// All rights reserved. / +//////////////////////////////////////////////////////////////////////////////// + +package auth + +import ( + "gitlab.com/xx_network/primitives/id" + "sync" +) + +// partnerCallbacks is a thread-safe wrapper for Callbacks specific to partnerIds +// For auth operations with a specific partner, these Callbacks will be used instead +type partnerCallbacks struct { + callbacks map[id.ID]Callbacks + sync.RWMutex +} + +// AddPartnerCallback that overrides the generic auth callback for the given partnerId +func (p *partnerCallbacks) AddPartnerCallback(partnerId *id.ID, cb Callbacks) { + p.Lock() + defer p.Unlock() + if _, ok := p.callbacks[*partnerId]; !ok { + p.callbacks[*partnerId] = cb + } +} + +// DeletePartnerCallback that overrides the generic auth callback for the given partnerId +func (p *partnerCallbacks) DeletePartnerCallback(partnerId *id.ID) { + p.Lock() + defer p.Unlock() + if _, ok := p.callbacks[*partnerId]; ok { + delete(p.callbacks, *partnerId) + } +} + +// getPartnerCallback returns the Callbacks for the given partnerId +func (p *partnerCallbacks) getPartnerCallback(partnerId *id.ID) Callbacks { + return p.callbacks[*partnerId] +} diff --git a/auth/receivedConfirm.go b/auth/receivedConfirm.go index 8ee24bd341ba6c03e2f00a7a5158d76558b6800e..538329e1b532a1a34d813f866dfb739319c09d3b 100644 --- a/auth/receivedConfirm.go +++ b/auth/receivedConfirm.go @@ -25,21 +25,21 @@ type receivedConfirmService struct { func (rcs *receivedConfirmService) Process(msg format.Message, receptionID receptionID.EphemeralIdentity, round rounds.Round) { - state := rcs.s + authState := rcs.s //parse the confirm - baseFmt, partnerPubKey, err := handleBaseFormat(msg, state.e2e.GetGroup()) + baseFmt, partnerPubKey, err := handleBaseFormat(msg, authState.e2e.GetGroup()) if err != nil { em := fmt.Sprintf("Failed to handle auth confirm: %s", err) jww.WARN.Print(em) - state.event.Report(10, "Auth", "ConfirmError", em) + authState.event.Report(10, "Auth", "ConfirmError", em) return } jww.TRACE.Printf("processing confirm: \n\t MYHISTORICALPUBKEY: %s\n\t"+ "MYPUBKEY: %s\n\t PARTNERPUBKEY: %s \n\t "+ "ECRPAYLOAD: %s \n\t MAC: %s", - state.e2e.GetHistoricalDHPubkey().TextVerbose(16, 0), + authState.e2e.GetHistoricalDHPubkey().TextVerbose(16, 0), rcs.SentRequest.GetMyPubKey().TextVerbose(16, 0), partnerPubKey.TextVerbose(16, 0), base64.StdEncoding.EncodeToString(baseFmt.data), @@ -47,13 +47,13 @@ func (rcs *receivedConfirmService) Process(msg format.Message, // decrypt the payload success, payload := cAuth.Decrypt(rcs.GetMyPrivKey(), partnerPubKey, - baseFmt.GetEcrPayload(), msg.GetMac(), state.e2e.GetGroup()) + baseFmt.GetEcrPayload(), msg.GetMac(), authState.e2e.GetGroup()) if !success { em := fmt.Sprintf("Received auth confirmation " + "failed its mac check") jww.WARN.Print(em) - state.event.Report(10, "Auth", "ConfirmError", em) + authState.event.Report(10, "Auth", "ConfirmError", em) return } @@ -63,7 +63,7 @@ func (rcs *receivedConfirmService) Process(msg format.Message, em := fmt.Sprintf("Failed to unmarshal auth confirmation's "+ "encrypted payload: %s", err) jww.WARN.Print(em) - state.event.Report(10, "Auth", "ConfirmError", em) + authState.event.Report(10, "Auth", "ConfirmError", em) return } @@ -72,7 +72,7 @@ func (rcs *receivedConfirmService) Process(msg format.Message, em := fmt.Sprintf("Could not get auth conf SIDH Pubkey: %s", err) jww.WARN.Print(em) - state.event.Report(10, "Auth", "ConfirmError", em) + authState.event.Report(10, "Auth", "ConfirmError", em) return } @@ -83,7 +83,7 @@ func (rcs *receivedConfirmService) Process(msg format.Message, // initial identity if !cAuth.VerifyOwnershipProof(rcs.SentRequest.GetMyPrivKey(), rcs.GetPartnerHistoricalPubKey(), - state.e2e.GetGroup(), ecrFmt.GetOwnership()) { + authState.e2e.GetGroup(), ecrFmt.GetOwnership()) { jww.WARN.Printf("Failed authenticate identity for auth "+ "confirmation of %s", rcs.GetPartner()) return @@ -91,7 +91,7 @@ func (rcs *receivedConfirmService) Process(msg format.Message, // add the partner p := session.GetDefaultParams() - _, err = state.e2e.AddPartner(rcs.GetPartner(), partnerPubKey, + _, err = authState.e2e.AddPartner(rcs.GetPartner(), partnerPubKey, rcs.GetMyPrivKey(), partnerSIDHPubKey, rcs.GetMySIDHPrivKey(), p, p) if err != nil { jww.WARN.Printf("Failed to create channel with partner %s and "+ @@ -103,7 +103,7 @@ func (rcs *receivedConfirmService) Process(msg format.Message, } // remove the service used for notifications of the confirm - state.net.DeleteService(receptionID.Source, rcs.notificationsService, nil) + authState.net.DeleteService(receptionID.Source, rcs.notificationsService, nil) // callbacks c := contact.Contact{ @@ -112,7 +112,14 @@ func (rcs *receivedConfirmService) Process(msg format.Message, OwnershipProof: ecrFmt.GetOwnership(), Facts: make([]fact.Fact, 0), } - state.callbacks.Confirm(c, receptionID, round) + + authState.partnerCallbacks.RLock() + if cb := authState.partnerCallbacks.getPartnerCallback(c.ID); cb != nil { + cb.Confirm(c, receptionID, round) + } else { + authState.callbacks.Confirm(c, receptionID, round) + } + authState.partnerCallbacks.RUnlock() } func (rcs *receivedConfirmService) String() string { diff --git a/auth/receivedRequest.go b/auth/receivedRequest.go index 944c1880b3ac0a744331abbcbb44c4f8dba79949..b410b04a3e29cca95dedd8bc14d310507e8bce57 100644 --- a/auth/receivedRequest.go +++ b/auth/receivedRequest.go @@ -28,11 +28,11 @@ type receivedRequestService struct { func (rrs *receivedRequestService) Process(message format.Message, receptionID receptionID.EphemeralIdentity, round rounds.Round) { - state := rrs.s + authState := rrs.s // check if the timestamp is before the id was created and therefore // should be ignored - tid, err := state.net.GetIdentity(receptionID.Source) + tid, err := authState.net.GetIdentity(receptionID.Source) if err != nil { jww.ERROR.Printf("received a request on %s which does not exist, "+ "this should not be possible: %+v", receptionID.Source.String(), err) @@ -47,7 +47,7 @@ func (rrs *receivedRequestService) Process(message format.Message, //decode the outer format baseFmt, partnerPubKey, err := handleBaseFormat( - message, state.e2e.GetGroup()) + message, authState.e2e.GetGroup()) if err != nil { jww.WARN.Printf("Failed to handle auth request: %s", err) return @@ -57,15 +57,15 @@ func (rrs *receivedRequestService) Process(message format.Message, jww.TRACE.Printf("processing requests: \n\t MYHISTORICALPUBKEY: %s "+ "\n\t PARTNERPUBKEY: %s \n\t ECRPAYLOAD: %s \n\t MAC: %s", - state.e2e.GetHistoricalDHPubkey().TextVerbose(16, 0), + authState.e2e.GetHistoricalDHPubkey().TextVerbose(16, 0), partnerPubKey.TextVerbose(16, 0), base64.StdEncoding.EncodeToString(baseFmt.data), base64.StdEncoding.EncodeToString(message.GetMac())) //Attempt to decrypt the payload - success, payload := cAuth.Decrypt(state.e2e.GetHistoricalDHPrivkey(), + success, payload := cAuth.Decrypt(authState.e2e.GetHistoricalDHPrivkey(), partnerPubKey, baseFmt.GetEcrPayload(), message.GetMac(), - state.e2e.GetGroup()) + authState.e2e.GetGroup()) if !success { jww.WARN.Printf("Received auth request of %s failed its mac "+ @@ -97,11 +97,11 @@ func (rrs *receivedRequestService) Process(message format.Message, format.DigestContents(message.GetContents()), base64.StdEncoding.EncodeToString(fp)) jww.INFO.Print(em) - state.event.Report(1, "Auth", "RequestReceived", em) + authState.event.Report(1, "Auth", "RequestReceived", em) // check the uniqueness of the request. Requests can be duplicated, so we // must verify this is is not a duplicate, and drop if it is - newFP, position := state.store.CheckIfNegotiationIsNew(partnerID, fp) + newFP, position := authState.store.CheckIfNegotiationIsNew(partnerID, fp) if !newFP { // if its the newest, resend the confirm @@ -113,10 +113,10 @@ func (rrs *receivedRequestService) Process(message format.Message, // check if we already accepted, if we did, resend the confirm if // we can load it - if _, err = state.e2e.GetPartner(partnerID); err != nil { + if _, err = authState.e2e.GetPartner(partnerID); err != nil { //attempt to load the confirm, if we can, resend it confirmPayload, mac, keyfp, err := - state.store.LoadConfirmation(partnerID) + authState.store.LoadConfirmation(partnerID) if err != nil { jww.ERROR.Printf("Could not reconfirm a duplicate "+ "request of an accepted confirm from %s to %s because "+ @@ -125,14 +125,26 @@ func (rrs *receivedRequestService) Process(message format.Message, } // resend the confirm. It sends as a critical message, so errors // do not need to be handled - _, _ = sendAuthConfirm(state.net, partnerID, keyfp, - confirmPayload, mac, state.event, state.params.ResetConfirmTag) - } else if state.params.ReplayRequests { + _, _ = sendAuthConfirm(authState.net, partnerID, keyfp, + confirmPayload, mac, authState.event, authState.params.ResetConfirmTag) + } else if authState.params.ReplayRequests { //if we did not already accept, auto replay the request if rrs.reset { - state.callbacks.Reset(c, receptionID, round) + authState.partnerCallbacks.RLock() + if cb := authState.partnerCallbacks.getPartnerCallback(c.ID); cb != nil { + cb.Reset(c, receptionID, round) + } else { + authState.callbacks.Reset(c, receptionID, round) + } + authState.partnerCallbacks.RUnlock() } else { - state.callbacks.Request(c, receptionID, round) + authState.partnerCallbacks.RLock() + if cb := authState.partnerCallbacks.getPartnerCallback(c.ID); cb != nil { + cb.Request(c, receptionID, round) + } else { + authState.callbacks.Request(c, receptionID, round) + } + authState.partnerCallbacks.RUnlock() } } //if not confirm, and params.replay requests is true, we need to replay @@ -159,21 +171,21 @@ func (rrs *receivedRequestService) Process(message format.Message, // error to see if it did or didnt exist // Note: due to the newFP handling above, this can ONLY run in the event of // a reset or when the partner doesnt exist, so it is safe - if err = state.e2e.DeletePartner(partnerID); err != nil { + if err = authState.e2e.DeletePartner(partnerID); err != nil { if !strings.Contains(err.Error(), ratchet.NoPartnerErrorStr) { jww.FATAL.Panicf("Failed to do actual partner deletion: %+v", err) } } else { reset = true - _ = state.store.DeleteConfirmation(partnerID) - _ = state.store.DeleteSentRequest(partnerID) + _ = authState.store.DeleteConfirmation(partnerID) + _ = authState.store.DeleteSentRequest(partnerID) } } // if a new, unique request is received when one already exists, delete the // old one and process the new one // this works because message pickup is generally time-sequential. - if err = state.store.DeleteReceivedRequest(partnerID); err != nil { + if err = authState.store.DeleteReceivedRequest(partnerID); err != nil { if !strings.Contains(err.Error(), store.NoRequestFound) { jww.FATAL.Panicf("Failed to delete old received request: %+v", err) @@ -187,7 +199,7 @@ func (rrs *receivedRequestService) Process(message format.Message, // (SIDH keys have polarity, so both sent keys cannot be used together) autoConfirm := false bail := false - err = state.store.HandleSentRequest(partnerID, + err = authState.store.HandleSentRequest(partnerID, func(request *store.SentRequest) error { //if this code is running, then we know we sent a request and can @@ -195,8 +207,8 @@ func (rrs *receivedRequestService) Process(message format.Message, //This runner will auto delete the sent request if successful //verify ownership proof - if !cAuth.VerifyOwnershipProof(state.e2e.GetHistoricalDHPrivkey(), - partnerPubKey, state.e2e.GetGroup(), ownershipProof) { + if !cAuth.VerifyOwnershipProof(authState.e2e.GetHistoricalDHPrivkey(), + partnerPubKey, authState.e2e.GetGroup(), ownershipProof) { jww.WARN.Printf("Invalid ownership proof from %s to %s "+ "received, discarding msgDigest: %s, fp: %s", partnerID, receptionID.Source, @@ -233,25 +245,39 @@ func (rrs *receivedRequestService) Process(message format.Message, // warning: the client will never be notified of the channel creation if a // crash occurs after the store but before the conclusion of the callback //create the auth storage - if err = state.store.AddReceived(c, partnerSIDHPubKey, round); err != nil { + if err = authState.store.AddReceived(c, partnerSIDHPubKey, round); err != nil { em := fmt.Sprintf("failed to store contact Auth "+ "Request: %s", err) jww.WARN.Print(em) - state.event.Report(10, "Auth", "RequestError", em) + authState.event.Report(10, "Auth", "RequestError", em) return } - //autoconfirm if we should + // auto-confirm if we should + authState.partnerCallbacks.RLock() + defer authState.partnerCallbacks.RUnlock() if autoConfirm || reset { - _, _ = state.confirm(c, state.params.getConfirmTag(reset)) + _, _ = authState.confirm(c, authState.params.getConfirmTag(reset)) //handle callbacks if autoConfirm { - state.callbacks.Confirm(c, receptionID, round) + if cb := authState.partnerCallbacks.getPartnerCallback(c.ID); cb != nil { + cb.Confirm(c, receptionID, round) + } else { + authState.callbacks.Confirm(c, receptionID, round) + } } else if reset { - state.callbacks.Reset(c, receptionID, round) + if cb := authState.partnerCallbacks.getPartnerCallback(c.ID); cb != nil { + cb.Reset(c, receptionID, round) + } else { + authState.callbacks.Reset(c, receptionID, round) + } } } else { - state.callbacks.Request(c, receptionID, round) + if cb := authState.partnerCallbacks.getPartnerCallback(c.ID); cb != nil { + cb.Request(c, receptionID, round) + } else { + authState.callbacks.Request(c, receptionID, round) + } } } diff --git a/auth/state.go b/auth/state.go index 607275a3075372141b799cfab0e9a2aa73cebbdd..43e1d9735fde5bd0e5c4bbc396ec3ff74727c4b5 100644 --- a/auth/state.go +++ b/auth/state.go @@ -9,7 +9,6 @@ package auth import ( "encoding/base64" - "github.com/pkg/errors" "gitlab.com/elixxir/client/auth/store" "gitlab.com/elixxir/client/cmix" @@ -24,7 +23,10 @@ import ( // state is an implementation of the State interface. type state struct { + // Main Callbacks for all auth operations callbacks Callbacks + // partner-specific Callbacks + partnerCallbacks partnerCallbacks net cmixClient e2e e2eHandler @@ -70,13 +72,14 @@ func NewStateLegacy(kv *versioned.KV, net cmix.Client, e2e e2e.Handler, callbacks Callbacks, backupTrigger func(reason string)) (State, error) { s := &state{ - callbacks: callbacks, - net: net, - e2e: e2e, - rng: rng, - event: event, - params: params, - backupTrigger: backupTrigger, + callbacks: callbacks, + partnerCallbacks: partnerCallbacks{callbacks: make(map[id.ID]Callbacks)}, + net: net, + e2e: e2e, + rng: rng, + event: event, + params: params, + backupTrigger: backupTrigger, } // create the store @@ -112,7 +115,13 @@ func (s *state) CallAllReceivedRequests() { rr := rrList[i] eph := receptionID.BuildIdentityFromRound(rr.GetContact().ID, rr.GetRound()) - s.callbacks.Request(rr.GetContact(), eph, rr.GetRound()) + s.partnerCallbacks.RLock() + if cb := s.partnerCallbacks.getPartnerCallback(rr.GetContact().ID); cb != nil { + cb.Request(rr.GetContact(), eph, rr.GetRound()) + } else { + s.callbacks.Request(rr.GetContact(), eph, rr.GetRound()) + } + s.partnerCallbacks.RUnlock() } } @@ -134,3 +143,13 @@ func (s *state) Close() error { }, nil) return nil } + +// AddPartnerCallback that overrides the generic auth callback for the given partnerId +func (s *state) AddPartnerCallback(partnerId *id.ID, cb Callbacks) { + s.partnerCallbacks.AddPartnerCallback(partnerId, cb) +} + +// DeletePartnerCallback that overrides the generic auth callback for the given partnerId +func (s *state) DeletePartnerCallback(partnerId *id.ID) { + s.partnerCallbacks.DeletePartnerCallback(partnerId) +} diff --git a/backup/backup.go b/backup/backup.go index 46f5bf73019e9c26e66b2a780f141a5b788647a4..4ade205c708b329346ab72cb062ca4851a90eb36 100644 --- a/backup/backup.go +++ b/backup/backup.go @@ -11,7 +11,7 @@ import ( "sync" "time" - "gitlab.com/elixxir/client/api/messenger" + "gitlab.com/elixxir/client/api/e2eApi" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/primitives/fact" @@ -41,7 +41,7 @@ type Backup struct { // Callback that is called with the encrypted backup when triggered updateBackupCb UpdateBackupFn - container *messenger.Container + container *e2eApi.Container jsonParams string @@ -91,7 +91,7 @@ type UpdateBackupFn func(encryptedBackup []byte) // Call this to turn on backups for the first time or to replace the user's // password. func InitializeBackup(password string, updateBackupCb UpdateBackupFn, - container *messenger.Container, e2e E2e, session Session, ud UserDiscovery, + container *e2eApi.Container, e2e E2e, session Session, ud UserDiscovery, kv *versioned.KV, rng *fastRNG.StreamGenerator) (*Backup, error) { b := &Backup{ updateBackupCb: updateBackupCb, @@ -135,7 +135,7 @@ func InitializeBackup(password string, updateBackupCb UpdateBackupFn, // ResumeBackup resumes a backup by restoring the Backup object and registering // a new callback. Call this to resume backups that have already been // initialized. Returns an error if backups have not already been initialized. -func ResumeBackup(updateBackupCb UpdateBackupFn, container *messenger.Container, +func ResumeBackup(updateBackupCb UpdateBackupFn, container *e2eApi.Container, e2e E2e, session Session, ud UserDiscovery, kv *versioned.KV, rng *fastRNG.StreamGenerator) (*Backup, error) { _, _, _, err := loadBackup(kv) diff --git a/backup/backup_test.go b/backup/backup_test.go index f61dc0a06b02adcaa3218c909a90dda6c90c3985..5e353b627ee449233db9308ec3166d4f381b9a28 100644 --- a/backup/backup_test.go +++ b/backup/backup_test.go @@ -14,7 +14,7 @@ import ( "testing" "time" - "gitlab.com/elixxir/client/api/messenger" + "gitlab.com/elixxir/client/api/e2eApi" "gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/ekv" @@ -32,7 +32,7 @@ func Test_InitializeBackup(t *testing.T) { cbChan := make(chan []byte, 2) cb := func(encryptedBackup []byte) { cbChan <- encryptedBackup } expectedPassword := "MySuperSecurePassword" - b, err := InitializeBackup(expectedPassword, cb, &messenger.Container{}, + b, err := InitializeBackup(expectedPassword, cb, &e2eApi.Container{}, newMockE2e(t), newMockSession(t), newMockUserDiscovery(), kv, rngGen) if err != nil { @@ -84,7 +84,7 @@ func Test_ResumeBackup(t *testing.T) { cbChan1 := make(chan []byte) cb1 := func(encryptedBackup []byte) { cbChan1 <- encryptedBackup } expectedPassword := "MySuperSecurePassword" - b, err := InitializeBackup(expectedPassword, cb1, &messenger.Container{}, + b, err := InitializeBackup(expectedPassword, cb1, &e2eApi.Container{}, newMockE2e(t), newMockSession(t), newMockUserDiscovery(), kv, rngGen) if err != nil { t.Errorf("Failed to initialize new Backup: %+v", err) @@ -106,7 +106,7 @@ func Test_ResumeBackup(t *testing.T) { // Resume the backup with a new callback cbChan2 := make(chan []byte) cb2 := func(encryptedBackup []byte) { cbChan2 <- encryptedBackup } - b2, err := ResumeBackup(cb2, &messenger.Container{}, newMockE2e(t), newMockSession(t), + b2, err := ResumeBackup(cb2, &e2eApi.Container{}, newMockE2e(t), newMockSession(t), newMockUserDiscovery(), kv, rngGen) if err != nil { t.Errorf("ResumeBackup returned an error: %+v", err) @@ -149,7 +149,7 @@ func Test_resumeBackup_NoKeyError(t *testing.T) { expectedErr := "object not found" s := storage.InitTestingSession(t) rngGen := fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG) - _, err := ResumeBackup(nil, &messenger.Container{}, newMockE2e(t), newMockSession(t), + _, err := ResumeBackup(nil, &e2eApi.Container{}, newMockE2e(t), newMockSession(t), newMockUserDiscovery(), s.GetKV(), rngGen) if err == nil || !strings.Contains(err.Error(), expectedErr) { t.Errorf("ResumeBackup did not return the expected error when no "+ @@ -392,7 +392,7 @@ func newTestBackup(password string, cb UpdateBackupFn, t *testing.T) *Backup { b, err := InitializeBackup( password, cb, - &messenger.Container{}, + &e2eApi.Container{}, newMockE2e(t), newMockSession(t), newMockUserDiscovery(), @@ -416,7 +416,7 @@ func Benchmark_InitializeBackup(t *testing.B) { expectedPassword := "MySuperSecurePassword" for i := 0; i < t.N; i++ { _, err := InitializeBackup(expectedPassword, cb, - &messenger.Container{}, + &e2eApi.Container{}, newMockE2e(t), newMockSession(t), newMockUserDiscovery(), kv, rngGen) if err != nil { diff --git a/bindings/connect.go b/bindings/connect.go index 9910af952b93165e769b15e9e54d508adcf378e3..a4ba6f9c785dda71ac582194829690811830fdd1 100644 --- a/bindings/connect.go +++ b/bindings/connect.go @@ -32,7 +32,7 @@ func (c *Connection) GetId() int { // partner.Manager is confirmed. // recipientContact - marshalled contact.Contact object // myIdentity - marshalled Identity object -func (c *Client) Connect(recipientContact []byte, myIdentity []byte) ( +func (c *Client) Connect(e2eClientId int, recipientContact []byte) ( *Connection, error) { cont, err := contact.Unmarshal(recipientContact) if err != nil { @@ -43,8 +43,7 @@ func (c *Client) Connect(recipientContact []byte, myIdentity []byte) ( return nil, err } - connection, err := connect.Connect(cont, myID, myDHPriv, c.api.GetRng(), - c.api.GetStorage().GetE2EGroup(), c.api.GetCmix(), connect.GetDefaultParams()) + connection, err := connect.Connect(cont, "test", connect.GetDefaultParams()) if err != nil { return nil, err diff --git a/cmd/callbacks.go b/cmd/callbacks.go index 07a4c66acd68cd14601ea63d32d9a30ddce28b4f..3d2050e4161e5615a26be8e52f0a4c462c140447 100644 --- a/cmd/callbacks.go +++ b/cmd/callbacks.go @@ -10,7 +10,7 @@ package cmd import ( "fmt" - "gitlab.com/elixxir/client/api/messenger" + "gitlab.com/elixxir/client/api/e2eApi" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/catalog" @@ -25,10 +25,10 @@ import ( type authCallbacks struct { autoConfirm bool confCh chan *id.ID - client *messenger.Client + client *e2eApi.Client } -func makeAuthCallbacks(client *messenger.Client, autoConfirm bool) *authCallbacks { +func makeAuthCallbacks(client *e2eApi.Client, autoConfirm bool) *authCallbacks { return &authCallbacks{ autoConfirm: autoConfirm, confCh: make(chan *id.ID, 10), @@ -71,7 +71,7 @@ func (a *authCallbacks) Reset(requestor contact.Contact, fmt.Printf(msg) } -func registerMessageListener(client *messenger.Client) chan receive.Message { +func registerMessageListener(client *e2eApi.Client) chan receive.Message { recvCh := make(chan receive.Message, 10000) listenerID := client.GetE2E().RegisterChannel("DefaultCLIReceiver", receive.AnyUser(), catalog.NoType, recvCh) diff --git a/cmd/fileTransfer.go b/cmd/fileTransfer.go index f09380f10c71289fc07fb05e0f7d7d77d27daa9b..ae7c3d84206678e89f2b9e3c92bdea7de076b901 100644 --- a/cmd/fileTransfer.go +++ b/cmd/fileTransfer.go @@ -9,7 +9,7 @@ package cmd import ( "fmt" - "gitlab.com/elixxir/client/api/messenger" + "gitlab.com/elixxir/client/api/e2eApi" "io/ioutil" "time" @@ -132,7 +132,7 @@ type receivedFtResults struct { // initFileTransferManager creates a new file transfer manager with a new // reception callback. Returns the file transfer manager and the channel that // will be triggered when the callback is called. -func initFileTransferManager(client *messenger.Client, maxThroughput int) ( +func initFileTransferManager(client *e2eApi.Client, maxThroughput int) ( *ftE2e.Wrapper, chan receivedFtResults) { // Create interfaces.ReceiveCallback that returns the results on a channel diff --git a/cmd/group.go b/cmd/group.go index fce4f5989c733a0fe2b7fa3f72ab625d29797698..6eb63d5571545070d7fa3b73682687ddbdefddd9 100644 --- a/cmd/group.go +++ b/cmd/group.go @@ -12,7 +12,7 @@ package cmd import ( "bufio" "fmt" - "gitlab.com/elixxir/client/api/messenger" + "gitlab.com/elixxir/client/api/e2eApi" "gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/rounds" "gitlab.com/elixxir/primitives/format" @@ -115,7 +115,7 @@ var groupCmd = &cobra.Command{ // initGroupManager creates a new group chat manager and starts the process // service. -func initGroupManager(client *messenger.Client) (groupChat.GroupChat, +func initGroupManager(client *e2eApi.Client) (groupChat.GroupChat, chan groupChat.MessageReceive, chan groupStore.Group) { recChan := make(chan groupChat.MessageReceive, 10) diff --git a/cmd/init.go b/cmd/init.go index ad48ca4850e5046c89b6e7b73ea212cad77856d9..6be506aa662f6d79bdaf5dbaa75c7b09c338200a 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -14,17 +14,17 @@ import ( "github.com/spf13/cobra" jww "github.com/spf13/jwalterweatherman" "github.com/spf13/viper" - "gitlab.com/elixxir/client/api/messenger" + "gitlab.com/elixxir/client/api/e2eApi" ) // initCmd creates a new user object with the given NDF var initCmd = &cobra.Command{ Use: "init", - Short: ("Initialize a user ID but do not connect to the network"), + Short: "Initialize a user ID but do not connect to the network", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { client := createClient() - e2e, err := messenger.LoadOrInitE2e(client) + e2e, err := e2eApi.LoadOrInitE2e(client) if err != nil { jww.FATAL.Panicf("%+v", err) } diff --git a/cmd/precan.go b/cmd/precan.go index 4a4050efe99237135d5dfb3c9aaf028f3d77974f..e7574b45853f15428f2ce619e5891cd8b2125849 100644 --- a/cmd/precan.go +++ b/cmd/precan.go @@ -11,7 +11,7 @@ package cmd import ( "encoding/binary" - "gitlab.com/elixxir/client/api/messenger" + "gitlab.com/elixxir/client/api/e2eApi" "strconv" jww "github.com/spf13/jwalterweatherman" @@ -67,7 +67,7 @@ func getPrecanID(recipientID *id.ID) uint { return uint(recipientID.Bytes()[7]) } -func addPrecanAuthenticatedChannel(client *messenger.Client, recipientID *id.ID, +func addPrecanAuthenticatedChannel(client *e2eApi.Client, recipientID *id.ID, recipient contact.Contact) { jww.WARN.Printf("Precanned user id detected: %s", recipientID) preUsr, err := client.MakePrecannedAuthenticatedChannel( diff --git a/cmd/root.go b/cmd/root.go index 8bdd2944b77cb12258a4d73804b8ec22d3377c6a..c3eb8e13ac2df23665b4dd800178ff551d236597 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -25,7 +25,7 @@ import ( "sync" "time" - "gitlab.com/elixxir/client/api/messenger" + "gitlab.com/elixxir/client/api/e2eApi" "gitlab.com/elixxir/client/backup" "gitlab.com/elixxir/client/e2e" @@ -559,7 +559,7 @@ func createClient() *api.Client { } // Construct client from backup data - backupIdList, _, err := messenger.NewClientFromBackup(string(ndfJSON), storeDir, + backupIdList, _, err := e2eApi.NewClientFromBackup(string(ndfJSON), storeDir, pass, backupPass, backupFile) if err != nil { jww.FATAL.Panicf("%+v", err) @@ -621,7 +621,7 @@ func initParams() api.Params { return p } -func initClient() *messenger.Client { +func initClient() *e2eApi.Client { createClient() pass := parsePassword(viper.GetString("password")) @@ -640,7 +640,7 @@ func initClient() *messenger.Client { authCbs = makeAuthCallbacks(nil, viper.GetBool("unsafe-channel-creation")) - client, err := messenger.Login(baseclient, authCbs) + client, err := e2eApi.LoginLegacy(baseclient, authCbs) if err != nil { jww.FATAL.Panicf("%+v", err) } @@ -707,7 +707,7 @@ func initClient() *messenger.Client { return client } -func acceptChannel(client *messenger.Client, recipientID *id.ID) { +func acceptChannel(client *e2eApi.Client, recipientID *id.ID) { recipientContact, err := client.GetAuth().GetReceivedRequest( recipientID) if err != nil { @@ -720,14 +720,14 @@ func acceptChannel(client *messenger.Client, recipientID *id.ID) { } } -func deleteChannel(client *messenger.Client, partnerId *id.ID) { +func deleteChannel(client *e2eApi.Client, partnerId *id.ID) { err := client.DeleteContact(partnerId) if err != nil { jww.FATAL.Panicf("%+v", err) } } -func addAuthenticatedChannel(client *messenger.Client, recipientID *id.ID, +func addAuthenticatedChannel(client *e2eApi.Client, recipientID *id.ID, recipient contact.Contact) { var allowed bool if viper.GetBool("unsafe-channel-creation") { @@ -764,7 +764,7 @@ func addAuthenticatedChannel(client *messenger.Client, recipientID *id.ID, } } -func resetAuthenticatedChannel(client *messenger.Client, recipientID *id.ID, +func resetAuthenticatedChannel(client *e2eApi.Client, recipientID *id.ID, recipient contact.Contact) { var allowed bool if viper.GetBool("unsafe-channel-creation") { @@ -1036,7 +1036,7 @@ func init() { viper.BindPFlag("log", rootCmd.PersistentFlags().Lookup("log")) rootCmd.Flags().StringP("regcode", "", "", - "Identity code (optional)") + "TransmissionIdentity code (optional)") viper.BindPFlag("regcode", rootCmd.Flags().Lookup("regcode")) rootCmd.PersistentFlags().StringP("message", "m", "", diff --git a/cmix/identity/tracker.go b/cmix/identity/tracker.go index 18e68d2f7bc34eab98affbf202e88c1a1efef296..7d9b7aaae3cbae55e8a7b5d83ed06b59649807c5 100644 --- a/cmix/identity/tracker.go +++ b/cmix/identity/tracker.go @@ -103,21 +103,8 @@ func NewOrLoadTracker(session storage.Session, addrSpace address.Space) *manager }) } else { jww.WARN.Printf("No tracked identities found and no legacy " + - "stored timestamp found; creating a new tracked identity " + - "from scratch.") - - t.tracked = append(t.tracked, TrackedID{ - // Make the next generation now so a generation triggers on - // first run - NextGeneration: netTime.Now(), - // Start generation 24 hours ago to make sure all resent - // ephemeral do pickups - // TODO: Should we go back farther? - LastGeneration: netTime.Now().Add(-time.Duration(ephemeral.Period)), - Source: t.session.GetReceptionID(), - ValidUntil: Forever, - Persistent: true, - }) + "stored timestamp found; no messages can be picked up until an " + + "identity is added.") } } else if err != nil { jww.FATAL.Panicf("Unable to create new Tracker: %+v", err) diff --git a/connect/authenticated.go b/connect/authenticated.go index 518bbc2eb482f12c23005071e4e81f42c47caf38..f12e4246016692d7b0aec8d0483f16d47314176b 100644 --- a/connect/authenticated.go +++ b/connect/authenticated.go @@ -10,6 +10,7 @@ package connect import ( "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/client/api/e2eApi" "gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/cmix" clientE2e "gitlab.com/elixxir/client/e2e" @@ -51,24 +52,23 @@ type AuthenticatedCallback func(connection AuthenticatedConnection) // ConnectWithAuthentication is called by the client, ie the one establishing // connection with the server. Once a connect.Connection has been established // with the server and then authenticate their identity to the server. -func ConnectWithAuthentication(recipient contact.Contact, myId *id.ID, - salt []byte, myRsaPrivKey *rsa.PrivateKey, myDhPrivKey *cyclic.Int, - rng *fastRNG.StreamGenerator, grp *cyclic.Group, net cmix.Client, +func ConnectWithAuthentication(recipient contact.Contact, e2eClient *e2eApi.Client, p Params) (AuthenticatedConnection, error) { // Track the time since we started to attempt to establish a connection timeStart := netTime.Now() // Establish a connection with the server - conn, err := Connect(recipient, myId, myDhPrivKey, rng, grp, net, p) + conn, err := Connect(recipient, e2eClient, p) if err != nil { return nil, errors.Errorf("failed to establish connection "+ "with recipient %s: %+v", recipient.ID, err) } // Build the authenticated connection and return - return connectWithAuthentication(conn, timeStart, recipient, salt, myRsaPrivKey, - rng, net, p) + identity := e2eClient.GetTransmissionIdentity() + return connectWithAuthentication(conn, timeStart, recipient, identity.Salt, identity.RSAPrivatePem, + e2eClient.GetRng(), e2eClient.GetCmix(), p) } // connectWithAuthentication builds and sends an IdentityAuthentication to diff --git a/connect/connect.go b/connect/connect.go index 0de11c560d74c6e085fe5fc3276cedb69a81490c..10dc397137b53e060fc29077eab6d8f646283197 100644 --- a/connect/connect.go +++ b/connect/connect.go @@ -8,6 +8,12 @@ package connect import ( "encoding/json" + "gitlab.com/elixxir/client/api/e2eApi" + "gitlab.com/elixxir/client/cmix" + "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/fastRNG" + "gitlab.com/elixxir/ekv" "io" "time" @@ -15,7 +21,6 @@ import ( jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/auth" "gitlab.com/elixxir/client/catalog" - "gitlab.com/elixxir/client/cmix" "gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/rounds" clientE2e "gitlab.com/elixxir/client/e2e" @@ -23,12 +28,8 @@ import ( "gitlab.com/elixxir/client/e2e/receive" "gitlab.com/elixxir/client/e2e/rekey" "gitlab.com/elixxir/client/event" - "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/contact" - "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/e2e" - "gitlab.com/elixxir/crypto/fastRNG" - "gitlab.com/elixxir/ekv" "gitlab.com/xx_network/primitives/id" ) @@ -118,41 +119,19 @@ func GetParameters(params string) (Params, error) { // and returns a Connection object for the newly-created partner.Manager // This function is to be used sender-side and will block until the // partner.Manager is confirmed. -func Connect(recipient contact.Contact, myId *id.ID, privKey *cyclic.Int, - rng *fastRNG.StreamGenerator, grp *cyclic.Group, net cmix.Client, +func Connect(recipient contact.Contact, e2eClient *e2eApi.Client, p Params) (Connection, error) { - //add the identity - net.AddIdentity(myId, time.Time{}, false) - - // Build an ephemeral KV - kv := versioned.NewKV(ekv.MakeMemstore()) - - // Build E2e handler - err := clientE2e.Init(kv, myId, privKey, grp, p.Rekey) - if err != nil { - return nil, err - } - e2eHandler, err := clientE2e.Load(kv, net, myId, grp, rng, p.Event) - if err != nil { - return nil, err - } // Build callback for E2E negotiation signalChannel := make(chan Connection, 1) cb := func(connection Connection) { signalChannel <- connection } - callback := getAuthCallback(cb, nil, e2eHandler, p) - - // Build auth object for E2E negotiation - authState, err := auth.NewState(kv, net, e2eHandler, - rng, p.Event, p.Auth, callback, nil) - if err != nil { - return nil, err - } + callback := getAuthCallback(cb, nil, e2eClient.GetE2E(), e2eClient.GetAuth(), p) + e2eClient.GetAuth().AddPartnerCallback(recipient.ID, callback) // Perform the auth request - _, err = authState.Request(recipient, nil) + _, err := e2eClient.GetAuth().Request(recipient, nil) if err != nil { return nil, err } @@ -199,7 +178,7 @@ func StartServer(cb Callback, myId *id.ID, privKey *cyclic.Int, } // Build callback for E2E negotiation - callback := getAuthCallback(nil, cb, e2eHandler, p) + callback := getAuthCallback(nil, cb, e2eHandler, nil, p) // Build auth object for E2E negotiation authState, err := auth.NewState(kv, net, e2eHandler, @@ -269,7 +248,7 @@ func (h *handler) Unregister(listenerID receive.ListenerID) { // building new Connection objects when an auth Request is received. type authCallback struct { // Used for signaling confirmation of E2E partnership - confrimCallback Callback + confirmCallback Callback requestCallback Callback // Used for building new Connection objects @@ -282,12 +261,13 @@ type authCallback struct { // of an auth.State object. // it will accept requests only if a request callback is passed in func getAuthCallback(confirm, request Callback, e2e clientE2e.Handler, - params Params) *authCallback { + auth auth.State, params Params) *authCallback { return &authCallback{ - confrimCallback: confirm, + confirmCallback: confirm, requestCallback: request, connectionE2e: e2e, connectionParams: params, + authState: auth, } } @@ -296,6 +276,7 @@ func (a authCallback) Confirm(requestor contact.Contact, receptionID receptionID.EphemeralIdentity, round rounds.Round) { jww.DEBUG.Printf("Connection auth request for %s confirmed", requestor.ID.String()) + defer a.authState.DeletePartnerCallback(requestor.ID) // After confirmation, get the new partner newPartner, err := a.connectionE2e.GetPartner(requestor.ID) @@ -303,26 +284,24 @@ func (a authCallback) Confirm(requestor contact.Contact, jww.ERROR.Printf("Unable to build connection with "+ "partner %s: %+v", requestor.ID, err) // Send a nil connection to avoid hold-ups down the line - if a.confrimCallback != nil { - a.confrimCallback(nil) + if a.confirmCallback != nil { + a.confirmCallback(nil) } - return } // Return the new Connection object - if a.confrimCallback != nil { - a.confrimCallback(BuildConnection(newPartner, a.connectionE2e, + if a.confirmCallback != nil { + a.confirmCallback(BuildConnection(newPartner, a.connectionE2e, a.authState, a.connectionParams)) } - } // Request will be called when an auth Request message is processed. func (a authCallback) Request(requestor contact.Contact, receptionID receptionID.EphemeralIdentity, round rounds.Round) { if a.requestCallback == nil { - jww.ERROR.Printf("Recieved a request when requests are" + + jww.ERROR.Printf("Received a request when requests are" + "not enable, will not accept") } _, err := a.authState.Confirm(requestor) @@ -371,7 +350,7 @@ func (h *handler) PartitionSize(payloadIndex uint) uint { return h.e2e.PartitionSize(payloadIndex) } -// PayloadSize Returns the max payload size for a partitionable E2E +// PayloadSize Returns the max payload size for a partition-able E2E // message func (h *handler) PayloadSize() uint { return h.e2e.PayloadSize() diff --git a/storage/user/info.go b/storage/user/info.go index 11d9381ef07cbad22a91dc49db8cff48d551fed8..62603c2225f0921f54684299f140fb33bfb6d182 100644 --- a/storage/user/info.go +++ b/storage/user/info.go @@ -105,7 +105,7 @@ func (u *User) PortableUserInfo() Info { ReceptionRSA: ci.GetReceptionRSA(), Precanned: ci.IsPrecanned(), //fixme: set these in the e2e layer, the command line layer - //needs more logical seperation so this can be removed + //needs more logical separation so this can be removed E2eDhPrivateKey: nil, E2eDhPublicKey: nil, } diff --git a/xxmutils/restoreContacts.go b/xxmutils/restoreContacts.go index 96e9c2b1b8d4fd26680bef805f27bbdb712d71b4..f17789206e3eb58fff0305db12f09ef9c1c9cd8e 100644 --- a/xxmutils/restoreContacts.go +++ b/xxmutils/restoreContacts.go @@ -11,7 +11,7 @@ import ( "encoding/json" "errors" "fmt" - "gitlab.com/elixxir/client/api/messenger" + "gitlab.com/elixxir/client/api/e2eApi" "gitlab.com/elixxir/client/single" "gitlab.com/xx_network/primitives/netTime" "math" @@ -37,7 +37,7 @@ import ( // 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 RestoreContactsFromBackup(backupPartnerIDs []byte, client *messenger.Client, +func RestoreContactsFromBackup(backupPartnerIDs []byte, client *e2eApi.Client, udManager *ud.Manager, updatesCb interfaces.RestoreContactsUpdater) ([]*id.ID, []*id.ID, []error, error) { @@ -178,7 +178,7 @@ func RestoreContactsFromBackup(backupPartnerIDs []byte, client *messenger.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, client *messenger.Client, udContact contact.Contact, + failCh chan failure, client *e2eApi.Client, udContact contact.Contact, wg *sync.WaitGroup) { defer wg.Done() // Start looking up contacts with user discovery and feed this @@ -205,7 +205,7 @@ func LookupContacts(in chan *id.ID, out chan *contact.Contact, // 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 ResetSessions(in, out chan *contact.Contact, failCh chan failure, - client *messenger.Client, wg *sync.WaitGroup) { + client *e2eApi.Client, wg *sync.WaitGroup) { defer wg.Done() for c := range in { _, err := client.GetAuth().Reset(*c) @@ -224,7 +224,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, client *messenger.Client, udContact contact.Contact) ( +func LookupContact(userID *id.ID, client *e2eApi.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