diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5d5bbe80f56f1e601b59d1c2d15b1ee269e36c0a..4a344591818545dcf0ebccf75d15fe54874d8ee4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -90,7 +90,7 @@ bindings-ios: - go get golang.org/x/mobile/bind - go install golang.org/x/mobile/cmd/gomobile@latest - gomobile init - - gomobile bind -target ios gitlab.com/elixxir/client/bindings + - gomobile bind -target ios,iossimulator,macos gitlab.com/elixxir/client/bindings - ls - zip -r iOS.zip Bindings.xcframework artifacts: diff --git a/auth/request.go b/auth/request.go index d37385815b55d2f6b1e87fabc5e1f167bb704360..31a064f8f0bf14e6f508b349ee508460a5e92ae3 100644 --- a/auth/request.go +++ b/auth/request.go @@ -82,6 +82,11 @@ func (s *state) request(partner contact.Contact, myfacts fact.FactList, historicalDHPub := diffieHellman.GeneratePublicKey(historicalDHPriv, dhGrp) + if !dhGrp.Inside(partner.DhPubKey.GetLargeInt()) { + return 0, errors.Errorf("partner's DH public key is not in the E2E "+ + "group; E2E group fingerprint is %d and DH key has %d", + dhGrp.GetFingerprint(), partner.DhPubKey.GetGroupFingerprint()) + } ownership := cAuth.MakeOwnershipProof(historicalDHPriv, partner.DhPubKey, dhGrp) confirmFp := cAuth.MakeOwnershipProofFP(ownership) diff --git a/auth/utils_test.go b/auth/utils_test.go index 5f27a218e0651736ace0ca165ef44e0ef581b05d..4136860e379218229be76f900d4484642741c919 100644 --- a/auth/utils_test.go +++ b/auth/utils_test.go @@ -61,9 +61,8 @@ func (m mockE2eHandler) StartProcesses() (stoppable.Stoppable, error) { } func (m mockE2eHandler) SendE2E(mt catalog.MessageType, recipient *id.ID, - payload []byte, params e2e.Params) ([]id.Round, cryptoE2e.MessageID, - time.Time, error) { - return nil, cryptoE2e.MessageID{}, time.Time{}, nil + payload []byte, params e2e.Params) (cryptoE2e.SendReport, error) { + return cryptoE2e.SendReport{}, nil } func (m mockE2eHandler) RegisterListener(senderID *id.ID, diff --git a/bindings/connect.go b/bindings/connect.go index 912ee6ffa9744e12a5b44ae626a198cb6e9bb36e..927d162aa921fae460b9849e8259c77f56afbb99 100644 --- a/bindings/connect.go +++ b/bindings/connect.go @@ -85,7 +85,7 @@ func (c *Cmix) Connect(e2eId int, recipientContact, e2eParamsJSON []byte) ( // - []byte - the JSON marshalled bytes of the E2ESendReport object, which can // be passed into Cmix.WaitForRoundResult to see if the send succeeded. func (c *Connection) SendE2E(mt int, payload []byte) ([]byte, error) { - rounds, mid, ts, err := c.connection.SendE2E(catalog.MessageType(mt), payload, + sendReport, err := c.connection.SendE2E(catalog.MessageType(mt), payload, c.params.Base) if err != nil { @@ -93,9 +93,10 @@ func (c *Connection) SendE2E(mt int, payload []byte) ([]byte, error) { } sr := E2ESendReport{ - RoundsList: makeRoundsList(rounds...), - MessageID: mid.Marshal(), - Timestamp: ts.UnixNano(), + RoundsList: makeRoundsList(sendReport.RoundList...), + MessageID: sendReport.MessageId.Marshal(), + Timestamp: sendReport.SentTime.UnixNano(), + KeyResidue: sendReport.KeyResidue.Marshal(), } return json.Marshal(&sr) diff --git a/bindings/e2eHandler.go b/bindings/e2eHandler.go index b71d6646d85eec5cea9a4450979d75003e20b9d2..95256801441ed19654d1d516e824149c3ee040ea 100644 --- a/bindings/e2eHandler.go +++ b/bindings/e2eHandler.go @@ -10,12 +10,12 @@ package bindings import ( "encoding/json" "fmt" + "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/cmix/identity/receptionID" "gitlab.com/elixxir/client/cmix/rounds" - "gitlab.com/elixxir/client/e2e" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" ) @@ -24,15 +24,17 @@ import ( // SendE2E. // // Example E2ESendReport: -// { -// "Rounds":[1,5,9], -// "MessageID":"51Yy47uZbP0o2Y9B/kkreDLTB6opUol3M3mYiY2dcdQ=", -// "Timestamp":1653582683183384000 -// } +//{ +//"Rounds": [ 1, 4, 9], +//"MessageID": "iM34yCIr4Je8ZIzL9iAAG1UWAeDiHybxMTioMAaezvs=", +//"Timestamp": 1661532254302612000, +//"KeyResidue": "9q2/A69EAuFM1hFAT7Bzy5uGOQ4T6bPFF72h5PlgCWE=" +//} type E2ESendReport struct { RoundsList - MessageID []byte - Timestamp int64 + MessageID []byte + Timestamp int64 + KeyResidue []byte } // GetReceptionID returns the marshalled default IDs. @@ -121,28 +123,33 @@ func (e *E2e) RemoveService(tag string) error { // - []byte - the JSON marshalled bytes of the E2ESendReport object, which can // be passed into Cmix.WaitForRoundResult to see if the send succeeded. func (e *E2e) SendE2E(messageType int, recipientId, payload, - e2eParams []byte) ([]byte, error) { - // Note that specifically these are the Base params from xxdk.E2EParams - params := e2e.GetDefaultParams() - err := params.UnmarshalJSON(e2eParams) + e2eParamsJSON []byte) ([]byte, error) { + if len(e2eParamsJSON) == 0 { + jww.WARN.Printf("e2e params not specified, using defaults...") + e2eParamsJSON = GetDefaultE2EParams() + } + params, err := parseE2EParams(e2eParamsJSON) if err != nil { return nil, err } + recipient, err := id.Unmarshal(recipientId) if err != nil { return nil, err } - roundIds, messageId, ts, err := e.api.GetE2E().SendE2E( - catalog.MessageType(messageType), recipient, payload, params) + sendReport, err := e.api.GetE2E().SendE2E( + catalog.MessageType(messageType), recipient, payload, + params.Base) if err != nil { return nil, err } result := E2ESendReport{ - RoundsList: makeRoundsList(roundIds...), - MessageID: messageId.Marshal(), - Timestamp: ts.UnixNano(), + RoundsList: makeRoundsList(sendReport.RoundList...), + MessageID: sendReport.MessageId.Marshal(), + Timestamp: sendReport.SentTime.UnixNano(), + KeyResidue: sendReport.KeyResidue.Marshal(), } return json.Marshal(result) } diff --git a/bindings/follow.go b/bindings/follow.go index 6267a34125388a681827437d7a1e1cea1aa1c8dd..199990bd69ee51e2b377d501ec537399dca89eab 100644 --- a/bindings/follow.go +++ b/bindings/follow.go @@ -10,6 +10,7 @@ package bindings import ( "encoding/json" "fmt" + "gitlab.com/elixxir/client/cmix/message" "time" "github.com/pkg/errors" @@ -168,3 +169,50 @@ func (c *Cmix) RegisterClientErrorCallback(clientError ClientError) { } }() } + +// TrackServicesCallback is the callback for Cmix.TrackServices. +// This will pass to the user a JSON-marshalled list of backend services. +// If there was an error retrieving or marshalling the service list, +// there is an error for the second parameter which will be non-null. +// +// Example JSON: +// +// [ +// { +// "Id": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", +// "Services": [ +// { +// "Identifier": null, +// "Tag": "test", +// "Metadata": null +// } +// ] +// }, +// { +// "Id": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", +// "Services": [ +// { +// "Identifier": null, +// "Tag": "test", +// "Metadata": null +// } +// ] +// }, +//] +type TrackServicesCallback interface { + Callback(marshalData []byte, err error) +} + +// TrackServices will return via a callback the list of services the +// backend keeps track of, which is formally referred to as a +// [message.ServiceList]. This may be passed into other bindings call which +// may need context on the available services for this client. +// +// Parameters: +// - cb - A TrackServicesCallback, which will be passed the marshalled +// message.ServiceList. +func (c *Cmix) TrackServices(cb TrackServicesCallback) { + c.api.GetCmix().TrackServices(func(list message.ServiceList) { + cb.Callback(json.Marshal(list)) + }) +} diff --git a/bindings/group.go b/bindings/group.go index 709a969091b8bbddd5a2d242e8ddab0e51312e9a..4d8af5a16450d7c451cec10f16600383b5250500 100644 --- a/bindings/group.go +++ b/bindings/group.go @@ -46,15 +46,15 @@ func (ut *groupTracker) make(g gs.Group) *Group { ut.mux.Lock() defer ut.mux.Unlock() - id := ut.count + utID := ut.count ut.count++ - ut.tracked[id] = &Group{ + ut.tracked[utID] = &Group{ g: g, - id: id, + id: utID, } - return ut.tracked[id] + return ut.tracked[utID] } // get a Group from the groupChatTracker given its ID. @@ -148,7 +148,7 @@ func (g *GroupChat) MakeGroup( } // Construct group - grp, rounds, status, err := g.m.MakeGroup(members, name, message) + grp, roundIDs, status, err := g.m.MakeGroup(members, name, message) if err != nil { return nil, err } @@ -156,7 +156,7 @@ func (g *GroupChat) MakeGroup( // Construct the group report report := GroupReport{ Id: grp.ID.Bytes(), - RoundsList: makeRoundsList(rounds...), + RoundsList: makeRoundsList(roundIDs...), Status: int(status), } @@ -365,7 +365,26 @@ func (g *Group) GetCreatedMS() int64 { // All subsequent members are ordered by their ID. // // Returns: -// - []byte - a JSON marshalled version of the member list. +// - []byte - JSON marshalled [group.Membership], which is an array of +// [group.Member]. +// +// Example JSON [group.Membership] return: +// [ +// { +// "ID": "U4x/lrFkvxuXu59LtHLon1sUhPJSCcnZND6SugndnVID", +// "DhKey": { +// "Value": 3534334367214237261, +// "Fingerprint": 16801541511233098363 +// } +// }, +// { +// "ID": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD", +// "DhKey": { +// "Value": 7497468244883513247, +// "Fingerprint": 16801541511233098363 +// } +// } +// ] func (g *Group) GetMembership() ([]byte, error) { return json.Marshal(g.g.Members) } diff --git a/bindings/json_test.go b/bindings/json_test.go new file mode 100644 index 0000000000000000000000000000000000000000..b42bc6806ab14d52f7a731513e72d4234164d084 --- /dev/null +++ b/bindings/json_test.go @@ -0,0 +1,33 @@ +package bindings + +import ( + "encoding/json" + "gitlab.com/elixxir/crypto/e2e" + "math/rand" + "testing" + "time" +) + +func TestName(t *testing.T) { + rl := []uint64{1, 4, 9} + prng := rand.New(rand.NewSource(42)) + rfp := make([]byte, 32) + prng.Read(rfp) + mid := e2e.NewMessageID(rfp, prng.Uint64()) + + randData := make([]byte, 32) + prng.Read(randData) + k := e2e.Key{} + copy(k[:], randData) + kr := e2e.NewKeyResidue(k) + + report := E2ESendReport{ + RoundsList: RoundsList{rl}, + MessageID: mid.Marshal(), + Timestamp: time.Now().UnixNano(), + KeyResidue: kr.Marshal(), + } + + marshal, _ := json.Marshal(report) + t.Logf("%s", marshal) +} diff --git a/bindings/notifications.go b/bindings/notifications.go index bbc79ca79c028ceac33a5ba1e972119f904aa4ba..e028ae0ce7a2186a2afd67873e668e7109a33022 100644 --- a/bindings/notifications.go +++ b/bindings/notifications.go @@ -7,67 +7,141 @@ package bindings -// FIXME: This is the old NotificationsForMe code that needs to be fixed -/* -type NotificationForMeReport struct { - ForMe bool - Type string +import ( + "encoding/json" + "gitlab.com/elixxir/client/cmix/message" + "gitlab.com/elixxir/primitives/notifications" +) + +// NotificationReports is a list of NotificationReport's. This will be returned +// via GetNotificationsReport as a JSON marshalled byte data. +// +// Example JSON: +// +// [ +// { +// "ForMe": true, +// "Type": "e2e", +// "Source": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD" +// }, +// { +// "ForMe": true, +// "Type": "e2e", +// "Source": "AAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD" +// }, +// { +// "ForMe": true, +// "Type": "e2e", +// "Source": "AAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD" +// } +//] +type NotificationReports []NotificationReport + +// NotificationReport is the bindings' representation for notifications for +// this user. +// +// Example NotificationReport JSON: +// +// { +// "ForMe": true, +// "Type": "e2e", +// "Source": "dGVzdGVyMTIzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +//} +// +// Given the Type, the Source value will have specific contextual meanings. +// Below is a table that will define the contextual meaning of the Source field +// given all possible Type fields. +// +// TYPE | SOURCE | DESCRIPTION +// ________________________________________________________________________________________ +// "default" | recipient user ID | A message with no association. +// "request" | sender user ID | A channel request has been received, from Source. +// "reset" | sender user ID | A channel reset has been received. +// "confirm" | sender user ID | A channel request has been accepted. +// "silent" | sender user ID | A message where the user should not be notified. +// "e2e" | sender user ID | A reception of an E2E message. +// "group" | group ID | A reception of a group chat message. +// "endFT" | sender user ID | The last message sent confirming end of file transfer. +// "groupRQ" | sender user ID | A request from Source to join a group chat. +// todo iterate over this docstring, ensure descriptions/sources are +// still accurate (they are from the old implementation +type NotificationReport struct { + // ForMe determines whether this value is for the user. If it is + // false, this report may be ignored. + ForMe bool + // Type is the type of notification. The list can be seen + Type string + // Source is the source of the notification. Source []byte } -type ManyNotificationForMeReport struct { - Many []*NotificationForMeReport -} +// GetNotificationsReport parses the received notification data to determine which +// notifications are for this user. // This returns the JSON-marshalled +// NotificationReports. +// +// Parameters: +// - e2eID - e2e object ID in the tracker +// - notificationCSV - the notification data received from the +// notifications' server. +// - marshalledServices - the JSON-marshalled list of services the backend +// keeps track of. Refer to Cmix.TrackServices for information about this. +// +// Returns: +// - []byte - A JSON marshalled NotificationReports. Some NotificationReport's +// within in this structure may have their NotificationReport.ForMe +// set to false. These may be ignored. +func GetNotificationsReport(e2eId int, notificationCSV string, + marshalledServices []byte) ([]byte, error) { + // Retrieve user + user, err := e2eTrackerSingleton.get(e2eId) + if err != nil { + return nil, err + } -// NotificationsForMe Check if a notification received is for me -// It returns a NotificationForMeReport which contains a ForMe bool stating if it is for the caller, -// a Type, and a source. These are as follows: -// TYPE SOURCE DESCRIPTION -// "default" recipient user ID A message with no association -// "request" sender user ID A channel request has been received -// "reset" sender user ID A channel reset has been received -// "confirm" sender user ID A channel request has been accepted -// "silent" sender user ID A message which should not be notified on -// "e2e" sender user ID reception of an E2E message -// "group" group ID reception of a group chat message -// "endFT" sender user ID Last message sent confirming end of file transfer -// "groupRQ" sender user ID Request from sender to join a group chat -func NotificationsForMe(notifCSV, preimages string) (*ManyNotificationForMeReport, error) { - // Handle deserialization of preimages - var preimageList []edge.Preimage - if err := json.Unmarshal([]byte(preimages), &preimageList); err != nil { - return nil, errors.WithMessagef(err, "Failed to unmarshal the " + - "preimages list, cannot check if notification is for me") + serviceList := message.ServiceList{} + err = json.Unmarshal(marshalledServices, &serviceList) + if err != nil { + return nil, err } - list, err := notifications.DecodeNotificationsCSV(notifCSV) + // Retrieve the services for this user + services := serviceList[*user.api.GetReceptionIdentity().ID] + + // Decode notifications' server data + notificationList, err := notifications.DecodeNotificationsCSV(notificationCSV) if err != nil { return nil, err } - notifList := make([]*NotificationForMeReport, len(list)) + // Construct a report list + reportList := make([]*NotificationReport, len(notificationList)) - for i, notifData := range list { - notifList[i] = &NotificationForMeReport{ - ForMe: false, - Type: "", - Source: nil, - } - // check if any preimages match with the passed in data - for _, preimage := range preimageList { - if fingerprint.CheckIdentityFpFromMessageHash(notifData.IdentityFP, notifData.MessageHash, preimage.Data) { - notifList[i] = &NotificationForMeReport{ + // Iterate over data provided by server + for i := range notificationList { + notifData := notificationList[i] + + // Iterate over all services + for j := range services { + // Pull data from services and from notification data + service := services[j] + messageHash := notifData.MessageHash + hash := service.HashFromMessageHash(notifData.MessageHash) + + // Check if this notification data is recognized by + // this service, ie "ForMe" + if service.ForMeFromMessageHash(messageHash, hash) { + // Fill report list with service data + reportList[i] = &NotificationReport{ ForMe: true, - Type: preimage.Type, - Source: preimage.Source, + Type: service.Tag, + Source: service.Identifier, } - break } } } - return &ManyNotificationForMeReport{notifList}, nil -}*/ + return json.Marshal(reportList) +} // RegisterForNotifications allows a client to register for push notifications. // The token is a firebase messaging token. diff --git a/bindings/notifications_test.go b/bindings/notifications_test.go new file mode 100644 index 0000000000000000000000000000000000000000..390062f08456961cb3e18eb84675e64f18e867b8 --- /dev/null +++ b/bindings/notifications_test.go @@ -0,0 +1,28 @@ +package bindings + +import ( + "encoding/json" + "fmt" + "gitlab.com/elixxir/client/e2e/ratchet" + "gitlab.com/xx_network/primitives/id" + "testing" +) + +func TestNotificationReport(t *testing.T) { + reports := []NotificationReport{} + + for i := 0; i < 3; i++ { + nr := NotificationReport{ + ForMe: true, + Type: ratchet.E2e, + Source: id.NewIdFromUInt(uint64(i), id.User, t).Bytes(), + } + + reports = append(reports, nr) + } + + nrs := NotificationReports(reports) + + marshal, _ := json.Marshal(nrs) + fmt.Printf("%s\n", marshal) +} diff --git a/bindings/single.go b/bindings/single.go index ca0e855cb2bdd53baa1da576ec198f2db5587976..a3bacbce28c6db129ae233ea0c684ad9b90a9817 100644 --- a/bindings/single.go +++ b/bindings/single.go @@ -166,7 +166,7 @@ type Stopper interface { // Parameters: // - callbackReport - the JSON marshalled bytes of the SingleUseCallbackReport // object, which can be passed into Cmix.WaitForRoundResult to see if the -// send succeeded. +// send operation succeeded. type SingleUseCallback interface { Callback(callbackReport []byte, err error) } @@ -177,7 +177,7 @@ type SingleUseCallback interface { // Parameters: // - callbackReport - the JSON marshalled bytes of the SingleUseResponseReport // object, which can be passed into Cmix.WaitForRoundResult to see if the -// send succeeded. +// send operation succeeded. type SingleUseResponse interface { Callback(responseReport []byte, err error) } diff --git a/bindings/ud.go b/bindings/ud.go index 217fb964b7f4b5d313f323fca5df46d95cf9d577..3a3f21a0d43a4905ba5645d40cd38f4e82ed4854 100644 --- a/bindings/ud.go +++ b/bindings/ud.go @@ -429,8 +429,15 @@ func LookupUD(e2eID int, udContact []byte, cb UdLookupCallback, // // Parameters: // - contactListJSON - the JSON marshalled bytes of []contact.Contact, or nil -// if an error occurs -// - err - any errors that occurred in the search +// if an error occurs. +// +// JSON Example: +// { +// "<xxc(2)F8dL9EC6gy+RMJuk3R+Au6eGExo02Wfio5cacjBcJRwDEgB7Ugdw/BAr6RkCABkWAFV1c2VybmFtZTA7c4LzV05sG+DMt+rFB0NIJg==xxc>", +// "<xxc(2)eMhAi/pYkW5jCmvKE5ZaTglQb+fTo1D8NxVitr5CCFADEgB7Ugdw/BAr6RoCABkWAFV1c2VybmFtZTE7fElAa7z3IcrYrrkwNjMS2w==xxc>", +// "<xxc(2)d7RJTu61Vy1lDThDMn8rYIiKSe1uXA/RCvvcIhq5Yg4DEgB7Ugdw/BAr6RsCABkWAFV1c2VybmFtZTI7N3XWrxIUpR29atpFMkcR6A==xxc>" +// } +// - err - any errors that occurred in the search. type UdSearchCallback interface { Callback(contactListJSON []byte, err error) } @@ -451,7 +458,7 @@ type UdSearchCallback interface { // Returns: // - []byte - the JSON marshalled bytes of the SingleUseSendReport object, // which can be passed into Cmix.WaitForRoundResult to see if the send -// succeeded. +// operation succeeded. func SearchUD(e2eID int, udContact []byte, cb UdSearchCallback, factListJSON, singleRequestParamsJSON []byte) ([]byte, error) { @@ -479,7 +486,20 @@ func SearchUD(e2eID int, udContact []byte, cb UdSearchCallback, } callback := func(contactList []contact.Contact, err error) { - contactListJSON, err2 := json.Marshal(contactList) + marshaledContactList := make([][]byte, 0) + // fixme: it may be wiser to change this callback interface + // to simply do the work below when parsing the response from UD. + // that would change ud/search.go in two places: + // - searchCallback + // - parseContacts + // I avoid doing that as it changes interfaces w/o approval + for i := range contactList { + con := contactList[i] + marshaledContactList = append( + marshaledContactList, con.Marshal()) + } + + contactListJSON, err2 := json.Marshal(marshaledContactList) if err2 != nil { jww.FATAL.Panicf( "Failed to marshal list of contact.Contact: %+v", err2) diff --git a/cmd/connect.go b/cmd/connect.go index e8697dc60b8f0b5181df175274e12e881ce12b78..7b31c2cd8be6557f64f214ddf781c375fe6ce319 100644 --- a/cmd/connect.go +++ b/cmd/connect.go @@ -486,7 +486,7 @@ func miscConnectionFunctions(user *xxdk.E2e, conn connect.Connection) { conn.GetPartner().PartnerId()) payload := []byte(msgBody) for { - roundIDs, _, _, err := conn.SendE2E(catalog.XxMessage, payload, + sendReport, err := conn.SendE2E(catalog.XxMessage, payload, paramsE2E) if err != nil { jww.FATAL.Panicf("[CONN] Failed to send E2E message: %v", err) @@ -494,7 +494,7 @@ func miscConnectionFunctions(user *xxdk.E2e, conn connect.Connection) { // Verify message sends were successful when verifySendFlag is present if viper.GetBool(verifySendFlag) { - if !verifySendSuccess(user, paramsE2E, roundIDs, + if !verifySendSuccess(user, paramsE2E, sendReport.RoundList, conn.GetPartner().PartnerId(), payload) { continue } diff --git a/cmd/flags.go b/cmd/flags.go index 93b5d505d77f4846f80d1cda6b32bfa29a0ad3cf..edd40259a56eb227c267811c125ffab746ec0f67 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -80,7 +80,9 @@ const ( // Misc sendIdFlag = "sendid" profileCpuFlag = "profile-cpu" + profileMemFlag = "profile-mem" userIdPrefixFlag = "userid-prefix" + legacyFlag = "legacy" ///////////////// Broadcast subcommand flags ////////////////////////////// broadcastNameFlag = "name" diff --git a/cmd/init.go b/cmd/init.go index e78ef22bb78387d64210e9d7365bc76fa765fd94..00294f2c4a79d6bd38ce9c330df5b86466a608c3 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -45,16 +45,27 @@ var initCmd = &cobra.Command{ jww.FATAL.Panicf("%+v", err) } - identity, err := xxdk.MakeReceptionIdentity(net) + // Generate identity + var identity xxdk.ReceptionIdentity + if viper.GetBool(legacyFlag) { + identity, err = xxdk.MakeLegacyReceptionIdentity(net) + } else { + identity, err = xxdk.MakeReceptionIdentity(net) + + } + + // Panic if conditional branch fails if err != nil { jww.FATAL.Panicf("%+v", err) } + // Store identity err = xxdk.StoreReceptionIdentity(identityStorageKey, identity, net) if err != nil { jww.FATAL.Panicf("%+v", err) } + // Write contact to file jww.INFO.Printf("User: %s", identity.ID) writeContact(identity.GetContact()) @@ -68,6 +79,11 @@ func init() { "Desired prefix of userID to brute force when running init command. Prepend (?i) for case-insensitive. Only Base64 characters are valid.") bindFlagHelper(userIdPrefixFlag, initCmd) + initCmd.Flags().BoolP(legacyFlag, "", false, + "Generates a legacy identity if set. "+ + "If this flag is absent, a standard identity will be generated.") + bindFlagHelper(legacyFlag, initCmd) + rootCmd.AddCommand(initCmd) } diff --git a/cmd/root.go b/cmd/root.go index 837b68e1af7d13f8476844c3bb0f525be4bcbd63..c3366aaf76240b114c3e6e4b0d0899058a4fbe91 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -14,10 +14,13 @@ import ( "encoding/hex" "encoding/json" "fmt" + cryptoE2e "gitlab.com/elixxir/crypto/e2e" "io/ioutil" "log" "os" - "runtime/pprof" + + "github.com/pkg/profile" + "strconv" "strings" "sync" @@ -58,13 +61,17 @@ var rootCmd = &cobra.Command{ Short: "Runs a client for cMix anonymous communication platform", Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - profileOut := viper.GetString(profileCpuFlag) - if profileOut != "" { - f, err := os.Create(profileOut) - if err != nil { - jww.FATAL.Panicf("%+v", err) - } - pprof.StartCPUProfile(f) + cpuProfileOut := viper.GetString(profileCpuFlag) + if cpuProfileOut != "" { + defer profile.Start(profile.CPUProfile, + profile.ProfilePath(cpuProfileOut), + profile.NoShutdownHook).Stop() + } + memProfileOut := viper.GetString(profileMemFlag) + if memProfileOut != "" { + defer profile.Start(profile.MemProfile, + profile.ProfilePath(memProfileOut), + profile.NoShutdownHook).Stop() } cmixParams, e2eParams := initParams() @@ -288,8 +295,10 @@ var rootCmd = &cobra.Command{ e2eParams.Base) } else { e2eParams.Base.DebugTag = "cmd.E2E" - roundIDs, _, _, err = user.GetE2E().SendE2E(mt, + var sendReport cryptoE2e.SendReport + sendReport, err = user.GetE2E().SendE2E(mt, recipient, payload, e2eParams.Base) + roundIDs = sendReport.RoundList } if err != nil { jww.FATAL.Panicf("%+v", err) @@ -382,9 +391,6 @@ var rootCmd = &cobra.Command{ "Failed to cleanly close threads: %+v\n", err) } - if profileOut != "" { - pprof.StopCPUProfile() - } jww.INFO.Printf("Client exiting!") }, } @@ -1101,6 +1107,10 @@ func init() { "Enable cpu profiling to this file") viper.BindPFlag(profileCpuFlag, rootCmd.Flags().Lookup(profileCpuFlag)) + rootCmd.Flags().String(profileMemFlag, "", + "Enable memory profiling to this file") + viper.BindPFlag(profileMemFlag, rootCmd.Flags().Lookup(profileMemFlag)) + // Proto user flags rootCmd.Flags().String(protoUserPathFlag, "", "Path to proto user JSON file containing cryptographic primitives "+ diff --git a/cmix/client.go b/cmix/client.go index 996cacdb46016a7675cde906cbcd9c66dc68c766..fb326f72ac1fcdc8c75cf7e61645bbca8f4fc061 100644 --- a/cmix/client.go +++ b/cmix/client.go @@ -246,6 +246,9 @@ func (c *client) Follow(report ClientErrorReport) (stoppable.Stoppable, error) { // Start the processes for the identity handler multi.Add(c.Tracker.StartProcesses()) + //Start the critical processing thread + multi.Add(c.crit.startProcessies()) + return multi, nil } diff --git a/cmix/critical.go b/cmix/critical.go index 03ebfc7b56429b0fd0e8f588fa5ca2fe2e809491..719e6d9f0eff0774bdf083f01f07034a58ab6127 100644 --- a/cmix/critical.go +++ b/cmix/critical.go @@ -1,6 +1,8 @@ package cmix import ( + "time" + jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/cmix/health" "gitlab.com/elixxir/client/stoppable" @@ -10,7 +12,6 @@ import ( "gitlab.com/elixxir/primitives/states" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" - "time" ) const criticalRawMessagesKey = "RawCriticalMessages" @@ -58,6 +59,12 @@ func newCritical(kv *versioned.KV, hm health.Monitor, return c } +func (c *critical) startProcessies() *stoppable.Single { + stop := stoppable.NewSingle("criticalStopper") + go c.runCriticalMessages(stop) + return stop +} + func (c *critical) runCriticalMessages(stop *stoppable.Single) { for { select { diff --git a/cmix/identity/tracker.go b/cmix/identity/tracker.go index 961aac77627f0f5ef15ed35b839c2c5eaafa9b4b..8d9f8a6d2a168d27147f9fe280f2d777e0b9935c 100644 --- a/cmix/identity/tracker.go +++ b/cmix/identity/tracker.go @@ -55,7 +55,7 @@ type Tracker interface { } type manager struct { - tracked []TrackedID + tracked []*TrackedID ephemeral *receptionID.Store session storage.Session newIdentity chan TrackedID @@ -76,7 +76,7 @@ type TrackedID struct { func NewOrLoadTracker(session storage.Session, addrSpace address.Space) *manager { // Initialization t := &manager{ - tracked: make([]TrackedID, 0), + tracked: make([]*TrackedID, 0), session: session, newIdentity: make(chan TrackedID, trackedIDChanSize), deleteIdentity: make(chan *id.ID, deleteIDChanSize), @@ -92,7 +92,7 @@ func NewOrLoadTracker(session storage.Session, addrSpace address.Space) *manager jww.WARN.Printf("No tracked identities found, creating a new " + "tracked identity from legacy stored timestamp.") - t.tracked = append(t.tracked, TrackedID{ + t.tracked = append(t.tracked, &TrackedID{ // Make the next generation now so a generation triggers on // first run NextGeneration: netTime.Now(), @@ -155,7 +155,7 @@ func (t *manager) GetIdentity(get *id.ID) (TrackedID, error) { defer t.mux.Unlock() for i := range t.tracked { if get.Cmp(t.tracked[i].Source) { - return t.tracked[i], nil + return *t.tracked[i], nil } } return TrackedID{}, errors.Errorf("could not find id %s", get) @@ -201,7 +201,7 @@ func (t *manager) track(stop *stoppable.Single) { if !isOld { jww.DEBUG.Printf("Tracking new identity %s", newIdentity.Source) // Otherwise, add it to the list and run - t.tracked = append(t.tracked, newIdentity) + t.tracked = append(t.tracked, &newIdentity) } t.save() @@ -236,7 +236,8 @@ func (t *manager) processIdentities(addressSize uint8) time.Time { nextEvent := netTime.Now().Add(time.Duration(ephemeral.Period)) // Loop through every tracked ID and see if any operations are needed - for i, inQuestion := range t.tracked { + for i := range t.tracked { + inQuestion := t.tracked[i] // Generate new ephemeral if is time for it if netTime.Now().After(inQuestion.NextGeneration) { nextGeneration := t.generateIdentitiesOverRange(inQuestion, addressSize) @@ -267,7 +268,7 @@ func (t *manager) processIdentities(addressSize uint8) time.Time { // Process any deletions if len(toRemove) > 0 { - newTracked := make([]TrackedID, 0, len(t.tracked)) + newTracked := make([]*TrackedID, 0, len(t.tracked)) for i := range t.tracked { if _, remove := toRemove[i]; !remove { newTracked = append(newTracked, t.tracked[i]) @@ -305,7 +306,7 @@ func unmarshalTimestamp(lastTimestampObj *versioned.Object) (time.Time, error) { // generateIdentitiesOverRange generates and adds all not yet existing ephemeral Ids // and returns the timestamp of the next generation for the given TrackedID -func (t *manager) generateIdentitiesOverRange(inQuestion TrackedID, +func (t *manager) generateIdentitiesOverRange(inQuestion *TrackedID, addressSize uint8) time.Time { // Ensure that ephemeral IDs will not be generated after the // identity is invalid @@ -374,7 +375,7 @@ func (t *manager) save() { for i := range t.tracked { if t.tracked[i].Persistent { - persistent = append(persistent, t.tracked[i]) + persistent = append(persistent, *t.tracked[i]) } } diff --git a/cmix/identity/tracker_test.go b/cmix/identity/tracker_test.go index d16f64b5526f30e2d9719974ad1f82560b7f6b1f..dc9a895764c996abf1cf947c92139f2b7a23c71e 100644 --- a/cmix/identity/tracker_test.go +++ b/cmix/identity/tracker_test.go @@ -67,7 +67,7 @@ func TestManager_processIdentities(t *testing.T) { addrSpace.UpdateAddressSpace(18) session := storage.InitTestingSession(t) m := &manager{ - tracked: make([]TrackedID, 0), + tracked: make([]*TrackedID, 0), session: session, newIdentity: make(chan TrackedID, trackedIDChanSize), deleteIdentity: make(chan *id.ID, deleteIDChanSize), @@ -79,7 +79,7 @@ func TestManager_processIdentities(t *testing.T) { // Add some expired test IDs testId := id.NewIdFromUInt(0, id.User, t) validUntil := netTime.Now().Add(time.Minute) - m.tracked = append(m.tracked, TrackedID{ + m.tracked = append(m.tracked, &TrackedID{ NextGeneration: netTime.Now(), LastGeneration: time.Time{}, Source: testId, diff --git a/cmix/message/serviceTracker.go b/cmix/message/serviceTracker.go index 616f6dfda392ba4cb65c8d02179bbae493fe26ec..e3313a4de659d935b26d6e4477c1e5056a558497 100644 --- a/cmix/message/serviceTracker.go +++ b/cmix/message/serviceTracker.go @@ -26,7 +26,6 @@ func (sm *ServicesManager) triggerServiceTracking() { if len(sm.trackers) == 0 { return } - services := make(ServiceList) for uid, tmap := range sm.tmap { tList := make([]Service, 0, len(tmap)) diff --git a/cmix/message/serviceTracker_test.go b/cmix/message/serviceTracker_test.go index c7b06b46a853bcc23e267830c9e2cda925385b3a..a1a487762c271bde32476a07652cfd4264b311bf 100644 --- a/cmix/message/serviceTracker_test.go +++ b/cmix/message/serviceTracker_test.go @@ -13,7 +13,7 @@ import ( func TestServiceList_Marshal_UnmarshalJSON(t *testing.T) { var sl ServiceList = make(map[id.ID][]Service) - numServices := 10 + numServices := 3 testString := "test" for i := 0; i < numServices; i++ { uid := id.NewIdFromUInt(uint64(i), id.User, t) @@ -24,6 +24,8 @@ func TestServiceList_Marshal_UnmarshalJSON(t *testing.T) { t.Errorf(err.Error()) } + t.Logf("%s", jsonResult) + sl = make(map[id.ID][]Service) err = sl.UnmarshalJSON(jsonResult) if err != nil { diff --git a/cmix/sendCmix.go b/cmix/sendCmix.go index 73dfcfbd2c02b6f1cafcf49cd4662826edf7e3e8..f0c97a6ffc47f7611bc73d22132f2d0e087abe72 100644 --- a/cmix/sendCmix.go +++ b/cmix/sendCmix.go @@ -109,6 +109,12 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, nodes nodes.Registrar, rng *fastRNG.StreamGenerator, events event.Reporter, senderId *id.ID, comms SendCmixCommsInterface) (id.Round, ephemeral.Id, error) { + if cmixParams.RoundTries == 0 { + return 0, ephemeral.Id{}, + errors.Errorf("invalid parameter set, "+ + "RoundTries cannot be 0: %+v", cmixParams) + } + timeStart := netTime.Now() maxTimeout := sender.GetHostParams().SendTimeout @@ -120,7 +126,8 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, } jww.INFO.Printf("[Send-%s] Looking for round to send cMix message to "+ - "%s (msgDigest: %s)", cmixParams.DebugTag, recipient, msg.Digest()) + "%s (msgDigest: %s)", cmixParams.DebugTag, recipient, + msg.Digest()) stream := rng.GetStream() defer stream.Close() @@ -129,7 +136,8 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, // See cmix.SetGroupBits for more info. cmix.SetGroupBits(msg, grp, stream) - for numRoundTries := uint(0); numRoundTries < cmixParams.RoundTries; numRoundTries++ { + for numRoundTries := uint( + 0); numRoundTries < cmixParams.RoundTries; numRoundTries++ { elapsed := netTime.Since(timeStart) jww.TRACE.Printf("[Send-%s] try %d, elapsed: %s", cmixParams.DebugTag, numRoundTries, elapsed) @@ -137,42 +145,50 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, if elapsed > cmixParams.Timeout { jww.INFO.Printf("[Send-%s] No rounds to send to %s "+ "(msgDigest: %s) were found before timeout %s", - cmixParams.DebugTag, recipient, msg.Digest(), cmixParams.Timeout) - return 0, ephemeral.Id{}, errors.New("Sending cmix message timed out") + cmixParams.DebugTag, recipient, msg.Digest(), + cmixParams.Timeout) + return 0, ephemeral.Id{}, errors.New( + "Sending cmix message timed out") } if numRoundTries > 0 { - jww.INFO.Printf("[Send-%s] Attempt %d to find round to send "+ - "message to %s (msgDigest: %s)", cmixParams.DebugTag, + jww.INFO.Printf("[Send-%s] Attempt %d to find round"+ + " to send message to %s (msgDigest: %s)", + cmixParams.DebugTag, numRoundTries+1, recipient, msg.Digest()) } // Find the best round to send to, excluding attempted rounds remainingTime := cmixParams.Timeout - elapsed - bestRound, err := instance.GetWaitingRounds().GetUpcomingRealtime( + waitingRounds := instance.GetWaitingRounds() + bestRound, err := waitingRounds.GetUpcomingRealtime( remainingTime, attempted, sendTimeBuffer) if err != nil { - jww.WARN.Printf("[Send-%s] Failed to GetUpcomingRealtime "+ - "(msgDigest: %s): %+v", cmixParams.DebugTag, msg.Digest(), err) + jww.WARN.Printf("[Send-%s] GetUpcomingRealtime failed "+ + "(msgDigest: %s): %+v", cmixParams.DebugTag, + msg.Digest(), err) } if bestRound == nil { jww.WARN.Printf( - "[Send-%s] Best round on send is nil", cmixParams.DebugTag) + "[Send-%s] Best round on send is nil", + cmixParams.DebugTag) continue } jww.TRACE.Printf("[Send-%s] Best round found: %+v", cmixParams.DebugTag, bestRound) - // Determine whether the selected round contains any nodes that are - // blacklisted by the CMIXParams object + // Determine whether the selected round contains any + // nodes that are blacklisted by the CMIXParams object containsBlacklisted := false if cmixParams.BlacklistedNodes != nil { + blacklist := cmixParams.BlacklistedNodes for _, nodeId := range bestRound.Topology { var nid id.ID copy(nid[:], nodeId) - if _, isBlacklisted := cmixParams.BlacklistedNodes[nid]; isBlacklisted { + _, isBlacklisted := blacklist[nid] + if isBlacklisted { containsBlacklisted = true break } @@ -180,8 +196,10 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, } if containsBlacklisted { - jww.WARN.Printf("[Send-%s] Round %d contains blacklisted "+ - "nodes, skipping...", cmixParams.DebugTag, bestRound.ID) + jww.WARN.Printf("[Send-%s] Round %d "+ + "contains blacklisted nodes, skipping...", + cmixParams.DebugTag, + bestRound.ID) continue } @@ -290,5 +308,5 @@ func sendCmixHelper(sender gateway.Sender, msg format.Message, recipient *id.ID, } return 0, ephemeral.Id{}, - errors.New("failed to send the message, unknown error") + errors.New("failed to send the message, out of round retries") } diff --git a/connect/authenticated.go b/connect/authenticated.go index c45489fbc78ab87ab1115ab6da02d2b0fe5167f4..b2d63f7582380f2116b6f78c14d00bedbcdc5da7 100644 --- a/connect/authenticated.go +++ b/connect/authenticated.go @@ -98,7 +98,7 @@ func connectWithAuthentication(conn Connection, timeStart time.Time, } // Send message to server - rids, _, _, err := conn.SendE2E(catalog.ConnectionAuthenticationRequest, + sendReport, err := conn.SendE2E(catalog.ConnectionAuthenticationRequest, payload, clientE2e.GetDefaultParams()) if err != nil { // Close connection on an error @@ -139,7 +139,7 @@ func connectWithAuthentication(conn Connection, timeStart time.Time, // Track the result of the round(s) we sent the // identity authentication message on err = net.GetRoundResults(remainingTime, - roundCb, rids...) + roundCb, sendReport.RoundList...) if err != nil { return nil, errors.Errorf("could not track rounds for successful " + "identity confirmation message delivery") diff --git a/connect/connect.go b/connect/connect.go index ba87dc91873e5d3153e38c60474d42b2f3e23cbc..5cc9f60a2462ed565cfdc8dd5de02fb591c29e20 100644 --- a/connect/connect.go +++ b/connect/connect.go @@ -7,6 +7,7 @@ package connect import ( + cryptoE2e "gitlab.com/elixxir/crypto/e2e" "io" "sync/atomic" "time" @@ -22,8 +23,6 @@ import ( "gitlab.com/elixxir/client/e2e/ratchet/partner" "gitlab.com/elixxir/client/e2e/receive" "gitlab.com/elixxir/crypto/contact" - "gitlab.com/elixxir/crypto/e2e" - "gitlab.com/xx_network/primitives/id" ) var alreadyClosedErr = errors.New("connection is closed") @@ -43,7 +42,7 @@ type Connection interface { // SendE2E is a wrapper for sending specifically to the Connection's // partner.Manager SendE2E(mt catalog.MessageType, payload []byte, params clientE2e.Params) ( - []id.Round, e2e.MessageID, time.Time, error) + cryptoE2e.SendReport, error) // RegisterListener is used for E2E reception // and allows for reading data sent from the partner.Manager @@ -221,9 +220,9 @@ func (h *handler) GetPartner() partner.Manager { // SendE2E is a wrapper for sending specifically to the Connection's // partner.Manager. func (h *handler) SendE2E(mt catalog.MessageType, payload []byte, - params clientE2e.Params) ([]id.Round, e2e.MessageID, time.Time, error) { + params clientE2e.Params) (cryptoE2e.SendReport, error) { if h.isClosed() { - return nil, e2e.MessageID{}, time.Time{}, alreadyClosedErr + return cryptoE2e.SendReport{}, alreadyClosedErr } h.updateLastUse(netTime.Now()) diff --git a/connect/utils_test.go b/connect/utils_test.go index 6e4be5173d00cd8ba4b671d6abee3a8669e1c77c..7fc60f5398b6361a7254cae0f72082acb17e975d 100644 --- a/connect/utils_test.go +++ b/connect/utils_test.go @@ -115,8 +115,7 @@ func (m *mockConnection) Close() error { func (m *mockConnection) GetPartner() partner.Manager { return m.partner } func (m *mockConnection) SendE2E( - mt catalog.MessageType, payload []byte, _ e2e.Params) ( - []id.Round, cryptoE2e.MessageID, time.Time, error) { + mt catalog.MessageType, payload []byte, _ e2e.Params) (cryptoE2e.SendReport, error) { m.payloadChan <- payload m.listener.Hear(receive.Message{ MessageType: mt, @@ -124,7 +123,7 @@ func (m *mockConnection) SendE2E( Sender: m.partner.myID, RecipientID: m.partner.partnerId, }) - return nil, cryptoE2e.MessageID{}, time.Time{}, nil + return cryptoE2e.SendReport{}, nil } func (m *mockConnection) RegisterListener( diff --git a/e2e/critical.go b/e2e/critical.go index 9a803886ff81faeded4e546a8462af9e78c73dc9..cc5a1ee9268e93923ae80520b5c9f211878d16bf 100644 --- a/e2e/critical.go +++ b/e2e/critical.go @@ -1,6 +1,7 @@ package e2e import ( + "gitlab.com/elixxir/crypto/e2e" "time" jww "github.com/spf13/jwalterweatherman" @@ -9,7 +10,6 @@ import ( "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/client/storage/versioned" ds "gitlab.com/elixxir/comms/network/dataStructures" - "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/primitives/format" "gitlab.com/elixxir/primitives/states" "gitlab.com/xx_network/primitives/id" @@ -29,7 +29,7 @@ type roundEventRegistrar interface { // anonymous function to include the structures from manager that critical is // not aware of. type criticalSender func(mt catalog.MessageType, recipient *id.ID, - payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error) + payload []byte, params Params) (e2e.SendReport, error) // critical is a structure that allows the auto resending of messages that must // be received. @@ -138,11 +138,11 @@ func (c *critical) evaluate(stop *stoppable.Single) { format.DigestContents(payload)) // Send the message - round, _, _, err := c.send(mt, recipient, payload, + sendReport, err := c.send(mt, recipient, payload, params) // Pass to the handler - c.handle(mt, recipient, payload, round, err) + c.handle(mt, recipient, payload, sendReport.RoundList, err) }(mt, recipient, payload, params) } diff --git a/e2e/fpGenerator_test.go b/e2e/fpGenerator_test.go index ebd2d7cc381a3d3ccc908b9118b697226bb0af59..1360d14e6c527aa7f063e49c6d19760b9a8a8b0a 100644 --- a/e2e/fpGenerator_test.go +++ b/e2e/fpGenerator_test.go @@ -16,6 +16,7 @@ import ( "gitlab.com/elixxir/client/e2e/ratchet/partner/session" "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/comms/network" + "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/comms/connect" "gitlab.com/xx_network/primitives/id" @@ -90,11 +91,15 @@ type mockSessionCypher struct { fp format.Fingerprint } -func (m mockSessionCypher) GetSession() *session.Session { return nil } -func (m mockSessionCypher) Fingerprint() format.Fingerprint { return m.fp } -func (m mockSessionCypher) Encrypt([]byte) (ecrContents, mac []byte) { return nil, nil } -func (m mockSessionCypher) Decrypt(format.Message) ([]byte, error) { return nil, nil } -func (m mockSessionCypher) Use() {} +func (m mockSessionCypher) GetSession() *session.Session { return nil } +func (m mockSessionCypher) Fingerprint() format.Fingerprint { return m.fp } +func (m mockSessionCypher) Encrypt([]byte) (ecrContents, mac []byte, residue e2e.KeyResidue) { + return nil, nil, e2e.KeyResidue{} +} +func (m mockSessionCypher) Decrypt(format.Message) ([]byte, e2e.KeyResidue, error) { + return nil, e2e.KeyResidue{}, nil +} +func (m mockSessionCypher) Use() {} //////////////////////////////////////////////////////////////////////////////// // Mock cMix // diff --git a/e2e/interface.go b/e2e/interface.go index 0578bbc719731f5d1c83a7e16330506aac8bac66..db4d4a59087883e17db9ce6f74a604e0f7645daa 100644 --- a/e2e/interface.go +++ b/e2e/interface.go @@ -2,6 +2,7 @@ package e2e import ( "gitlab.com/elixxir/client/cmix/rounds" + "gitlab.com/elixxir/crypto/e2e" "time" "github.com/cloudflare/circl/dh/sidh" @@ -12,7 +13,6 @@ import ( "gitlab.com/elixxir/client/e2e/receive" "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/e2e" "gitlab.com/xx_network/primitives/id" ) @@ -35,7 +35,7 @@ type Handler interface { // Will return an error if the network is not healthy or in // the event of a failed send SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, - params Params) ([]id.Round, e2e.MessageID, time.Time, error) + params Params) (e2e.SendReport, error) /* === Reception ==================================================== */ diff --git a/e2e/manager.go b/e2e/manager.go index bd7c313811a792ddc5535f8e4ab0f00cd97406b0..9fc1b4b3d123a4d0b6657cc2ddfa955f72866802 100644 --- a/e2e/manager.go +++ b/e2e/manager.go @@ -4,10 +4,9 @@ import ( "bytes" "encoding/base64" "encoding/json" - "sync" - "time" - jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/crypto/e2e" + "sync" "gitlab.com/xx_network/primitives/netTime" @@ -23,7 +22,6 @@ import ( "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/xx_network/primitives/id" ) @@ -214,8 +212,7 @@ func (m *manager) StartProcesses() (stoppable.Stoppable, error) { rekeySendFunc := func(mt catalog.MessageType, recipient *id.ID, payload []byte, - cmixParams cmix.CMIXParams) ( - []id.Round, e2e.MessageID, time.Time, error) { + cmixParams cmix.CMIXParams) (e2e.SendReport, error) { // FIXME: we should have access to the e2e params here... par := GetDefaultParams() par.CMIXParams = cmixParams @@ -284,14 +281,15 @@ func (m *manager) DeletePartnerNotify(partnerId *id.ID, params Params) error { m.DeletePartnerCallbacks(partnerId) // Send closing E2E message - rounds, msgID, timestamp, err := sendFunc() + + sendReport, err := sendFunc() if err != nil { jww.ERROR.Printf("Failed to send %s E2E message to %s: %+v", catalog.E2eClose, partnerId, err) } else { jww.INFO.Printf( "Sent %s E2E message to %s on rounds %v with message ID %s at %s", - catalog.E2eClose, partnerId, rounds, msgID, timestamp) + catalog.E2eClose, partnerId, sendReport.RoundList, sendReport.MessageId, sendReport.SentTime) } return nil diff --git a/e2e/params.go b/e2e/params.go index 2702d490656342e975883177b115f63dbf2df961..ce0b72ff54282a5798c0ea2e085d8cd3143bc734 100644 --- a/e2e/params.go +++ b/e2e/params.go @@ -100,3 +100,9 @@ func (p *Params) UnmarshalJSON(data []byte) error { return nil } + +// String implements stringer interface by returning a json string +func (p *Params) String() string { + json, _ := p.MarshalJSON() + return string(json) +} diff --git a/e2e/parse/partition.go b/e2e/parse/partition.go index da7628381175971f748d456761ccc836345bd227..9e21827586a2601766e675c548ffcbfad61050ea 100644 --- a/e2e/parse/partition.go +++ b/e2e/parse/partition.go @@ -8,6 +8,7 @@ package parse import ( + "gitlab.com/elixxir/crypto/e2e" "time" "github.com/pkg/errors" @@ -78,7 +79,8 @@ func (p *Partitioner) Partition(recipient *id.ID, mt catalog.MessageType, } func (p *Partitioner) HandlePartition(sender *id.ID, - contents []byte, relationshipFingerprint []byte) (receive.Message, bool) { + contents []byte, relationshipFingerprint []byte, + residue e2e.KeyResidue) (receive.Message, e2e.KeyResidue, bool) { if isFirst(contents) { // If it is the first message in a set, then handle it as so @@ -92,7 +94,7 @@ func (p *Partitioner) HandlePartition(sender *id.ID, storageTimestamp := netTime.Now() return p.partition.AddFirst(sender, fm.getType(), messageID, fm.getPart(), fm.getNumParts(), fm.getTimestamp(), storageTimestamp, - fm.getSizedContents(), relationshipFingerprint) + fm.getSizedContents(), relationshipFingerprint, residue) } else { // If it is a subsequent message part, handle it as so mp := messagePartFromBytes(contents) diff --git a/e2e/parse/partition/multiPartMessage.go b/e2e/parse/partition/multiPartMessage.go index d067248d2a792fe846a9cb2e42c92ba001d5b3d5..f7fd42085929395ea4fa3d4265909aeecf0fb467 100644 --- a/e2e/parse/partition/multiPartMessage.go +++ b/e2e/parse/partition/multiPartMessage.go @@ -41,6 +41,8 @@ type multiPartMessage struct { StorageTimestamp time.Time MessageType catalog.MessageType + KeyResidue e2e.KeyResidue + parts [][]byte kv *versioned.KV mux sync.Mutex diff --git a/e2e/parse/partition/store.go b/e2e/parse/partition/store.go index 7774e3187b90235d79f2ce4082024e8f4a547dec..868737ea996f4f30516fbadae66112286955d704 100644 --- a/e2e/parse/partition/store.go +++ b/e2e/parse/partition/store.go @@ -8,12 +8,14 @@ package partition import ( + "bytes" "encoding/binary" "encoding/json" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/e2e/receive" "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/crypto/e2e" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" "golang.org/x/crypto/blake2b" @@ -49,47 +51,60 @@ func NewOrLoad(kv *versioned.KV) *Store { return partitionStore } +// AddFirst adds the first partition message to the Store object. func (s *Store) AddFirst(partner *id.ID, mt catalog.MessageType, messageID uint64, partNum, numParts uint8, senderTimestamp, - storageTimestamp time.Time, part []byte, relationshipFingerprint []byte) ( - receive.Message, bool) { + storageTimestamp time.Time, part []byte, relationshipFingerprint []byte, + residue e2e.KeyResidue) ( + receive.Message, e2e.KeyResidue, bool) { mpm := s.load(partner, messageID) - mpm.AddFirst(mt, partNum, numParts, senderTimestamp, storageTimestamp, part) + if bytes.Equal(residue.Marshal(), []byte{}) { + // fixme: should this error or crash? + jww.WARN.Printf("Key reside from first message " + + "is empty, continuing...") + } + + mpm.KeyResidue = residue msg, ok := mpm.IsComplete(relationshipFingerprint) s.mux.Lock() defer s.mux.Unlock() + keyRes := e2e.KeyResidue{} if !ok { s.activeParts[mpm] = true s.saveActiveParts() } else { + keyRes = mpm.KeyResidue mpID := getMultiPartID(mpm.Sender, mpm.MessageID) delete(s.multiParts, mpID) } - return msg, ok + return msg, keyRes, ok } func (s *Store) Add(partner *id.ID, messageID uint64, partNum uint8, - part []byte, relationshipFingerprint []byte) (receive.Message, bool) { + part []byte, relationshipFingerprint []byte) ( + receive.Message, e2e.KeyResidue, bool) { mpm := s.load(partner, messageID) mpm.Add(partNum, part) msg, ok := mpm.IsComplete(relationshipFingerprint) + keyRes := e2e.KeyResidue{} if !ok { s.activeParts[mpm] = true s.saveActiveParts() } else { + keyRes = mpm.KeyResidue mpID := getMultiPartID(mpm.Sender, mpm.MessageID) delete(s.multiParts, mpID) } - return msg, ok + return msg, keyRes, ok } // prune clears old messages on it's stored timestamp. diff --git a/e2e/parse/partition/store_test.go b/e2e/parse/partition/store_test.go index 909de9b829d54e7b07fc4936ed82bdd2337ccc5f..29526a2b829ad23e53f17ada0e2c393daf5fda5b 100644 --- a/e2e/parse/partition/store_test.go +++ b/e2e/parse/partition/store_test.go @@ -11,6 +11,7 @@ import ( "bytes" "gitlab.com/elixxir/client/catalog" "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/ekv" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" @@ -39,15 +40,27 @@ func TestNewOrLoad(t *testing.T) { func TestStore_AddFirst(t *testing.T) { part := []byte("Test message.") s := NewOrLoad(versioned.NewKV(ekv.MakeMemstore())) + b := make([]byte, e2e.KeyResidueLength) + kr, err := e2e.UnmarshalKeyResidue(b) + if err != nil { + t.Fatalf("Failed to unmarshal key residue: %+v", err) + } - msg, complete := s.AddFirst(id.NewIdFromString("User", id.User, t), + msg, receivedKr, complete := s.AddFirst(id.NewIdFromString("User", id.User, t), catalog.XxMessage, 5, 0, 1, netTime.Now(), netTime.Now(), part, - []byte{0}) + []byte{0}, kr) if !complete { t.Errorf("AddFirst returned that the message was not complete.") } + if !bytes.Equal(receivedKr[:], kr[:]) { + t.Fatalf("Key residue returned from complete partition did not "+ + "match first key signature."+ + "\nExpected: %v"+ + "\nReceived: %v", kr, receivedKr) + } + if !bytes.Equal(part, msg.Payload) { t.Errorf("AddFirst returned message with invalid payload."+ "\nexpected: %v\nreceived: %v", part, msg.Payload) @@ -59,21 +72,33 @@ func TestStore_Add(t *testing.T) { part1 := []byte("Test message.") part2 := []byte("Second Sentence.") s := NewOrLoad(versioned.NewKV(ekv.MakeMemstore())) + b := make([]byte, e2e.KeyResidueLength) + kr, err := e2e.UnmarshalKeyResidue(b) + if err != nil { + t.Fatalf("Failed to unmarshal key residue: %+v", err) + } - msg, complete := s.AddFirst(id.NewIdFromString("User", id.User, t), + msg, _, complete := s.AddFirst(id.NewIdFromString("User", id.User, t), catalog.XxMessage, 5, 0, 2, netTime.Now(), netTime.Now(), part1, - []byte{0}) + []byte{0}, kr) if complete { t.Errorf("AddFirst returned that the message was complete.") } - msg, complete = s.Add(id.NewIdFromString("User", id.User, t), + msg, receivedKr, complete := s.Add(id.NewIdFromString("User", id.User, t), 5, 1, part2, []byte{0}) if !complete { t.Errorf("AddFirst returned that the message was not complete.") } + if !bytes.Equal(receivedKr[:], kr[:]) { + t.Fatalf("Key residue returned from complete partition did not "+ + "match first key signature."+ + "\nExpected: %v"+ + "\nReceived: %v", kr, receivedKr) + } + part := append(part1, part2...) if !bytes.Equal(part, msg.Payload) { t.Errorf("AddFirst returned message with invalid payload."+ @@ -92,10 +117,15 @@ func TestStore_prune(t *testing.T) { partner1 := id.NewIdFromString("User", id.User, t) messageId1 := uint64(5) oldTimestamp := netTime.Now().Add(-2 * clearPartitionThreshold) + b := make([]byte, e2e.KeyResidueLength) + kr, err := e2e.UnmarshalKeyResidue(b) + if err != nil { + t.Fatalf("Failed to unmarshal key residue: %+v", err) + } s.AddFirst(partner1, catalog.XxMessage, messageId1, 0, 2, netTime.Now(), oldTimestamp, part1, - []byte{0}) + []byte{0}, kr) s.Add(partner1, messageId1, 1, part2, []byte{0}) partner2 := id.NewIdFromString("User1", id.User, t) @@ -103,7 +133,7 @@ func TestStore_prune(t *testing.T) { newTimestamp := netTime.Now() s.AddFirst(partner2, catalog.XxMessage, messageId2, 0, 2, netTime.Now(), newTimestamp, part1, - []byte{0}) + []byte{0}, kr) // Call clear messages s.prune() diff --git a/e2e/parse/partition_test.go b/e2e/parse/partition_test.go index 22c1f238eda4b2f2f0be5575e68143c28970a749..3abf6ff1f7db7d41eeaff31ba6dee0bcd3e82fb2 100644 --- a/e2e/parse/partition_test.go +++ b/e2e/parse/partition_test.go @@ -8,6 +8,7 @@ package parse import ( + "gitlab.com/elixxir/crypto/e2e" "testing" "gitlab.com/elixxir/client/catalog" @@ -72,10 +73,11 @@ func TestPartitioner_HandlePartition(t *testing.T) { p := NewPartitioner(versioned.NewKV(ekv.MakeMemstore()), len(ipsumTestStr)) m := newMessagePart(1107, 1, []byte(ipsumTestStr), len(ipsumTestStr)+headerLen) - _, _ = p.HandlePartition( + _, _, _ = p.HandlePartition( &id.DummyUser, m.bytes(), []byte{'t', 'e', 's', 't', 'i', 'n', 'g', 's', 't', 'r', 'i', 'n', 'g'}, + e2e.KeyResidue{}, ) } @@ -85,9 +87,10 @@ func TestPartitioner_HandleFirstPartition(t *testing.T) { m := newFirstMessagePart( catalog.XxMessage, 1107, 1, netTime.Now(), []byte(ipsumTestStr), len([]byte(ipsumTestStr))+firstHeaderLen) - _, _ = p.HandlePartition( + _, _, _ = p.HandlePartition( &id.DummyUser, m.bytes(), []byte{'t', 'e', 's', 't', 'i', 'n', 'g', 's', 't', 'r', 'i', 'n', 'g'}, + e2e.KeyResidue{}, ) } diff --git a/e2e/processor.go b/e2e/processor.go index 17e2293401209f84783f4855182f607cc8f6bd0e..b1a8411eb473f511b974e132086a917e51469994 100644 --- a/e2e/processor.go +++ b/e2e/processor.go @@ -23,7 +23,7 @@ func (p *processor) Process(ecrMsg format.Message, // ensure the key will be marked used before returning defer p.cy.Use() - contents, err := p.cy.Decrypt(ecrMsg) + contents, residue, err := p.cy.Decrypt(ecrMsg) if err != nil { jww.ERROR.Printf("decrypt failed of %s (fp: %s), dropping: %+v", ecrMsg.Digest(), p.cy.Fingerprint(), err) @@ -31,8 +31,9 @@ func (p *processor) Process(ecrMsg format.Message, } sess := p.cy.GetSession() - message, done := p.m.partitioner.HandlePartition(sess.GetPartner(), - contents, sess.GetRelationshipFingerprint()) + // todo: handle residue here + message, _, done := p.m.partitioner.HandlePartition(sess.GetPartner(), + contents, sess.GetRelationshipFingerprint(), residue) if done { message.RecipientID = receptionID.Source message.EphemeralID = receptionID.EphId diff --git a/e2e/ratchet/partner/session/cypher.go b/e2e/ratchet/partner/session/cypher.go index ef4094a40f0967f199dd4f89786fd6a2dcda5459..12ea988916ccffaf91d54a013246f09beaaafcb0 100644 --- a/e2e/ratchet/partner/session/cypher.go +++ b/e2e/ratchet/partner/session/cypher.go @@ -63,13 +63,15 @@ type Cypher interface { // Encrypt uses the E2E key to encrypt the message to its intended // recipient. It also properly populates the associated data, including the - // MAC, fingerprint, and encrypted timestamp. - Encrypt(contents []byte) (ecrContents, mac []byte) + // MAC, fingerprint, and encrypted timestamp. It generates a residue of the + // key used to encrypt the contents. + Encrypt(contents []byte) (ecrContents, mac []byte, residue e2eCrypto.KeyResidue) // Decrypt uses the E2E key to decrypt the message. It returns an error in // case of HMAC verification failure or in case of a decryption error - // (related to padding). - Decrypt(msg format.Message) ([]byte, error) + // (related to padding). It generates a residue of the + // key used to encrypt the contents. + Decrypt(msg format.Message) (decryptedPayload []byte, residue e2eCrypto.KeyResidue, err error) // Use sets the key as used. It cannot be used again. Use() @@ -110,11 +112,13 @@ func (k *cypher) Fingerprint() format.Fingerprint { // Encrypt uses the E2E key to encrypt the message to its intended recipient. It // also properly populates the associated data, including the MAC, fingerprint, -// and encrypted timestamp. -func (k *cypher) Encrypt(contents []byte) (ecrContents, mac []byte) { +// and encrypted timestamp. It generates a residue of the key used to encrypt the contents. +func (k *cypher) Encrypt(contents []byte) (ecrContents, mac []byte, residue e2eCrypto.KeyResidue) { fp := k.Fingerprint() key := k.generateKey() + residue = e2eCrypto.NewKeyResidue(key) + // encrypt the payload ecrContents = e2eCrypto.Crypt(key, fp, contents) @@ -122,25 +126,28 @@ func (k *cypher) Encrypt(contents []byte) (ecrContents, mac []byte) { // Currently, the MAC doesn't include any of the associated data mac = hash.CreateHMAC(ecrContents, key[:]) - return ecrContents, mac + return ecrContents, mac, residue } // Decrypt uses the E2E key to decrypt the message. It returns an error in case // of HMAC verification failure or in case of a decryption error (related to -// padding). -func (k *cypher) Decrypt(msg format.Message) ([]byte, error) { +// padding). It generates a residue of the key used to encrypt the contents +func (k *cypher) Decrypt(msg format.Message) (decryptedPayload []byte, residue e2eCrypto.KeyResidue, err error) { fp := k.Fingerprint() key := k.generateKey() // Verify the MAC is correct if !hash.VerifyHMAC(msg.GetContents(), msg.GetMac(), key[:]) { - return nil, errors.New("HMAC verification failed for E2E message") + return nil, e2eCrypto.KeyResidue{}, errors.New("HMAC verification failed for E2E message") } // Decrypt the payload - decryptedPayload := e2eCrypto.Crypt(key, fp, msg.GetContents()) + decryptedPayload = e2eCrypto.Crypt(key, fp, msg.GetContents()) + + // Construct residue + residue = e2eCrypto.NewKeyResidue(key) - return decryptedPayload, nil + return decryptedPayload, residue, nil } // Use sets the key as used. It cannot be used again. diff --git a/e2e/ratchet/partner/session/cypher_test.go b/e2e/ratchet/partner/session/cypher_test.go index b6c92de98bc3dcaf1b6e18237df418ad246dbe5b..c46e380a8bb48f129f06301460c9f52dc05849d7 100644 --- a/e2e/ratchet/partner/session/cypher_test.go +++ b/e2e/ratchet/partner/session/cypher_test.go @@ -153,7 +153,7 @@ func Test_cypher_EncryptDecrypt(t *testing.T) { msg.SetContents(contents) // Encrypt - contentsEnc, mac := cy.Encrypt(msg.GetContents()) + contentsEnc, mac, _ := cy.Encrypt(msg.GetContents()) // Make the encrypted message ecrMsg := format.NewMessage(grp.GetP().ByteLen()) @@ -162,7 +162,7 @@ func Test_cypher_EncryptDecrypt(t *testing.T) { ecrMsg.SetMac(mac) // Decrypt - contentsDecr, err := cy.Decrypt(ecrMsg) + contentsDecr, _, err := cy.Decrypt(ecrMsg) if err != nil { t.Fatalf("Decrypt error: %+v", err) } diff --git a/e2e/rekey/exchange.go b/e2e/rekey/exchange.go index 30345ca1a28cf7b30ea8db9fd6587289e4092aec..cd5f553efa6501c956de7da3601e5fe5a56e4291 100644 --- a/e2e/rekey/exchange.go +++ b/e2e/rekey/exchange.go @@ -16,12 +16,10 @@ import ( "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/e2e" "gitlab.com/xx_network/primitives/id" - "time" ) type E2eSender func(mt catalog.MessageType, recipient *id.ID, payload []byte, - cmixParams cmix.CMIXParams) ( - []id.Round, e2e.MessageID, time.Time, error) + cmixParams cmix.CMIXParams) (e2e.SendReport, error) func Start(switchboard *receive.Switchboard, ratchet *ratchet.Ratchet, sender E2eSender, net cmix.Client, grp *cyclic.Group, params Params) (stoppable.Stoppable, error) { diff --git a/e2e/rekey/rekey.go b/e2e/rekey/rekey.go index 960df918f20e3aee3e87a77ac4959668fc5db87c..3d2cdfca774503ea68d6d0bb217c73ffbeba34dc 100644 --- a/e2e/rekey/rekey.go +++ b/e2e/rekey/rekey.go @@ -125,7 +125,8 @@ func negotiate(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSe params := cmix.GetDefaultCMIXParams() params.DebugTag = "kx.Request" - rounds, msgID, _, err := sendE2E(param.Trigger, sess.GetPartner(), + // fixme: should this use the key residue? + sendReport, err := sendE2E(param.Trigger, sess.GetPartner(), payload, params) // If the send fails, returns the error so it can be handled. The caller // should ensure the calling session is in a state where the Rekey will @@ -137,18 +138,18 @@ func negotiate(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSe } //create the runner which will handle the result of sending the messages - sendResults := make(chan ds.EventReturn, len(rounds)) + sendResults := make(chan ds.EventReturn, len(sendReport.RoundList)) //Register the event for all rounds roundEvents := instance.GetRoundEvents() - for _, r := range rounds { + for _, r := range sendReport.RoundList { roundEvents.AddRoundEventChan(r, sendResults, sendTimeout, states.COMPLETED, states.FAILED) } //Wait until the result tracking responds success, numRoundFail, numTimeOut := cmix.TrackResults(sendResults, - len(rounds)) + len(sendReport.RoundList)) // If a single partition of the Key Negotiation request does not // transmit, the partner cannot read the result. Log the error and set @@ -157,14 +158,14 @@ func negotiate(instance *commsNetwork.Instance, grp *cyclic.Group, sendE2E E2eSe _ = sess.TrySetNegotiationStatus(session.Unconfirmed) return errors.Errorf("[REKEY] Key Negotiation rekey for %s failed to "+ "transmit %v/%v paritions: %v round failures, %v timeouts, msgID: %s", - sess, numRoundFail+numTimeOut, len(rounds), numRoundFail, - numTimeOut, msgID) + sess, numRoundFail+numTimeOut, len(sendReport.RoundList), numRoundFail, + numTimeOut, sendReport.MessageId) } // otherwise, the transmission is a success and this should be denoted // in the session and the log jww.INFO.Printf("[REKEY] Key Negotiation rekey transmission for %s, msgID %s successful", - sess, msgID) + sess, sendReport.MessageId) err = sess.TrySetNegotiationStatus(session.Sent) if err != nil { if sess.NegotiationStatus() == session.NewSessionTriggered { diff --git a/e2e/rekey/trigger.go b/e2e/rekey/trigger.go index 80d2cd2b62a8a1840e8605aa79bc7d4e501cbb2d..4f62828c669c4c34c6500747fca1af4bb7922aee 100644 --- a/e2e/rekey/trigger.go +++ b/e2e/rekey/trigger.go @@ -127,7 +127,8 @@ func handleTrigger(ratchet *ratchet.Ratchet, sender E2eSender, params := cmix.GetDefaultCMIXParams() params.Critical = true //ignore results, the passed sender interface makes it a critical message - _, _, _, _ = sender(param.Confirm, request.Sender, payload, + // fixme: should this ignore the error as well? + _, _ = sender(param.Confirm, request.Sender, payload, params) return nil diff --git a/e2e/rekey/trigger_test.go b/e2e/rekey/trigger_test.go index 8e9ab6658eb627babb1dd9acacd0150222f1a71c..ba41dff0e1e179c746265260a5328c8312772465 100644 --- a/e2e/rekey/trigger_test.go +++ b/e2e/rekey/trigger_test.go @@ -119,7 +119,8 @@ func TestHandleTrigger(t *testing.T) { rekeyParams := GetDefaultParams() stop := stoppable.NewSingle("stoppable") rekeyParams.RoundTimeout = 0 * time.Second - err = handleTrigger(r, testSendE2E, &mockNetManager{}, grp, receiveMsg, rekeyParams, stop) + err = handleTrigger(r, testSendE2E, &mockNetManager{}, grp, receiveMsg, + rekeyParams, stop) if err != nil { t.Errorf("Handle trigger error: %v", err) } diff --git a/e2e/rekey/utils_test.go b/e2e/rekey/utils_test.go index 3e1f77f1dcdc80a760498da5ea6b1905b90cec84..4f040f4d71083ca6625165e9c73caef261d6e54b 100644 --- a/e2e/rekey/utils_test.go +++ b/e2e/rekey/utils_test.go @@ -8,6 +8,7 @@ package rekey import ( + "gitlab.com/elixxir/crypto/e2e" "math/rand" "testing" "time" @@ -27,7 +28,6 @@ import ( network2 "gitlab.com/elixxir/comms/network" ds "gitlab.com/elixxir/comms/network/dataStructures" "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/hash" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/comms/connect" @@ -73,7 +73,8 @@ func genSidhKeys() (*sidh.PrivateKey, *sidh.PublicKey, *sidh.PrivateKey, *sidh.P } func testSendE2E(mt catalog.MessageType, recipient *id.ID, - payload []byte, cmixParams cmix.CMIXParams) ([]id.Round, e2e.MessageID, time.Time, error) { + payload []byte, cmixParams cmix.CMIXParams) ( + e2e.SendReport, error) { rounds := []id.Round{id.Round(0), id.Round(1), id.Round(2)} alicePartner, err := r.GetPartner(aliceID) if err != nil { @@ -109,7 +110,9 @@ func testSendE2E(mt catalog.MessageType, recipient *id.ID, bobSwitchboard.Speak(confirmMessage) - return rounds, e2e.MessageID{}, time.Time{}, nil + return e2e.SendReport{ + RoundList: rounds, + }, nil } var pub = "-----BEGIN CERTIFICATE-----\nMIIGHTCCBAWgAwIBAgIUOcAn9cpH+hyRH8/UfqtbFDoSxYswDQYJKoZIhvcNAQEL\nBQAwgZIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJQ2xhcmVt\nb250MRAwDgYDVQQKDAdFbGl4eGlyMRQwEgYDVQQLDAtEZXZlbG9wbWVudDEZMBcG\nA1UEAwwQZ2F0ZXdheS5jbWl4LnJpcDEfMB0GCSqGSIb3DQEJARYQYWRtaW5AZWxp\neHhpci5pbzAeFw0xOTA4MTYwMDQ4MTNaFw0yMDA4MTUwMDQ4MTNaMIGSMQswCQYD\nVQQGEwJVUzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCUNsYXJlbW9udDEQMA4GA1UE\nCgwHRWxpeHhpcjEUMBIGA1UECwwLRGV2ZWxvcG1lbnQxGTAXBgNVBAMMEGdhdGV3\nYXkuY21peC5yaXAxHzAdBgkqhkiG9w0BCQEWEGFkbWluQGVsaXh4aXIuaW8wggIi\nMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7Dkb6VXFn4cdpU0xh6ji0nTDQ\nUyT9DSNW9I3jVwBrWfqMc4ymJuonMZbuqK+cY2l+suS2eugevWZrtzujFPBRFp9O\n14Jl3fFLfvtjZvkrKbUMHDHFehascwzrp3tXNryiRMmCNQV55TfITVCv8CLE0t1i\nbiyOGM9ZWYB2OjXt59j76lPARYww5qwC46vS6+3Cn2Yt9zkcrGeskWEFa2VttHqF\n910TP+DZk2R5C7koAh6wZYK6NQ4S83YQurdHAT51LKGrbGehFKXq6/OAXCU1JLi3\nkW2PovTb6MZuvxEiRmVAONsOcXKu7zWCmFjuZZwfRt2RhnpcSgzfrarmsGM0LZh6\nJY3MGJ9YdPcVGSz+Vs2E4zWbNW+ZQoqlcGeMKgsIiQ670g0xSjYICqldpt79gaET\n9PZsoXKEmKUaj6pq1d4qXDk7s63HRQazwVLGBdJQK8qX41eCdR8VMKbrCaOkzD5z\ngnEu0jBBAwdMtcigkMIk1GRv91j7HmqwryOBHryLi6NWBY3tjb4So9AppDQB41SH\n3SwNenAbNO1CXeUqN0hHX6I1bE7OlbjqI7tXdrTllHAJTyVVjenPel2ApMXp+LVR\ndDbKtwBiuM6+n+z0I7YYerxN1gfvpYgcXm4uye8dfwotZj6H2J/uSALsU2v9UHBz\nprdrLSZk2YpozJb+CQIDAQABo2kwZzAdBgNVHQ4EFgQUDaTvG7SwgRQ3wcYx4l+W\nMcZjX7owHwYDVR0jBBgwFoAUDaTvG7SwgRQ3wcYx4l+WMcZjX7owDwYDVR0TAQH/\nBAUwAwEB/zAUBgNVHREEDTALgglmb28uY28udWswDQYJKoZIhvcNAQELBQADggIB\nADKz0ST0uS57oC4rT9zWhFqVZkEGh1x1XJ28bYtNUhozS8GmnttV9SnJpq0EBCm/\nr6Ub6+Wmf60b85vCN5WDYdoZqGJEBjGGsFzl4jkYEE1eeMfF17xlNUSdt1qLCE8h\nU0glr32uX4a6nsEkvw1vo1Liuyt+y0cOU/w4lgWwCqyweu3VuwjZqDoD+3DShVzX\n8f1p7nfnXKitrVJt9/uE+AtAk2kDnjBFbRxCfO49EX4Cc5rADUVXMXm0itquGBYp\nMbzSgFmsMp40jREfLYRRzijSZj8tw14c2U9z0svvK9vrLCrx9+CZQt7cONGHpr/C\n/GIrP/qvlg0DoLAtjea73WxjSCbdL3Nc0uNX/ymXVHdQ5husMCZbczc9LYdoT2VP\nD+GhkAuZV9g09COtRX4VP09zRdXiiBvweiq3K78ML7fISsY7kmc8KgVH22vcXvMX\nCgGwbrxi6QbQ80rWjGOzW5OxNFvjhvJ3vlbOT6r9cKZGIPY8IdN/zIyQxHiim0Jz\noavr9CPDdQefu9onizsmjsXFridjG/ctsJxcUEqK7R12zvaTxu/CVYZbYEUFjsCe\nq6ZAACiEJGvGeKbb/mSPvGs2P1kS70/cGp+P5kBCKqrm586FB7BcafHmGFrWhT3E\nLOUYkOV/gADT2hVDCrkPosg7Wb6ND9/mhCVVhf4hLGRh\n-----END CERTIFICATE-----\n" diff --git a/e2e/sendE2E.go b/e2e/sendE2E.go index 284008a92d92988b56abb6f6e81fd49381be94e0..3a181f3c7f2e508fe7372d7c2d8684919f016de8 100644 --- a/e2e/sendE2E.go +++ b/e2e/sendE2E.go @@ -19,11 +19,24 @@ import ( "gitlab.com/xx_network/primitives/netTime" ) +// SendE2E send a message containing the payload to the +// recipient of the passed message type, per the given +// parameters - encrypted with end-to-end encryption. +// Default parameters can be retrieved through +// GetDefaultParams() +// If too long, it will chunk a message up into its messages +// and send each as a separate cmix message. It will return +// the list of all rounds sent on, a unique ID for the +// message, and the timestamp sent on. +// the recipient must already have an e2e relationship, +// otherwise an error will be returned. +// Will return an error if the network is not healthy or in +// the event of a failed send func (m *manager) SendE2E(mt catalog.MessageType, recipient *id.ID, - payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error) { + payload []byte, params Params) (e2e.SendReport, error) { if !m.net.IsHealthy() { - return nil, e2e.MessageID{}, time.Time{}, + return e2e.SendReport{}, errors.New("cannot sendE2E when network is not healthy") } @@ -35,18 +48,18 @@ func (m *manager) SendE2E(mt catalog.MessageType, recipient *id.ID, params.Critical = false } - rounds, msgID, t, err := m.sendE2E(mt, recipient, payload, params) + sendReport, err := m.sendE2E(mt, recipient, payload, params) if handleCritical { - m.crit.handle(mt, recipient, payload, rounds, err) + m.crit.handle(mt, recipient, payload, sendReport.RoundList, err) } - return rounds, msgID, t, err + return sendReport, err } // sendE2eFn contains a prepared sendE2E operation and sends an E2E message when // called, returning the results of the send. -type sendE2eFn func() ([]id.Round, e2e.MessageID, time.Time, error) +type sendE2eFn func() (e2e.SendReport, error) // prepareSendE2E makes a prepared function that does the e2e send. // This is so that when doing deletePartner we can prepare the send before @@ -63,41 +76,46 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID, partitions, internalMsgId, err := m.partitioner.Partition(recipient, mt, ts, payload) if err != nil { - return nil, errors.WithMessage(err, "failed to send unsafe message") + return nil, errors.WithMessage(err, + "failed to send unsafe message") } - jww.INFO.Printf("E2E sending %d messages to %s", len(partitions), recipient) + jww.INFO.Printf("E2E sending %d messages to %s", + len(partitions), recipient) - // When sending E2E messages, we first partition into cMix packets and then - // send each partition over cMix + // When sending E2E messages, we first partition into cMix + // packets and then send each partition over cMix roundIds := make([]id.Round, len(partitions)) errCh := make(chan error, len(partitions)) - // The Key manager for the partner (recipient) ensures single use of each - // key negotiated for the ratchet + // The Key manager for the partner (recipient) ensures single + // use of each key negotiated for the ratchet partner, err := m.Ratchet.GetPartner(recipient) if err != nil { return nil, errors.WithMessagef(err, - "cannot send E2E message no relationship found with %s", recipient) + "cannot send E2E message no relationship found with %s", + recipient) } msgID := e2e.NewMessageID( partner.SendRelationshipFingerprint(), internalMsgId) wg := sync.WaitGroup{} - + var keyResidue e2e.KeyResidue for i, p := range partitions { if mt != catalog.KeyExchangeTrigger { // Check if any rekeys need to happen and trigger them - rekeySendFunc := func(mt catalog.MessageType, recipient *id.ID, + rekeySendFunc := func(mt catalog.MessageType, + recipient *id.ID, payload []byte, cmixParams cmix.CMIXParams) ( - []id.Round, e2e.MessageID, time.Time, error) { + e2e.SendReport, error) { par := params par.CMIXParams = cmixParams return m.SendE2E(mt, recipient, payload, par) } - rekey.CheckKeyExchanges(m.net.GetInstance(), m.grp, rekeySendFunc, - m.events, partner, m.rekeyParams, 1*time.Minute) + rekey.CheckKeyExchanges(m.net.GetInstance(), m.grp, + rekeySendFunc, m.events, partner, + m.rekeyParams, 1*time.Minute) } var keyGetter func() (session.Cypher, error) @@ -107,23 +125,29 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID, keyGetter = partner.PopSendCypher } - // FIXME: remove this wait, it is weird. Why is it here? we cant remember. + // FIXME: remove this wait, it is weird. Why is it + // here? we cant remember. key, err := waitForKey( - keyGetter, params.KeyGetRetryCount, params.KeyGeRetryDelay, + keyGetter, params.KeyGetRetryCount, + params.KeyGeRetryDelay, params.Stop, recipient, format.DigestContents(p), i) if err != nil { return nil, errors.WithMessagef(err, "Failed to get key for end-to-end encryption") } - // This does not encrypt for cMix but instead end-to-end encrypts the - // cMix message - contentsEnc, mac := key.Encrypt(p) + // This does not encrypt for cMix but instead + // end-to-end encrypts the cMix message + contentsEnc, mac, residue := key.Encrypt(p) + // Carry the first key residue to the top level + if i == 0 { + keyResidue = residue + } - jww.INFO.Printf( - "E2E sending %d/%d to %s with key fp: %s, msgID: %s (msgDigest %s)", - i+i, len(partitions), recipient, key.Fingerprint(), msgID, - format.DigestContents(p)) + jww.INFO.Printf("E2E sending %d/%d to %s with key fp: %s, "+ + "msgID: %s (msgDigest %s)", + i+i, len(partitions), recipient, key.Fingerprint(), + msgID, format.DigestContents(p)) var s message.Service if i == len(partitions)-1 { @@ -132,16 +156,20 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID, s = partner.MakeService(params.ServiceTag) } - // We send each partition in its own thread here; some may send in round - // X, others in X+1 or X+2, and so on + // We send each partition in its own thread here; some + // may send in round X, others in X+1 or X+2, and so + // on localI := i thisSendFunc := func() { wg.Add(1) go func(i int) { var err error roundIds[i], _, err = m.net.Send(recipient, - key.Fingerprint(), s, contentsEnc, mac, params.CMIXParams) + key.Fingerprint(), s, contentsEnc, mac, + params.CMIXParams) if err != nil { + jww.DEBUG.Printf("[E2E] cMix error on "+ + "Send: %+v", err) errCh <- err } wg.Done() @@ -150,7 +178,7 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID, sendFuncs = append(sendFuncs, thisSendFunc) } - sendE2E = func() ([]id.Round, e2e.MessageID, time.Time, error) { + sendE2E = func() (e2e.SendReport, error) { for i := range sendFuncs { sendFuncs[i]() } @@ -161,27 +189,33 @@ func (m *manager) prepareSendE2E(mt catalog.MessageType, recipient *id.ID, if numFail > 0 { jww.INFO.Printf("Failed to E2E send %d/%d to %s", numFail, len(partitions), recipient) - return nil, e2e.MessageID{}, time.Time{}, errors.Errorf( + return e2e.SendReport{}, errors.Errorf( "Failed to E2E send %v/%v sub payloads: %s", numFail, len(partitions), errRtn) } else { jww.INFO.Printf("Successfully E2E sent %d/%d to %s", - len(partitions)-numFail, len(partitions), recipient) + len(partitions)-numFail, len(partitions), + recipient) } - jww.INFO.Printf("Successful E2E Send of %d messages to %s with msgID %s", - len(partitions), recipient, msgID) + jww.INFO.Printf("Successful E2E Send of %d messages to %s "+ + "with msgID %s", len(partitions), recipient, msgID) - return roundIds, msgID, ts, nil + return e2e.SendReport{ + RoundList: roundIds, + MessageId: msgID, + SentTime: ts, + KeyResidue: keyResidue, + }, nil } return sendE2E, nil } func (m *manager) sendE2E(mt catalog.MessageType, recipient *id.ID, - payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error) { + payload []byte, params Params) (e2e.SendReport, error) { sendFunc, err := m.prepareSendE2E(mt, recipient, payload, params) if err != nil { - return nil, e2e.MessageID{}, time.Time{}, err + return e2e.SendReport{}, err } return sendFunc() } diff --git a/e2e/sendE2E_test.go b/e2e/sendE2E_test.go index d316b90c79a388ac32c405542e49d882089138d1..12f89ce15a2fdf692f8b82ceecddebf7e8bd25f8 100644 --- a/e2e/sendE2E_test.go +++ b/e2e/sendE2E_test.go @@ -22,6 +22,7 @@ import ( "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/cyclic" dh "gitlab.com/elixxir/crypto/diffieHellman" + "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/ekv" "gitlab.com/elixxir/primitives/format" @@ -106,7 +107,7 @@ func Test_manager_SendE2E_Smoke(t *testing.T) { payload := []byte("My Payload") p := GetDefaultParams() - _, _, _, err = m1.SendE2E(catalog.NoType, partnerID, payload, p) + _, err = m1.SendE2E(catalog.NoType, partnerID, payload, p) if err != nil { t.Errorf("SendE2E failed: %+v", err) } @@ -221,11 +222,15 @@ type mockWaitForKeyCypher struct { cypherNum int } -func (m *mockWaitForKeyCypher) GetSession() *session.Session { return nil } -func (m *mockWaitForKeyCypher) Fingerprint() format.Fingerprint { return format.Fingerprint{} } -func (m *mockWaitForKeyCypher) Encrypt([]byte) ([]byte, []byte) { return nil, nil } -func (m *mockWaitForKeyCypher) Decrypt(format.Message) ([]byte, error) { return nil, nil } -func (m *mockWaitForKeyCypher) Use() {} +func (m *mockWaitForKeyCypher) GetSession() *session.Session { return nil } +func (m *mockWaitForKeyCypher) Fingerprint() format.Fingerprint { return format.Fingerprint{} } +func (m *mockWaitForKeyCypher) Encrypt([]byte) ([]byte, []byte, e2e.KeyResidue) { + return nil, nil, e2e.KeyResidue{} +} +func (m *mockWaitForKeyCypher) Decrypt(format.Message) ([]byte, e2e.KeyResidue, error) { + return nil, e2e.KeyResidue{}, nil +} +func (m *mockWaitForKeyCypher) Use() {} // Tests that getSendErrors returns all the errors on the channel. func Test_getSendErrors(t *testing.T) { diff --git a/e2e/unsafeProcessor.go b/e2e/unsafeProcessor.go index 3cd173d525244ea2bdb15cd1c28fe4af1847ce58..741ae088b71f185c32a6cd6d53d2ed769199f627 100644 --- a/e2e/unsafeProcessor.go +++ b/e2e/unsafeProcessor.go @@ -33,8 +33,9 @@ func (up *UnsafeProcessor) Process(ecrMsg format.Message, } //Parse - message, done := up.m.partitioner.HandlePartition(sender, - ecrMsg.GetContents(), nil) + // todo: handle residue here + message, _, done := up.m.partitioner.HandlePartition(sender, + ecrMsg.GetContents(), nil, e2e.KeyResidue{}) if done { message.RecipientID = receptionID.Source diff --git a/fileTransfer/connect/send.go b/fileTransfer/connect/send.go index 2b00c8ba71cc8817a2764025ae34f8e4bdcc3438..0f0c0df1904aed876f52fa9342a116e79260b8d7 100644 --- a/fileTransfer/connect/send.go +++ b/fileTransfer/connect/send.go @@ -45,7 +45,7 @@ func sendNewFileTransferMessage( params.LastServiceTag = catalog.Silent params.DebugTag = initialMessageDebugTag - _, _, _, err := connectionHandler.SendE2E( + _, err := connectionHandler.SendE2E( catalog.NewFileTransfer, transferInfo, params) if err != nil { return errors.Errorf(errNewFtSendE2e, err) @@ -65,7 +65,7 @@ func sendEndFileTransferMessage(cmix ft.Cmix, connectionHandler connection) { params.LastServiceTag = catalog.EndFT params.DebugTag = lastMessageDebugTag - _, _, _, err := connectionHandler.SendE2E( + _, err := connectionHandler.SendE2E( catalog.EndFileTransfer, nil, params) if err != nil { jww.ERROR.Printf(errEndFtSendE2e, err) diff --git a/fileTransfer/connect/utils_test.go b/fileTransfer/connect/utils_test.go index 7d0fb6aeba668c2fcccf89cd881746007a84a101..400b5288f6a148eee8dd82b13f5e1085e0f73327 100644 --- a/fileTransfer/connect/utils_test.go +++ b/fileTransfer/connect/utils_test.go @@ -26,7 +26,7 @@ import ( "gitlab.com/elixxir/client/xxdk" "gitlab.com/elixxir/comms/network" "gitlab.com/elixxir/crypto/cyclic" - e2eCrypto "gitlab.com/elixxir/crypto/e2e" + cryptoE2e "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/ekv" "gitlab.com/elixxir/primitives/format" @@ -38,7 +38,6 @@ import ( "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" "gitlab.com/xx_network/primitives/ndf" - "gitlab.com/xx_network/primitives/netTime" "sync" "testing" "time" @@ -268,7 +267,7 @@ func (m *mockConnection) GetPartner() partner.Manager { // SendE2E adds the message to the e2e handler map. func (m *mockConnection) SendE2E(mt catalog.MessageType, payload []byte, - _ e2e.Params) ([]id.Round, e2eCrypto.MessageID, time.Time, error) { + _ e2e.Params) (cryptoE2e.SendReport, error) { m.handler.Lock() defer m.handler.Unlock() @@ -278,7 +277,7 @@ func (m *mockConnection) SendE2E(mt catalog.MessageType, payload []byte, Sender: m.myID, }) - return []id.Round{42}, e2eCrypto.MessageID{}, netTime.Now(), nil + return cryptoE2e.SendReport{RoundList: []id.Round{42}}, nil } func (m *mockConnection) RegisterListener(mt catalog.MessageType, diff --git a/fileTransfer/connect/wrapper.go b/fileTransfer/connect/wrapper.go index 60a3f6641da53aad60d53a29feb533180738556b..0d826daecfa137cfa001b8a482e0b47687593dc3 100644 --- a/fileTransfer/connect/wrapper.go +++ b/fileTransfer/connect/wrapper.go @@ -13,9 +13,8 @@ import ( "gitlab.com/elixxir/client/e2e/ratchet/partner" "gitlab.com/elixxir/client/e2e/receive" ft "gitlab.com/elixxir/client/fileTransfer" - e2eCrypto "gitlab.com/elixxir/crypto/e2e" + cryptoE2e "gitlab.com/elixxir/crypto/e2e" ftCrypto "gitlab.com/elixxir/crypto/fileTransfer" - "gitlab.com/xx_network/primitives/id" "time" ) @@ -41,7 +40,7 @@ type Wrapper struct { type connection interface { GetPartner() partner.Manager SendE2E(mt catalog.MessageType, payload []byte, params e2e.Params) ( - []id.Round, e2eCrypto.MessageID, time.Time, error) + cryptoE2e.SendReport, error) RegisterListener(messageType catalog.MessageType, newListener receive.Listener) (receive.ListenerID, error) } diff --git a/fileTransfer/e2e/send.go b/fileTransfer/e2e/send.go index a073d0afe841a04026081b9033e0e1cc5c164062..6f19468dcb07c8b698ad9b574f3de038818fc3e2 100644 --- a/fileTransfer/e2e/send.go +++ b/fileTransfer/e2e/send.go @@ -46,7 +46,7 @@ func sendNewFileTransferMessage( params.LastServiceTag = catalog.Silent params.DebugTag = initialMessageDebugTag - _, _, _, err := e2eHandler.SendE2E( + _, err := e2eHandler.SendE2E( catalog.NewFileTransfer, recipient, transferInfo, params) if err != nil { return errors.Errorf(errNewFtSendE2e, err) @@ -66,7 +66,7 @@ func sendEndFileTransferMessage(recipient *id.ID, cmix ft.Cmix, e2eHandler e2eHa params.LastServiceTag = catalog.EndFT params.DebugTag = lastMessageDebugTag - _, _, _, err := e2eHandler.SendE2E( + _, err := e2eHandler.SendE2E( catalog.EndFileTransfer, recipient, nil, params) if err != nil { jww.ERROR.Printf(errEndFtSendE2e, err) diff --git a/fileTransfer/e2e/utils_test.go b/fileTransfer/e2e/utils_test.go index 164d155740c789916f1ff5a96b3bd3c89079c61f..a185a84aafaf6120fd6a9df74cb774291ea36eeb 100644 --- a/fileTransfer/e2e/utils_test.go +++ b/fileTransfer/e2e/utils_test.go @@ -28,7 +28,7 @@ import ( "gitlab.com/elixxir/client/xxdk" "gitlab.com/elixxir/comms/network" "gitlab.com/elixxir/crypto/cyclic" - e "gitlab.com/elixxir/crypto/e2e" + cryptoE2e "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/ekv" "gitlab.com/elixxir/primitives/format" @@ -40,7 +40,6 @@ import ( "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/id/ephemeral" "gitlab.com/xx_network/primitives/ndf" - "gitlab.com/xx_network/primitives/netTime" "sync" "time" ) @@ -259,7 +258,7 @@ func (m *mockE2e) StartProcesses() (stoppable.Stoppable, error) { panic("impleme // SendE2E adds the message to the e2e handler map. func (m *mockE2e) SendE2E(mt catalog.MessageType, recipient *id.ID, - payload []byte, _ e2e.Params) ([]id.Round, e.MessageID, time.Time, error) { + payload []byte, _ e2e.Params) (cryptoE2e.SendReport, error) { m.handler.listeners[mt].Hear(receive.Message{ MessageType: mt, @@ -268,7 +267,7 @@ func (m *mockE2e) SendE2E(mt catalog.MessageType, recipient *id.ID, RecipientID: recipient, }) - return []id.Round{42}, e.MessageID{}, netTime.Now(), nil + return cryptoE2e.SendReport{RoundList: []id.Round{42}}, nil } func (m *mockE2e) RegisterListener(_ *id.ID, mt catalog.MessageType, diff --git a/fileTransfer/e2e/wrapper.go b/fileTransfer/e2e/wrapper.go index e27c281c9dfc490d271b3d225b73643b9e75cfa2..de212b0ca6a34b651e2686ee61781e4fb75db0b0 100644 --- a/fileTransfer/e2e/wrapper.go +++ b/fileTransfer/e2e/wrapper.go @@ -12,7 +12,7 @@ import ( "gitlab.com/elixxir/client/e2e" "gitlab.com/elixxir/client/e2e/receive" ft "gitlab.com/elixxir/client/fileTransfer" - e2eCrypto "gitlab.com/elixxir/crypto/e2e" + cryptoE2e "gitlab.com/elixxir/crypto/e2e" ftCrypto "gitlab.com/elixxir/crypto/fileTransfer" "gitlab.com/xx_network/primitives/id" "time" @@ -39,7 +39,7 @@ type Wrapper struct { // for easier testing. type e2eHandler interface { SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, - params e2e.Params) ([]id.Round, e2eCrypto.MessageID, time.Time, error) + params e2e.Params) (cryptoE2e.SendReport, error) RegisterListener(senderID *id.ID, messageType catalog.MessageType, newListener receive.Listener) receive.ListenerID } diff --git a/groupChat/e2eManager_test.go b/groupChat/e2eManager_test.go index 37e4019cb8442cf95c8537cbb412d2d4a5d1e585..1c4a777d149876b5433655aebd3c087d446f3c79 100644 --- a/groupChat/e2eManager_test.go +++ b/groupChat/e2eManager_test.go @@ -11,7 +11,7 @@ import ( "gitlab.com/elixxir/client/e2e/receive" "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/e2e" + cryptoE2e "gitlab.com/elixxir/crypto/e2e" "gitlab.com/xx_network/primitives/id" "sync" "testing" @@ -65,16 +65,15 @@ func (tnm *testE2eManager) GetE2eMsg(i int) testE2eMessage { } func (tnm *testE2eManager) SendE2E(_ catalog.MessageType, recipient *id.ID, - payload []byte, _ clientE2E.Params) ([]id.Round, e2e.MessageID, time.Time, - error) { + payload []byte, _ clientE2E.Params) (cryptoE2e.SendReport, error) { tnm.Lock() defer tnm.Unlock() tnm.errSkip++ if tnm.sendErr == 1 { - return nil, e2e.MessageID{}, time.Time{}, errors.New("SendE2E error") + return cryptoE2e.SendReport{}, errors.New("SendE2E error") } else if tnm.sendErr == 2 && tnm.errSkip%2 == 0 { - return nil, e2e.MessageID{}, time.Time{}, errors.New("SendE2E error") + return cryptoE2e.SendReport{}, errors.New("SendE2E error") } tnm.e2eMessages = append(tnm.e2eMessages, testE2eMessage{ @@ -82,7 +81,7 @@ func (tnm *testE2eManager) SendE2E(_ catalog.MessageType, recipient *id.ID, Payload: payload, }) - return []id.Round{0, 1, 2, 3}, e2e.MessageID{}, time.Time{}, nil + return cryptoE2e.SendReport{RoundList: []id.Round{0, 1, 2, 3}}, nil } func (*testE2eManager) RegisterListener(*id.ID, catalog.MessageType, receive.Listener) receive.ListenerID { diff --git a/groupChat/interface.go b/groupChat/interface.go index 0355c90943797cb7ab98d7e02e648ba946f1692b..d670a565c2e2a3aa16ec061980ee3f331acae19b 100644 --- a/groupChat/interface.go +++ b/groupChat/interface.go @@ -32,7 +32,7 @@ import ( "gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/client/xxdk" "gitlab.com/elixxir/crypto/cyclic" - crypto "gitlab.com/elixxir/crypto/e2e" + cryptoE2e "gitlab.com/elixxir/crypto/e2e" "gitlab.com/elixxir/crypto/fastRNG" "gitlab.com/elixxir/crypto/group" "gitlab.com/xx_network/primitives/id" @@ -126,7 +126,7 @@ type groupCmix interface { // needed by GroupChat type groupE2eHandler interface { SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, - params e2e.Params) ([]id.Round, crypto.MessageID, time.Time, error) + params e2e.Params) (cryptoE2e.SendReport, error) RegisterListener(senderID *id.ID, messageType catalog.MessageType, newListener receive.Listener) receive.ListenerID AddService(tag string, processor message.Processor) error diff --git a/groupChat/sendRequests.go b/groupChat/sendRequests.go index b28985361e09183b6b4d807e10c770b454386bda..ff566063a696effc99444dd024aee9891e627418 100644 --- a/groupChat/sendRequests.go +++ b/groupChat/sendRequests.go @@ -120,13 +120,13 @@ func (m *manager) sendRequest(memberID *id.ID, request []byte) ([]id.Round, erro p.LastServiceTag = catalog.GroupRq p.DebugTag = "group.Request" - rounds, _, _, err := m.getE2eHandler().SendE2E( + sendReport, err := m.getE2eHandler().SendE2E( catalog.GroupCreationRequest, memberID, request, p) if err != nil { return nil, errors.Errorf(sendE2eErr, memberID, err) } - return rounds, nil + return sendReport.RoundList, nil } // roundIdMap2List converts the map of round IDs to a list of round IDs. diff --git a/restlike/connect/receiver.go b/restlike/connect/receiver.go index d6e87c57489a4235cd0e225fb38c4c87dad4afc3..be76084b075900e9b25741bab62131281191eb6c 100644 --- a/restlike/connect/receiver.go +++ b/restlike/connect/receiver.go @@ -55,7 +55,7 @@ func respond(response *restlike.Message, conn connect.Connection) error { } // TODO: Parameterize params - _, _, _, err = conn.SendE2E(catalog.XxMessage, payload, e2e.GetDefaultParams()) + _, err = conn.SendE2E(catalog.XxMessage, payload, e2e.GetDefaultParams()) if err != nil { return errors.Errorf("unable to send restlike response message: %+v", err) } diff --git a/restlike/connect/request.go b/restlike/connect/request.go index 4ea32656a2f3716481153e1955d0435311b61244..0dd35c27f71139ee9a39c3dad0ccc9eb7914532d 100644 --- a/restlike/connect/request.go +++ b/restlike/connect/request.go @@ -49,7 +49,8 @@ func (s *Request) Request(method restlike.Method, path restlike.URI, s.Net.RegisterListener(catalog.XxMessage, &response{responseCallback: cb}) // Transmit the Message - _, _, _, err = s.Net.SendE2E(catalog.XxMessage, msg, e2eParams) + // fixme: should this use the key residue? + _, err = s.Net.SendE2E(catalog.XxMessage, msg, e2eParams) if err != nil { return nil, err } @@ -84,6 +85,6 @@ func (s *Request) AsyncRequest(method restlike.Method, path restlike.URI, s.Net.RegisterListener(catalog.XxMessage, &response{responseCallback: cb}) // Transmit the Message - _, _, _, err = s.Net.SendE2E(catalog.XxMessage, msg, e2eParams) + _, err = s.Net.SendE2E(catalog.XxMessage, msg, e2eParams) return err } diff --git a/storage/versioned/kv.go b/storage/versioned/kv.go index 2b8b7ae2129d5a67fdf576297a4318e229c91ff8..13f05e82c7449282c669453eefbff1a6bb03ad46 100644 --- a/storage/versioned/kv.go +++ b/storage/versioned/kv.go @@ -164,3 +164,9 @@ func (v *KV) GetFullKey(key string, version uint64) string { func (v *KV) makeKey(key string, version uint64) string { return fmt.Sprintf("%s%s_%d", v.prefix, key, version) } + +// Exists returns false if the error indicates the element doesn't +// exist. +func (v *KV) Exists(err error) bool { + return ekv.Exists(err) +} diff --git a/ud/mockE2e_test.go b/ud/mockE2e_test.go index c57e148fe6a63845a480bebb1aa939789b600bfc..bcdf30e75cfb5d3b5e1a4ba97282fcd099879689 100644 --- a/ud/mockE2e_test.go +++ b/ud/mockE2e_test.go @@ -109,7 +109,7 @@ func (m mockE2eHandler) StartProcesses() (stoppable.Stoppable, error) { panic("implement me") } -func (m mockE2eHandler) SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, params e2e.Params) ([]id.Round, cryptoE2e.MessageID, time.Time, error) { +func (m mockE2eHandler) SendE2E(mt catalog.MessageType, recipient *id.ID, payload []byte, params e2e.Params) (cryptoE2e.SendReport, error) { //TODO implement me panic("implement me") }