diff --git a/api/authenticatedChannel.go b/api/authenticatedChannel.go index 0af89ff00d7f87f5590d55f4b2dfcd2788d013d0..88682af983c107345b6415648bec9558f2eb4d6b 100644 --- a/api/authenticatedChannel.go +++ b/api/authenticatedChannel.go @@ -20,16 +20,17 @@ import ( // RequestAuthenticatedChannel sends a request to another party to establish an // authenticated channel // It will not run if the network status is not healthy -// An error will be returned if a channel already exists, if a request was -// already received, or if a request was already sent +// An error will be returned if a channel already exists or if a request was +// already received // When a confirmation occurs, the channel will be created and the callback // will be called +// Can be retried. func (c *Client) RequestAuthenticatedChannel(recipient, me contact.Contact, - message string) error { + message string) (id.Round, error) { jww.INFO.Printf("RequestAuthenticatedChannel(%s)", recipient.ID) if !c.network.GetHealthTracker().IsHealthy() { - return errors.New("Cannot request authenticated channel " + + return 0, errors.New("Cannot request authenticated channel " + "creation when the network is not healthy") } @@ -60,11 +61,12 @@ func (c *Client) GetAuthenticatedChannelRequest(partner *id.ID) (contact.Contact // An error will be returned if a channel already exists, if a request doest // exist, or if the passed in contact does not exactly match the received // request -func (c *Client) ConfirmAuthenticatedChannel(recipient contact.Contact) error { +// Can be retried. +func (c *Client) ConfirmAuthenticatedChannel(recipient contact.Contact) (id.Round, error) { jww.INFO.Printf("ConfirmAuthenticatedChannel(%s)", recipient.ID) if !c.network.GetHealthTracker().IsHealthy() { - return errors.New("Cannot request authenticated channel " + + return 0, errors.New("Cannot request authenticated channel " + "creation when the network is not healthy") } diff --git a/auth/confirm.go b/auth/confirm.go index fee1433a2c22b7323cb5c1ce9d1ea57c6108c9a4..d91f81e33e9e1d52aac5136e620ec405842ccd24 100644 --- a/auth/confirm.go +++ b/auth/confirm.go @@ -12,26 +12,23 @@ import ( jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces" "gitlab.com/elixxir/client/interfaces/params" - "gitlab.com/elixxir/client/interfaces/utility" "gitlab.com/elixxir/client/storage" - ds "gitlab.com/elixxir/comms/network/dataStructures" + "gitlab.com/xx_network/primitives/id" "gitlab.com/elixxir/crypto/contact" "gitlab.com/elixxir/crypto/diffieHellman" cAuth "gitlab.com/elixxir/crypto/e2e/auth" "gitlab.com/elixxir/primitives/format" - "gitlab.com/elixxir/primitives/states" "io" - "time" ) func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, - storage *storage.Session, net interfaces.NetworkManager) error { + storage *storage.Session, net interfaces.NetworkManager) (id.Round, error) { /*edge checking*/ // check that messages can be sent over the network if !net.GetHealthTracker().IsHealthy() { - return errors.New("Cannot confirm authenticated message " + + return 0, errors.New("Cannot confirm authenticated message " + "when the network is not healthy") } @@ -40,14 +37,14 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, // the lock storedContact, err := storage.Auth().GetReceivedRequest(partner.ID) if err != nil { - return errors.Errorf("failed to find a pending Auth Request: %s", + return 0, errors.Errorf("failed to find a pending Auth Request: %s", err) } // verify the passed contact matches what is stored if storedContact.DhPubKey.Cmp(partner.DhPubKey) != 0 { storage.Auth().Fail(partner.ID) - return errors.WithMessage(err, "Pending Auth Request has different "+ + return 0, errors.WithMessage(err, "Pending Auth Request has different "+ "pubkey than stored") } @@ -68,7 +65,7 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, _, err = rng.Read(salt) if err != nil { storage.Auth().Fail(partner.ID) - return errors.Wrap(err, "Failed to generate salt for "+ + return 0, errors.Wrap(err, "Failed to generate salt for "+ "confirmation") } @@ -108,21 +105,19 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, if err := storage.E2e().AddPartner(partner.ID, partner.DhPubKey, newPrivKey, p, p); err != nil { storage.Auth().Fail(partner.ID) - return errors.Errorf("Failed to create channel with partner (%s) "+ + return 0, errors.Errorf("Failed to create channel with partner (%s) "+ "on confirmation: %+v", partner.ID, err) } // delete the in progress negotiation // this unlocks the request lock - if err := storage.Auth().Delete(partner.ID); err != nil { - return errors.Errorf("UNRECOVERABLE! Failed to delete in "+ + //fixme - do these deletes at a later date + /*if err := storage.Auth().Delete(partner.ID); err != nil { + return 0, errors.Errorf("UNRECOVERABLE! Failed to delete in "+ "progress negotiation with partner (%s) after creating confirmation: %+v", partner.ID, err) - } - - //store the message as a critical message so it will always be sent - storage.GetCriticalRawMessages().AddProcessing(cmixMsg, partner.ID) + }*/ jww.INFO.Printf("Confirming Auth with %s, msgDigest: %s", partner.ID, cmixMsg.Digest()) @@ -134,39 +129,11 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, // retried jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+ "to transmit: %+v", partner.ID, cmixMsg.Digest(), err) - storage.GetCriticalRawMessages().Failed(cmixMsg, partner.ID) - return errors.WithMessage(err, "Auth Confirm Failed to transmit") + return 0, errors.WithMessage(err, "Auth Confirm Failed to transmit") } jww.INFO.Printf("Confirm Request with %s (msgDigest: %s) sent on round %d", partner.ID, cmixMsg.Digest(), round) - /*check message delivery*/ - sendResults := make(chan ds.EventReturn, 1) - roundEvents := net.GetInstance().GetRoundEvents() - - roundEvents.AddRoundEventChan(round, sendResults, 1*time.Minute, - states.COMPLETED, states.FAILED) - - success, numFailed, _ := utility.TrackResults(sendResults, 1) - if !success { - if numFailed > 0 { - jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+ - "delivery due to round failure, will retry on reconnect", - partner.ID, cmixMsg.Digest()) - } else { - jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+ - "delivery due to timeout, will retry on reconnect", - partner.ID, cmixMsg.Digest()) - } - jww.ERROR.Printf("auth confirm failed to transmit, will be " + - "handled on reconnect") - storage.GetCriticalRawMessages().Failed(cmixMsg, partner.ID) - } else { - jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) delivered "+ - "sucesfully", partner.ID, cmixMsg.Digest()) - storage.GetCriticalRawMessages().Succeeded(cmixMsg, partner.ID) - } - - return nil + return round, nil } diff --git a/auth/request.go b/auth/request.go index 7c963123b49dd532734871c687277a318887093d..c43707904f835b19d1e64ba53cb4ec9fe550355f 100644 --- a/auth/request.go +++ b/auth/request.go @@ -12,59 +12,59 @@ import ( jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces" "gitlab.com/elixxir/client/interfaces/params" - "gitlab.com/elixxir/client/interfaces/utility" "gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/client/storage/auth" "gitlab.com/elixxir/client/storage/e2e" - ds "gitlab.com/elixxir/comms/network/dataStructures" "gitlab.com/elixxir/crypto/contact" + "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/diffieHellman" cAuth "gitlab.com/elixxir/crypto/e2e/auth" "gitlab.com/elixxir/primitives/format" - "gitlab.com/elixxir/primitives/states" + "gitlab.com/xx_network/primitives/id" "io" "strings" - "time" ) const terminator = ";" func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, - storage *storage.Session, net interfaces.NetworkManager) error { + storage *storage.Session, net interfaces.NetworkManager) (id.Round, error) { /*edge checks generation*/ // check that an authenticated channel does not already exists if _, err := storage.E2e().GetPartner(partner.ID); err == nil || !strings.Contains(err.Error(), e2e.NoPartnerErrorStr) { - return errors.Errorf("Authenticated channel already " + + return 0, errors.Errorf("Authenticated channel already " + "established with partner") } // check that the request is being sent from the proper ID if !me.ID.Cmp(storage.GetUser().ReceptionID) { - return errors.Errorf("Authenticated channel request " + + return 0, errors.Errorf("Authenticated channel request " + "can only be sent from user's identity") } // check that the message is properly formed if strings.Contains(message, terminator) { - return errors.Errorf("Message cannot contain '%s'", terminator) + return 0, errors.Errorf("Message cannot contain '%s'", terminator) } + //denote if this is a resend of an old request + resend := false + //lookup if an ongoing request is occurring - rqType, _, _, err := storage.Auth().GetRequest(partner.ID) - if err != nil && strings.Contains(err.Error(), auth.NoRequest) { - err = nil - } - if err != nil { + rqType, sr, _, err := storage.Auth().GetRequest(partner.ID) + + if err != nil && !strings.Contains(err.Error(), auth.NoRequest){ if rqType == auth.Receive { - return errors.WithMessage(err, - "Cannot send a request after "+ - "receiving a request") + return 0, errors.WithMessage(err, + "Cannot send a request after receiving a request") } else if rqType == auth.Sent { - return errors.WithMessage(err, - "Cannot send a request after "+ - "already sending one") + resend = true + }else{ + return 0, errors.WithMessage(err, + "Cannot send a request after receiving unknown error " + + "on requesting contact status") } } @@ -76,7 +76,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, ecrFmt := newEcrFormat(baseFmt.GetEcrPayloadLen()) requestFmt, err := newRequestFormat(ecrFmt) if err != nil { - return errors.Errorf("failed to make request format: %+v", err) + return 0, errors.Errorf("failed to make request format: %+v", err) } //check the payload fits @@ -85,7 +85,7 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, msgPayloadBytes := []byte(msgPayload) if len(msgPayloadBytes) > requestFmt.MsgPayloadLen() { - return errors.Errorf("Combined message longer than space "+ + return 0, errors.Errorf("Combined message longer than space "+ "available in payload; available: %v, length: %v", requestFmt.MsgPayloadLen(), len(msgPayloadBytes)) } @@ -95,17 +95,27 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, salt := make([]byte, saltSize) _, err = rng.Read(salt) if err != nil { - return errors.Wrap(err, "Failed to generate salt") + return 0, errors.Wrap(err, "Failed to generate salt") + } + + var newPrivKey, newPubKey *cyclic.Int + + // in this case we have an ongoing request so we can resend the extant + // request + if resend{ + newPrivKey = sr.GetMyPrivKey() + newPubKey = sr.GetMyPubKey() + //in this case it is a new request and we must generate new keys + }else{ + //generate new keypair + newPrivKey = diffieHellman.GeneratePrivateKey(256, grp, rng) + newPubKey = diffieHellman.GeneratePublicKey(newPrivKey, grp) } //generate ownership proof ownership := cAuth.MakeOwnershipProof(storage.E2e().GetDHPrivateKey(), partner.DhPubKey, storage.E2e().GetGroup()) - //generate new keypair - newPrivKey := diffieHellman.GeneratePrivateKey(256, grp, rng) - newPubKey := diffieHellman.GeneratePublicKey(newPrivKey, grp) - jww.TRACE.Printf("RequestAuth MYPUBKEY: %v", newPubKey.Bytes()) jww.TRACE.Printf("RequestAuth THEIRPUBKEY: %v", partner.DhPubKey.Bytes()) @@ -130,67 +140,30 @@ func RequestAuth(partner, me contact.Contact, message string, rng io.Reader, /*store state*/ //fixme: channel is bricked if the first store succedes but the second fails //store the in progress auth - err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, newPrivKey, - newPrivKey, confirmFp) - if err != nil { - return errors.Errorf("Failed to store auth request: %s", err) + if !resend{ + err = storage.Auth().AddSent(partner.ID, partner.DhPubKey, newPrivKey, + newPrivKey, confirmFp) + if err != nil { + return 0, errors.Errorf("Failed to store auth request: %s", err) + } } - //store the message as a critical message so it will always be sent - storage.GetCriticalRawMessages().AddProcessing(cmixMsg, partner.ID) + jww.INFO.Printf("Requesting Auth with %s, msgDigest: %s", + partner.ID, cmixMsg.Digest()) - go func() { - jww.INFO.Printf("Requesting Auth with %s, msgDigest: %s", - partner.ID, cmixMsg.Digest()) - - /*send message*/ - round, _, err := net.SendCMIX(cmixMsg, partner.ID, - params.GetDefaultCMIX()) - if err != nil { - // if the send fails just set it to failed, it will - // but automatically retried - jww.WARN.Printf("Auth Request with %s (msgDigest: %s)"+ - " failed to transmit: %+v", partner.ID, - cmixMsg.Digest(), err) - storage.GetCriticalRawMessages().Failed(cmixMsg, - partner.ID) - } + /*send message*/ + round, _, err := net.SendCMIX(cmixMsg, partner.ID, + params.GetDefaultCMIX()) + if err != nil { + // if the send fails just set it to failed, it will + // but automatically retried + return 0, errors.WithMessagef(err, "Auth Request with %s " + + "(msgDigest: %s) failed to transmit: %+v", partner.ID, + cmixMsg.Digest(), err) + } - jww.INFO.Printf("Auth Request with %s (msgDigest: %s) sent"+ - " on round %d", partner.ID, cmixMsg.Digest(), round) - - /*check message delivery*/ - sendResults := make(chan ds.EventReturn, 1) - roundEvents := net.GetInstance().GetRoundEvents() - - roundEvents.AddRoundEventChan(round, sendResults, 1*time.Minute, - states.COMPLETED, states.FAILED) - - success, numFailed, _ := utility.TrackResults(sendResults, 1) - if !success { - if numFailed > 0 { - jww.WARN.Printf("Auth Request with %s "+ - "(msgDigest: %s) failed "+ - "delivery due to round failure, "+ - "will retry on reconnect", - partner.ID, cmixMsg.Digest()) - } else { - jww.WARN.Printf("Auth Request with %s "+ - "(msgDigest: %s) failed "+ - "delivery due to timeout, "+ - "will retry on reconnect", - partner.ID, cmixMsg.Digest()) - } - storage.GetCriticalRawMessages().Failed(cmixMsg, - partner.ID) - } else { - jww.INFO.Printf("Auth Request with %s (msgDigest: %s) "+ - "delivered sucessfully", partner.ID, - cmixMsg.Digest()) - storage.GetCriticalRawMessages().Succeeded(cmixMsg, - partner.ID) - } - }() + jww.INFO.Printf("Auth Request with %s (msgDigest: %s) sent"+ + " on round %d", partner.ID, cmixMsg.Digest(), round) - return nil + return round, nil } diff --git a/bindings/authenticatedChannels.go b/bindings/authenticatedChannels.go index 28784c87f944bd3d15e43b873194f968dd513971..30b12f0a1b3039fba5b18eafeff874cc7a438a60 100644 --- a/bindings/authenticatedChannels.go +++ b/bindings/authenticatedChannels.go @@ -27,19 +27,20 @@ func (c *Client) MakePrecannedAuthenticatedChannel(precannedID int) (*Contact, e // authenticated channel // It will not run if the network status is not healthy // An error will be returned if a channel already exists, if a request was -// already received, or if a request was already sent +// already received. // When a confirmation occurs, the channel will be created and the callback // will be called +// This can be called many times and retried. // // This function takes the marshaled send report to ensure a memory leak does // not occur as a result of both sides of the bindings holding a refrence to // the same pointer. func (c *Client) RequestAuthenticatedChannel(recipientMarshaled, - meMarshaled []byte, message string) error { + meMarshaled []byte, message string) (int, error) { recipent, err := contact.Unmarshal(recipientMarshaled) if err != nil { - return errors.New(fmt.Sprintf("Failed to "+ + return 0, errors.New(fmt.Sprintf("Failed to "+ "RequestAuthenticatedChannel: Failed to Unmarshal Recipent: "+ "%+v", err)) } @@ -47,11 +48,13 @@ func (c *Client) RequestAuthenticatedChannel(recipientMarshaled, me, err := contact.Unmarshal(meMarshaled) if err != nil { - return errors.New(fmt.Sprintf("Failed to "+ + return 0, errors.New(fmt.Sprintf("Failed to "+ "RequestAuthenticatedChannel: Failed to Unmarshal Me: %+v", err)) } - return c.api.RequestAuthenticatedChannel(recipent, me, message) + rid, err := c.api.RequestAuthenticatedChannel(recipent, me, message) + + return int(rid), err } // RegisterAuthCallbacks registers both callbacks for authenticated channels. @@ -79,19 +82,26 @@ func (c *Client) RegisterAuthCallbacks(request AuthRequestCallback, // received request and sends a message to the requestor that the request has // been confirmed // It will not run if the network status is not healthy -// An error will be returned if a channel already exists, if a request doest +// An error will be returned if a request doest // exist, or if the passed in contact does not exactly match the received -// request -func (c *Client) ConfirmAuthenticatedChannel(recipientMarshaled []byte) error { +// request. +// This can be called many times and retried. +// +// This function takes the marshaled send report to ensure a memory leak does +// not occur as a result of both sides of the bindings holding a refrence to +// the same pointer. +func (c *Client) ConfirmAuthenticatedChannel(recipientMarshaled []byte) (int, error) { recipent, err := contact.Unmarshal(recipientMarshaled) if err != nil { - return errors.New(fmt.Sprintf("Failed to "+ + return 0, errors.New(fmt.Sprintf("Failed to "+ "ConfirmAuthenticatedChannel: Failed to Unmarshal Recipient: "+ "%+v", err)) } - return c.api.ConfirmAuthenticatedChannel(recipent) + rid, err := c.api.ConfirmAuthenticatedChannel(recipent) + + return int(rid), err } // VerifyOwnership checks if the ownership proof on a passed contact matches the diff --git a/cmd/root.go b/cmd/root.go index c6ea6c91425d2cf96f532287dfcbfdc387fc7639..0ec69bc76ad143f3a14632f9dc348d943a65d39c 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -95,7 +95,7 @@ var rootCmd = &cobra.Command{ requestor contact.Contact, message string) { jww.INFO.Printf("Channel Request: %s", requestor.ID) - err := client.ConfirmAuthenticatedChannel( + _, err := client.ConfirmAuthenticatedChannel( requestor) if err != nil { jww.FATAL.Panicf("%+v", err) @@ -399,7 +399,7 @@ func acceptChannel(client *api.Client, recipientID *id.ID) { if err != nil { jww.FATAL.Panicf("%+v", err) } - err = client.ConfirmAuthenticatedChannel( + _, err = client.ConfirmAuthenticatedChannel( recipientContact) if err != nil { jww.FATAL.Panicf("%+v", err) @@ -461,7 +461,7 @@ func addAuthenticatedChannel(client *api.Client, recipientID *id.ID, me := client.GetUser().GetContact() jww.INFO.Printf("Requesting auth channel from: %s", recipientID) - err := client.RequestAuthenticatedChannel(recipientContact, + _, err := client.RequestAuthenticatedChannel(recipientContact, me, msg) if err != nil { jww.FATAL.Panicf("%+v", err) diff --git a/cmd/single.go b/cmd/single.go index 7fe8e2038ef34240bd2ee363e6f38d8d94d26ed9..15f803b11bec0f775845fdfdfb9f8292c75ea2a7 100644 --- a/cmd/single.go +++ b/cmd/single.go @@ -55,7 +55,7 @@ var singleCmd = &cobra.Command{ authMgr.AddGeneralRequestCallback(func( requester contact.Contact, message string) { jww.INFO.Printf("Got request: %s", requester.ID) - err := client.ConfirmAuthenticatedChannel(requester) + _, err := client.ConfirmAuthenticatedChannel(requester) if err != nil { jww.FATAL.Panicf("%+v", err) } diff --git a/cmd/ud.go b/cmd/ud.go index ccefe891a4e87c2053ec62fd95e835115aa21a45..38cbecb2cd1c6572cd140b158f435fe4291500cd 100644 --- a/cmd/ud.go +++ b/cmd/ud.go @@ -55,7 +55,7 @@ var udCmd = &cobra.Command{ authMgr.AddGeneralRequestCallback(func( requester contact.Contact, message string) { jww.INFO.Printf("Got Request: %s", requester.ID) - err := client.ConfirmAuthenticatedChannel(requester) + _, err := client.ConfirmAuthenticatedChannel(requester) if err != nil { jww.FATAL.Panicf("%+v", err) }