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/api/client.go b/api/client.go index 8ce14676d76183bbb89ff3fbce9a64096085ae1b..d3cb829b84b0f87b2743d259cfe884973cb070d4 100644 --- a/api/client.go +++ b/api/client.go @@ -84,33 +84,12 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str protoUser := createNewUser(rngStream, cmixGrp, e2eGrp) - // Get current client version - currentVersion, err := version.ParseVersion(SEMVER) - if err != nil { - return errors.WithMessage(err, "Could not parse version string.") - } - - // Create Storage - passwordStr := string(password) - storageSess, err := storage.New(storageDir, passwordStr, protoUser, - currentVersion, cmixGrp, e2eGrp, rngStreamGen) + err = checkVersionAndSetupStorage(def, storageDir, password, protoUser, + cmixGrp, e2eGrp, rngStreamGen, false, registrationCode) if err != nil { return err } - // Save NDF to be used in the future - storageSess.SetBaseNDF(def) - - //store the registration code for later use - storageSess.SetRegCode(registrationCode) - - //move the registration state to keys generated - err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete) - if err != nil { - return errors.WithMessage(err, "Failed to denote state "+ - "change in session") - } - //TODO: close the session return nil } @@ -135,29 +114,39 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [ protoUser := createPrecannedUser(precannedID, rngStream, cmixGrp, e2eGrp) - // Get current client version - currentVersion, err := version.ParseVersion(SEMVER) + err = checkVersionAndSetupStorage(def, storageDir, password, protoUser, + cmixGrp, e2eGrp, rngStreamGen, true, "") if err != nil { - return errors.WithMessage(err, "Could not parse version string.") + return err } + //TODO: close the session + return nil +} - // Create Storage - passwordStr := string(password) - storageSess, err := storage.New(storageDir, passwordStr, protoUser, - currentVersion, cmixGrp, e2eGrp, rngStreamGen) +// NewVanityClient creates a user with a receptionID that starts with the supplied prefix +// It creates client storage, generates keys, connects, and registers +// with the network. Note that this does not register a username/identity, but +// merely creates a new cryptographic identity for adding such information +// at a later date. +func NewVanityClient(ndfJSON, storageDir string, password []byte, registrationCode string, userIdPrefix string) error { + jww.INFO.Printf("NewVanityClient()") + // Use fastRNG for RNG ops (AES fortuna based RNG using system RNG) + rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG) + rngStream := rngStreamGen.GetStream() + + // Parse the NDF + def, err := parseNDF(ndfJSON) if err != nil { return err } + cmixGrp, e2eGrp := decodeGroups(def) - // Save NDF to be used in the future - storageSess.SetBaseNDF(def) + protoUser := createNewVanityUser(rngStream, cmixGrp, e2eGrp, userIdPrefix) - //move the registration state to indicate registered with permissioning - err = storageSess.ForwardRegistrationStatus( - storage.PermissioningComplete) + err = checkVersionAndSetupStorage(def, storageDir, password, protoUser, + cmixGrp, e2eGrp, rngStreamGen, false, registrationCode) if err != nil { - return errors.WithMessage(err, "Failed to denote state "+ - "change in session") + return err } //TODO: close the session @@ -571,3 +560,43 @@ func decodeGroups(ndf *ndf.NetworkDefinition) (cmixGrp, e2eGrp *cyclic.Group) { return cmixGrp, e2eGrp } + +// checkVersionAndSetupStorage is common code shared by NewClient, NewPrecannedClient and NewVanityClient +// it checks client version and creates a new storage for user data +func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, storageDir string, password []byte, + protoUser user.User, cmixGrp, e2eGrp *cyclic.Group, rngStreamGen *fastRNG.StreamGenerator, + isPrecanned bool, registrationCode string) error { + // Get current client version + currentVersion, err := version.ParseVersion(SEMVER) + if err != nil { + return errors.WithMessage(err, "Could not parse version string.") + } + + // Create Storage + passwordStr := string(password) + storageSess, err := storage.New(storageDir, passwordStr, protoUser, + currentVersion, cmixGrp, e2eGrp, rngStreamGen) + if err != nil { + return err + } + + // Save NDF to be used in the future + storageSess.SetBaseNDF(def) + + if !isPrecanned { + //store the registration code for later use + storageSess.SetRegCode(registrationCode) + //move the registration state to keys generated + err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete) + } else { + //move the registration state to indicate registered with permissioning + err = storageSess.ForwardRegistrationStatus(storage.PermissioningComplete) + } + + if err != nil { + return errors.WithMessage(err, "Failed to denote state "+ + "change in session") + } + + return nil +} diff --git a/api/results.go b/api/results.go index da57e4c5180b622e5d8c6c8a9312cc081f797801..73d1193ccb9f0d3cb5667d6aa5a9170a2db78a5c 100644 --- a/api/results.go +++ b/api/results.go @@ -66,6 +66,8 @@ type historicalRoundsComm interface { func (c *Client) GetRoundResults(roundList []id.Round, timeout time.Duration, roundCallback RoundEventCallback) error { + jww.INFO.Printf("GetRoundResults(%v, %s)", roundList, timeout) + sendResults := make(chan ds.EventReturn, len(roundList)) return c.getRoundResults(roundList, timeout, roundCallback, @@ -90,6 +92,8 @@ func (c *Client) getRoundResults(roundList []id.Round, timeout time.Duration, allRoundsSucceeded := true numResults := 0 + oldestRound := networkInstance.GetOldestRoundID() + // Parse and adjudicate every round for _, rnd := range roundList { // Every round is timed out by default, until proven to have finished @@ -110,9 +114,7 @@ func (c *Client) getRoundResults(roundList []id.Round, timeout time.Duration, numResults++ } } else { - jww.DEBUG.Printf("Failed to ger round [%d] in buffer: %v", rnd, err) // Update oldest round (buffer may have updated externally) - oldestRound := networkInstance.GetOldestRoundID() if rnd < oldestRound { // If round is older that oldest round in our buffer // Add it to the historical round request (performed later) @@ -150,10 +152,12 @@ func (c *Client) getRoundResults(roundList []id.Round, timeout time.Duration, roundCallback(false, true, roundsResults) return case roundReport := <-sendResults: + numResults-- + // Skip if the round is nil (unknown from historical rounds) // they default to timed out, so correct behavior is preserved - if roundReport.RoundInfo == nil || roundReport.TimedOut { + if roundReport.RoundInfo == nil || roundReport.TimedOut { allRoundsSucceeded = false } else { // If available, denote the result @@ -180,7 +184,8 @@ func (c *Client) getHistoricalRounds(msg *pb.HistoricalRounds, var resp *pb.HistoricalRoundsResponse - for { + //retry 5 times + for i := 0; i < 5; i++ { // Find a gateway to request about the roundRequests result, err := c.GetNetworkInterface().GetSender().SendToAny(func(host *connect.Host) (interface{}, error) { return comms.RequestHistoricalRounds(host, msg) @@ -192,9 +197,15 @@ func (c *Client) getHistoricalRounds(msg *pb.HistoricalRounds, if err == nil { resp = result.(*pb.HistoricalRoundsResponse) break + } else { + jww.ERROR.Printf("Failed to lookup historical rounds: %s", err) } } + if resp == nil{ + return + } + // Process historical rounds, sending back to the caller thread for _, ri := range resp.Rounds { sendResults <- ds.EventReturn{ diff --git a/api/user.go b/api/user.go index 892d84c63c8fb0e29001774c6c645f351b3d00b8..48d7f992dfa32b48a3905752c55459ddc710e701 100644 --- a/api/user.go +++ b/api/user.go @@ -17,6 +17,10 @@ import ( "gitlab.com/xx_network/crypto/xx" "gitlab.com/xx_network/primitives/id" "math/rand" + "regexp" + "runtime" + "strings" + "sync" ) const ( @@ -134,3 +138,126 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic. ReceptionRSA: rsaKey, } } + +// createNewVanityUser generates an identity for cMix +// The identity's ReceptionID is not random but starts with the supplied prefix +func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix string) user.User { + // CMIX Keygen + // FIXME: Why 256 bits? -- this is spec but not explained, it has + // to do with optimizing operations on one side and still preserves + // decent security -- cite this. + cMixKeyBytes, err := csprng.GenerateInGroup(cmix.GetPBytes(), 256, rng) + if err != nil { + jww.FATAL.Panicf(err.Error()) + } + + // DH Keygen + // FIXME: Why 256 bits? -- this is spec but not explained, it has + // to do with optimizing operations on one side and still preserves + // decent security -- cite this. Why valid for BOTH e2e and cmix? + e2eKeyBytes, err := csprng.GenerateInGroup(e2e.GetPBytes(), 256, rng) + if err != nil { + jww.FATAL.Panicf(err.Error()) + } + + // RSA Keygen (4096 bit defaults) + transmissionRsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen) + if err != nil { + jww.FATAL.Panicf(err.Error()) + } + + // Salt, UID, etc gen + transmissionSalt := make([]byte, SaltSize) + n, err := csprng.NewSystemRNG().Read(transmissionSalt) + if err != nil { + jww.FATAL.Panicf(err.Error()) + } + if n != SaltSize { + jww.FATAL.Panicf("transmissionSalt size too small: %d", n) + } + transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User) + if err != nil { + jww.FATAL.Panicf(err.Error()) + } + + receptionRsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen) + if err != nil { + jww.FATAL.Panicf(err.Error()) + } + + var mu sync.Mutex // just in case more than one go routine tries to access receptionSalt and receptionID + done := make(chan struct{}) + found:= make(chan bool) + wg:= &sync.WaitGroup{} + cores := runtime.NumCPU() + + var receptionSalt []byte + var receptionID *id.ID + + pref := prefix + ignoreCase := false + // check if case-insensitivity is enabled + if strings.HasPrefix(prefix, "(?i)") { + pref = strings.ToLower(pref[4:]) + ignoreCase = true + } + // Check if prefix contains valid Base64 characters + match, _ := regexp.MatchString("^[A-Za-z0-9+/]+$", pref) + if match == false { + jww.FATAL.Panicf("Prefix contains non-Base64 characters") + } + jww.INFO.Printf("Vanity userID generation started. Prefix: %s Ignore-Case: %v NumCPU: %d", pref, ignoreCase, cores) + for w := 0; w < cores; w++{ + wg.Add(1) + go func() { + rSalt := make([]byte, SaltSize) + for { + select { + case <- done: + defer wg.Done() + return + default: + n, err = csprng.NewSystemRNG().Read(rSalt) + if err != nil { + jww.FATAL.Panicf(err.Error()) + } + if n != SaltSize { + jww.FATAL.Panicf("receptionSalt size too small: %d", n) + } + rID, err := xx.NewID(receptionRsaKey.GetPublic(), rSalt, id.User) + if err != nil { + jww.FATAL.Panicf(err.Error()) + } + id := rID.String() + if ignoreCase { + id = strings.ToLower(id) + } + if strings.HasPrefix(id, pref) { + mu.Lock() + receptionID = rID + receptionSalt = rSalt + mu.Unlock() + found <- true + defer wg.Done() + return + } + } + } + }() + } + // wait for a solution then close the done channel to signal the workers to exit + <- found + close(done) + wg.Wait() + return user.User{ + TransmissionID: transmissionID.DeepCopy(), + TransmissionSalt: transmissionSalt, + TransmissionRSA: transmissionRsaKey, + ReceptionID: receptionID.DeepCopy(), + ReceptionSalt: receptionSalt, + ReceptionRSA: receptionRsaKey, + Precanned: false, + CmixDhPrivateKey: cmix.NewIntFromBytes(cMixKeyBytes), + E2eDhPrivateKey: e2e.NewIntFromBytes(e2eKeyBytes), + } +} diff --git a/auth/callback.go b/auth/callback.go index ef21512f88a06c19322c03518bc262d7d2e94ebe..2c39824cb8631b222d6140fd66d2e9f143873639 100644 --- a/auth/callback.go +++ b/auth/callback.go @@ -213,7 +213,7 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest, if mgr, err := m.storage.E2e().GetPartner(sr.GetPartner()); mgr != nil || err == nil { jww.WARN.Printf("Cannot confirm auth for %s, channel already "+ "exists.", sr.GetPartner()) - m.storage.Auth().Fail(sr.GetPartner()) + m.storage.Auth().Done(sr.GetPartner()) return } @@ -221,7 +221,7 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest, baseFmt, partnerPubKey, err := handleBaseFormat(cmixMsg, grp) if err != nil { jww.WARN.Printf("Failed to handle auth confirm: %s", err) - m.storage.Auth().Fail(sr.GetPartner()) + m.storage.Auth().Done(sr.GetPartner()) return } @@ -236,7 +236,7 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest, if !success { jww.WARN.Printf("Recieved auth confirmation failed its mac " + "check") - m.storage.Auth().Fail(sr.GetPartner()) + m.storage.Auth().Done(sr.GetPartner()) return } @@ -244,7 +244,7 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest, if err != nil { jww.WARN.Printf("Failed to unmarshal auth confirmation's "+ "encrypted payload: %s", err) - m.storage.Auth().Fail(sr.GetPartner()) + m.storage.Auth().Done(sr.GetPartner()) return } @@ -252,7 +252,7 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth.SentRequest, if err := m.doConfirm(sr, grp, partnerPubKey, sr.GetMyPrivKey(), sr.GetPartnerHistoricalPubKey(), ecrFmt.GetOwnership()); err != nil { jww.WARN.Printf("Confirmation failed: %s", err) - m.storage.Auth().Fail(sr.GetPartner()) + m.storage.Auth().Done(sr.GetPartner()) return } } diff --git a/auth/confirm.go b/auth/confirm.go index fee1433a2c22b7323cb5c1ce9d1ea57c6108c9a4..40c983c6feb73446495bb9307a2c6793fca7b259 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,15 @@ 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) } + defer storage.Auth().Done(partner.ID) // 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 "+ + storage.Auth().Done(partner.ID) + return 0, errors.WithMessage(err, "Pending Auth Request has different "+ "pubkey than stored") } @@ -67,8 +65,7 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, salt := make([]byte, saltSize) _, 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") } @@ -107,22 +104,19 @@ func ConfirmRequestAuth(partner contact.Contact, rng io.Reader, p := storage.E2e().GetE2ESessionParams() 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) "+ - "on confirmation: %+v", - partner.ID, err) + jww.WARN.Printf("Failed to create channel with partner (%s) "+ + "on confirmation, this is likley a replay: %s", + partner.ID, err.Error()) } // 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 +128,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/bindings/callback.go b/bindings/callback.go index d0fe898c204188646c74c647f41759b5988cbf69..a6526d24d3ba961db2b79bdc2fbd6a1b950821dc 100644 --- a/bindings/callback.go +++ b/bindings/callback.go @@ -31,12 +31,19 @@ type NetworkHealthCallback interface { Callback(bool) } -// RoundEventHandler handles round events happening on the cMix network. +// RoundEventCallback handles waiting on the exact state of a round on +// the cMix network. type RoundEventCallback interface { EventCallback(rid, state int, timedOut bool) } -// RoundEventHandler handles round events happening on the cMix network. +// RoundCompletionCallback is returned when the completion of a round is known. +type RoundCompletionCallback interface { + EventCallback(rid int, success, timedOut bool) +} + +// MessageDeliveryCallback gets called on the determination if all events +// related to a message send were successful. type MessageDeliveryCallback interface { EventCallback(msgID []byte, delivered, timedOut bool, roundResults []byte) } diff --git a/bindings/client.go b/bindings/client.go index 34fb521076fca455294824ef3104f1c67445669d..d5c40e456de1b263a48184250cbb67fecc9e0c88 100644 --- a/bindings/client.go +++ b/bindings/client.go @@ -8,7 +8,6 @@ package bindings import ( - "encoding/json" "errors" "fmt" jww "github.com/spf13/jwalterweatherman" @@ -157,11 +156,7 @@ func UnmarshalContact(b []byte) (*Contact, error) { //Unmarshals a marshaled send report object, returns an error if it fails func UnmarshalSendReport(b []byte) (*SendReport, error) { sr := &SendReport{} - if err := json.Unmarshal(b, sr); err != nil { - return nil, errors.New(fmt.Sprintf("Failed to Unmarshal "+ - "Send Report: %+v", err)) - } - return sr, nil + return sr, sr.Unmarshal(b) } // StartNetworkFollower kicks off the tracking of the network. It starts @@ -333,29 +328,55 @@ func (c *Client) RegisterRoundEventsHandler(rid int, cb RoundEventCallback, return newRoundUnregister(roundID, ec, c.api.GetRoundEvents()) } -// RegisterMessageDeliveryCB allows the caller to get notified if the rounds a -// message was sent in successfully completed. Under the hood, this uses the same -// interface as RegisterRoundEventsHandler, but provides a convenient way to use -// the interface in its most common form, looking up the result of message -// retrieval +// WaitForRoundCompletion allows the caller to get notified if a round +// has completed (or failed). Under the hood, this uses an API which uses the internal +// round data, network historical round lookup, and waiting on network events +// to determine what has (or will) occur. +// +// The callbacks will return at timeoutMS if no state update occurs +func (c *Client) WaitForRoundCompletion(roundID int, + rec RoundCompletionCallback, timeoutMS int) error { + + f := func(allRoundsSucceeded, timedOut bool, rounds map[id.Round]api.RoundResult) { + rec.EventCallback(roundID, allRoundsSucceeded, timedOut) + } + + timeout := time.Duration(timeoutMS) * time.Millisecond + + return c.api.GetRoundResults([]id.Round{id.Round(roundID)}, timeout, f) +} + +// WaitForMessageDelivery allows the caller to get notified if the rounds a +// message was sent in successfully completed. Under the hood, this uses an API +// which uses the internal round data, network historical round lookup, and +// waiting on network events to determine what has (or will) occur. // // The callbacks will return at timeoutMS if no state update occurs // // 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 reference to // the same pointer. -func (c *Client) WaitForRoundCompletion(marshaledSendReport []byte, +func (c *Client) WaitForMessageDelivery(marshaledSendReport []byte, mdc MessageDeliveryCallback, timeoutMS int) error { - + jww.INFO.Printf("WaitForMessageDelivery(%v, _, %v)", + marshaledSendReport, timeoutMS) sr, err := UnmarshalSendReport(marshaledSendReport) if err != nil { return errors.New(fmt.Sprintf("Failed to "+ - "WaitForRoundCompletion callback due to bad Send Report: %+v", err)) + "WaitForMessageDelivery callback due to bad Send Report: %+v", err)) + } + + if sr==nil || sr.rl == nil || len(sr.rl.list) == 0{ + return errors.New(fmt.Sprintf("Failed to "+ + "WaitForMessageDelivery callback due to invalid Send Report " + + "unmarshal: %s", string(marshaledSendReport))) } f := func(allRoundsSucceeded, timedOut bool, rounds map[id.Round]api.RoundResult) { results := make([]byte, len(sr.rl.list)) - + jww.INFO.Printf("Processing WaitForMessageDelivery report " + + "for %v, success: %v, timedout: %v", sr.mid, allRoundsSucceeded, + timedOut) for i, r := range sr.rl.list { if result, exists := rounds[r]; exists { results[i] = byte(result) @@ -367,7 +388,9 @@ func (c *Client) WaitForRoundCompletion(marshaledSendReport []byte, timeout := time.Duration(timeoutMS) * time.Millisecond - return c.api.GetRoundResults(sr.rl.list, timeout, f) + err = c.api.GetRoundResults(sr.rl.list, timeout, f) + + return err } // Returns a user object from which all information about the current user diff --git a/bindings/message.go b/bindings/message.go index 978a62743dbd823062f1c4a961e20d74f386c496..6cead4ad09a8be5fc49433bf9e68e5cf0ab87a9f 100644 --- a/bindings/message.go +++ b/bindings/message.go @@ -7,7 +7,9 @@ package bindings -import "gitlab.com/elixxir/client/interfaces/message" +import ( + "gitlab.com/elixxir/client/interfaces/message" +) // Message is a message received from the cMix network in the clear // or that has been decrypted using established E2E keys. @@ -36,10 +38,12 @@ func (m *Message) GetMessageType() int { } // Returns the message's timestamp in ms -func (m *Message) GetTimestampMS() int { - return int(m.r.Timestamp.Unix()) +func (m *Message) GetTimestampMS() int64 { + ts := m.r.Timestamp.UnixNano() + ts = (ts+999999)/1000000 + return ts } -func (m *Message) GetTimestampNano() int { - return int(m.r.Timestamp.UnixNano()) +func (m *Message) GetTimestampNano() int64 { + return m.r.Timestamp.UnixNano() } diff --git a/bindings/send.go b/bindings/send.go index a7e35873447758c22cb9ddfc8eddeaf86fe1bb73..673fad0003ac009b707de67be8f3edc9804f639f 100644 --- a/bindings/send.go +++ b/bindings/send.go @@ -135,6 +135,11 @@ type SendReport struct { mid e2e.MessageID } +type SendReportDisk struct{ + List []id.Round + Mid []byte +} + func (sr *SendReport) GetRoundList() *RoundList { return sr.rl } @@ -144,5 +149,22 @@ func (sr *SendReport) GetMessageID() []byte { } func (sr *SendReport) Marshal() ([]byte, error) { - return json.Marshal(sr) + srd := SendReportDisk{ + List: sr.rl.list, + Mid: sr.mid[:], + } + return json.Marshal(&srd) +} + +func (sr *SendReport) Unmarshal(b []byte) error { + srd := SendReportDisk{ + } + if err := json.Unmarshal(b, &srd); err!=nil{ + return errors.New(fmt.Sprintf("Failed to unmarshal send " + + "report: %s", err.Error())) + } + + copy(sr.mid[:],srd.Mid) + sr.rl = &RoundList{list:srd.List} + return nil } diff --git a/cmd/getndf.go b/cmd/getndf.go index 914412093c8f1247953473c29a02edcd68346235..7ac150020c911d695f646993e3a409c18d6cb8da 100644 --- a/cmd/getndf.go +++ b/cmd/getndf.go @@ -18,11 +18,13 @@ import ( // "gitlab.com/elixxir/client/switchboard" // "gitlab.com/elixxir/client/ud" // "gitlab.com/elixxir/primitives/fact" + "gitlab.com/elixxir/client/api" "gitlab.com/elixxir/comms/client" "gitlab.com/xx_network/comms/connect" //"time" pb "gitlab.com/elixxir/comms/mixmessages" "gitlab.com/xx_network/primitives/id" + "gitlab.com/xx_network/primitives/id/ephemeral" "gitlab.com/xx_network/primitives/utils" ) @@ -63,12 +65,14 @@ var getNDFCmd = &cobra.Command{ if gwHost != "" { host, _ := connect.NewHost(&id.TempGateway, gwHost, cert, params) + dummyID := ephemeral.ReservedIDs[0] pollMsg := &pb.GatewayPoll{ Partial: &pb.NDFHash{ Hash: nil, }, LastUpdate: uint64(0), - ReceptionID: id.DummyUser.Marshal(), + ReceptionID: dummyID[:], + ClientVersion: []byte(api.SEMVER), } resp, err := comms.SendPoll(host, pollMsg) if err != nil { diff --git a/cmd/init.go b/cmd/init.go index cf19521f066d1e9e878524a7ee75fd3471cf6b7c..b00f215475bfba0c513752b1d2fd01fd13cea5c8 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -11,6 +11,7 @@ package cmd import ( "fmt" "github.com/spf13/cobra" + "github.com/spf13/viper" jww "github.com/spf13/jwalterweatherman" ) @@ -29,5 +30,9 @@ var initCmd = &cobra.Command{ } func init() { + initCmd.Flags().StringP("userid-prefix", "", "", + "Desired prefix of userID to brute force when running init command. Prepend (?i) for case-insensitive. Only Base64 characters are valid.") + _ = viper.BindPFlag("userid-prefix", initCmd.Flags().Lookup("userid-prefix")) + rootCmd.AddCommand(initCmd) } diff --git a/cmd/root.go b/cmd/root.go index ac44e11d9643bd385e67e8fabafc7a4df9809a5b..567dfa016e59a06bde1da0e187f254997d71ba72 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) @@ -306,7 +306,7 @@ func createClient() *api.Client { storeDir := viper.GetString("session") regCode := viper.GetString("regcode") precannedID := viper.GetUint("sendid") - + userIDprefix := viper.GetString("userid-prefix") //create a new client if none exist if _, err := os.Stat(storeDir); os.IsNotExist(err) { // Load NDF @@ -320,8 +320,14 @@ func createClient() *api.Client { err = api.NewPrecannedClient(precannedID, string(ndfJSON), storeDir, []byte(pass)) } else { - err = api.NewClient(string(ndfJSON), storeDir, + if userIDprefix != "" { + err = api.NewVanityClient(string(ndfJSON), storeDir, + []byte(pass), regCode, userIDprefix) + } else { + err = api.NewClient(string(ndfJSON), storeDir, []byte(pass), regCode) + } + } if err != nil { @@ -399,7 +405,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 +467,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) } diff --git a/network/follow.go b/network/follow.go index 5a098dbf027ab2907a0fb0d2a18f7f660c324d44..698c7c5df120f22f0d9c94527b7e9f1583361c61 100644 --- a/network/follow.go +++ b/network/follow.go @@ -24,8 +24,8 @@ package network import ( "fmt" + "sync/atomic" "time" - jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces" "gitlab.com/elixxir/client/network/rounds" @@ -60,8 +60,9 @@ func (m *manager) followNetwork(report interfaces.ClientErrorReport, quitCh <-ch case <-ticker.C: m.follow(report, rng, m.Comms) case <-TrackTicker.C: - jww.INFO.Println(m.tracker.Report()) - m.tracker = newPollTracker() + numPolls := atomic.SwapUint64(m.tracker, 0) + jww.INFO.Printf("Polled the network %d times in the " + + "last %s", numPolls, debugTrackPeriod) } } } @@ -76,7 +77,7 @@ func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source, "impossible: %+v", err) } - m.tracker.Track(identity.EphId, identity.Source) + atomic.AddUint64(m.tracker, 1) // Get client version for poll version := m.Session.GetClientVersion() @@ -99,11 +100,13 @@ func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source, identity.EndRequest, identity.EndRequest.Sub(identity.StartRequest), host.GetId()) result, err := comms.SendPoll(host, &pollReq) if err != nil { - report( - "NetworkFollower", - fmt.Sprintf("Failed to poll network, \"%s\", Gateway: %s", err.Error(), host.String()), - fmt.Sprintf("%+v", err), - ) + if report != nil { + report( + "NetworkFollower", + fmt.Sprintf("Failed to poll network, \"%s\", Gateway: %s", err.Error(), host.String()), + fmt.Sprintf("%+v", err), + ) + } jww.ERROR.Printf("Unable to poll %s for NDF: %+v", host, err) } return result, err diff --git a/network/manager.go b/network/manager.go index d307e8f67c7cdafa70273fda3d297cd7c6a40cc1..e97a304d38ea561604efb1d9314a6b39e369b2de 100644 --- a/network/manager.go +++ b/network/manager.go @@ -46,8 +46,8 @@ type manager struct { round *rounds.Manager message *message.Manager - //map of polls for debugging - tracker *pollTracker + //number of polls done in a period of time + tracker *uint64 //tracks already checked rounds checked *checkedRounds @@ -70,10 +70,12 @@ func NewManager(session *storage.Session, switchboard *switchboard.Switchboard, // set them here when they are needed on startup session.E2e().SetE2ESessionParams(params.E2EParams) + tracker := uint64(0) + //create manager object m := manager{ param: params, - tracker: newPollTracker(), + tracker: &tracker, checked: newCheckedRounds(), } diff --git a/storage/auth/store.go b/storage/auth/store.go index a03dee9eaced47223f597f14d78c6c093ede6cfd..d6730d03d8fcde7db0ee9edb76cb056942be8b7c 100644 --- a/storage/auth/store.go +++ b/storage/auth/store.go @@ -355,17 +355,18 @@ func (s *Store) GetRequest(partner *id.ID) (RequestType, *SentRequest, contact.C } } -// Fail is one of two calls after using a request. This one is to be used when +// Done is one of two calls after using a request. This one is to be used when // the use is unsuccessful. It will allow any thread waiting on access to // continue using the structure. // It does not return an error because an error is not handleable. -func (s *Store) Fail(partner *id.ID) { +func (s *Store) Done(partner *id.ID) { s.mux.RLock() r, ok := s.requests[*partner] s.mux.RUnlock() if !ok { - jww.ERROR.Panicf("Request cannot be failed, not found: %s", partner) + jww.ERROR.Panicf("Request cannot be finished, not " + + "found: %s", partner) return } diff --git a/storage/auth/store_test.go b/storage/auth/store_test.go index 94d0318f3d702cd7f9fb58860ada31a1b6f54b17..9f94169dc07eefe12c2d7ec9685d3d256fa2f326 100644 --- a/storage/auth/store_test.go +++ b/storage/auth/store_test.go @@ -526,11 +526,11 @@ func TestStore_Fail(t *testing.T) { } }() - s.Fail(c.ID) + s.Done(c.ID) // Check if the request's mutex is locked if reflect.ValueOf(&s.requests[*c.ID].mux).Elem().FieldByName("state").Int() != 0 { - t.Errorf("Fail() did not unlock mutex.") + t.Errorf("Done() did not unlock mutex.") } } @@ -540,11 +540,11 @@ func TestStore_Fail_RequestNotInMap(t *testing.T) { defer func() { if r := recover(); r == nil { - t.Errorf("Fail() did not panic when the request is not in map.") + t.Errorf("Done() did not panic when the request is not in map.") } }() - s.Fail(id.NewIdFromUInt(rand.Uint64(), id.User, t)) + s.Done(id.NewIdFromUInt(rand.Uint64(), id.User, t)) } // Happy path: receive request.