diff --git a/api/client.go b/api/client.go index a9e632ee8c20b3ade858d47fd33f30c658e3e0f4..02d8cb741e863a6d44810615dd9958dcd15e9d28 100644 --- a/api/client.go +++ b/api/client.go @@ -63,7 +63,7 @@ type Client struct { //object used to register and communicate with permissioning permissioning *registration.Registration //object containing auth interactions - auth *auth.Manager + auth *auth.State //services system to track running threads followerServices *services diff --git a/auth/callback.go b/auth/callback.go index c82f0c85086ce903c1317056d26e620c1a0930fa..73b0a6bbe668a9643a38f0b20eb03c150fd5daf6 100644 --- a/auth/callback.go +++ b/auth/callback.go @@ -30,7 +30,7 @@ import ( "gitlab.com/xx_network/primitives/id" ) -func (m *Manager) StartProcesses() (stoppable.Stoppable, error) { +func (s *State) StartProcesses() (stoppable.Stoppable, error) { stop := stoppable.NewSingle("Auth") go func() { @@ -39,8 +39,8 @@ func (m *Manager) StartProcesses() (stoppable.Stoppable, error) { case <-stop.Quit(): stop.ToStopped() return - case msg := <-m.rawMessages: - m.processAuthMessage(msg) + case msg := <-s.rawMessages: + s.processAuthMessage(msg) } } }() @@ -48,8 +48,8 @@ func (m *Manager) StartProcesses() (stoppable.Stoppable, error) { return stop, nil } -func (m *Manager) processAuthMessage(msg message.Receive) { - authStore := m.storage.Auth() +func (s *State) processAuthMessage(msg message.Receive) { + authStore := s.storage.Auth() //lookup the message, check if it is an auth request cmixMsg, err := format.Unmarshal(msg.Payload) if err != nil { @@ -72,24 +72,24 @@ func (m *Manager) processAuthMessage(msg message.Receive) { } //denote that the message is not garbled - m.storage.GetGarbledMessages().Remove(cmixMsg) - grp := m.storage.E2e().GetGroup() + s.storage.GetGarbledMessages().Remove(cmixMsg) + grp := s.storage.E2e().GetGroup() switch fpType { case auth2.General: // if it is general, that means a new request has // been received - m.handleRequest(cmixMsg, myHistoricalPrivKey, grp) + s.handleRequest(cmixMsg, myHistoricalPrivKey, grp) case auth2.Specific: // if it is specific, that means the original request was sent // by this users and a confirmation has been received jww.INFO.Printf("Received AuthConfirm from %s, msgDigest: %s", sr.GetPartner(), cmixMsg.Digest()) - m.handleConfirm(cmixMsg, sr, grp) + s.handleConfirm(cmixMsg, sr, grp) } } -func (m *Manager) handleRequest(cmixMsg format.Message, +func (s *State) handleRequest(cmixMsg format.Message, myHistoricalPrivKey *cyclic.Int, grp *cyclic.Group) { //decode the outer format baseFmt, partnerPubKey, err := handleBaseFormat( @@ -155,7 +155,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, return } - events := m.net.GetEventManager() + events := s.net.GetEventManager() em := fmt.Sprintf("Received AuthRequest from %s,"+ " msgDigest: %s", partnerID, cmixMsg.Digest()) jww.INFO.Print(em) @@ -168,34 +168,34 @@ func (m *Manager) handleRequest(cmixMsg format.Message, // a negotiation or authenticated channel in progress fp := cAuth.CreateNegotiationFingerprint(partnerPubKey, partnerSIDHPubKey) - newFP, latest := m.storage.Auth().AddIfNew(partnerID, fp) + newFP, latest := s.storage.Auth().AddIfNew(partnerID, fp) resetSession := false autoConfirm := false if baseFmt.GetVersion() >= 1 && newFP && latest { // If we had an existing session and it's new, then yes, we // want to reset - if _, err := m.storage.E2e().GetPartner(partnerID); err == nil { + if _, err := s.storage.E2e().GetPartner(partnerID); err == nil { jww.INFO.Printf("Resetting session for %s", partnerID) resetSession = true // Most likely, we got 2 reset sessions at once, so this // is a non-fatal error but we will record a warning // just in case. - err = m.storage.E2e().DeletePartner(partnerID) + err = s.storage.E2e().DeletePartner(partnerID) if err != nil { jww.WARN.Printf("Unable to delete channel: %+v", err) } // Also delete any existing request, sent or received - m.storage.Auth().Delete(partnerID) + s.storage.Auth().Delete(partnerID) } // If we had an existing negotiation open, then it depends // If we've only received, then user has not confirmed, treat as // a non-duplicate request, so delete the old one (to cause new // callback to be called) - rType, _, _, err := m.storage.Auth().GetRequest(partnerID) + rType, _, _, err := s.storage.Auth().GetRequest(partnerID) if err != nil && rType == auth2.Receive { - m.storage.Auth().Delete(partnerID) + s.storage.Auth().Delete(partnerID) } // If we've already Sent and are now receiving, @@ -228,7 +228,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, // if it does and the keys used are the same as we have, send a // confirmation in case there are state issues. // do not store - if _, err := m.storage.E2e().GetPartner(partnerID); err == nil { + if _, err := s.storage.E2e().GetPartner(partnerID); err == nil { em := fmt.Sprintf("Received Auth request for %s, "+ "channel already exists. Ignoring", partnerID) jww.WARN.Print(em) @@ -237,7 +237,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, return } else { //check if the relationship already exists, - rType, _, c, err := m.storage.Auth().GetRequest(partnerID) + rType, _, c, err := s.storage.Auth().GetRequest(partnerID) if err != nil && !strings.Contains(err.Error(), auth2.NoRequest) { // if another error is received, print it and exit em := fmt.Sprintf("Received new Auth request for %s, "+ @@ -257,8 +257,8 @@ func (m *Manager) handleRequest(cmixMsg format.Message, events.Report(5, "Auth", "DuplicateRequest", em) // if the caller of the API wants requests replayed, // replay the duplicate request - if m.replayRequests { - cbList := m.requestCallbacks.Get(c.ID) + if s.replayRequests { + cbList := s.requestCallbacks.Get(c.ID) for _, cb := range cbList { rcb := cb.(interfaces.RequestCallback) go rcb(c) @@ -283,7 +283,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, // Check if I need to resend by comparing the // IDs - myBytes := m.storage.GetUser().ReceptionID.Bytes() + myBytes := s.storage.GetUser().ReceptionID.Bytes() theirBytes := partnerID.Bytes() for i := 0; i < len(myBytes); i++ { if myBytes[i] > theirBytes[i] { @@ -301,7 +301,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, } // If I do, delete my request on disk - m.storage.Auth().Delete(partnerID) + s.storage.Auth().Delete(partnerID) // Do the normal, fall out of this if block and // create the contact, note that we use the data @@ -336,7 +336,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, // fixme: the client will never be notified of the channel creation if a // crash occurs after the store but before the conclusion of the callback //create the auth storage - if err = m.storage.Auth().AddReceived(c, partnerSIDHPubKey); err != nil { + if err = s.storage.Auth().AddReceived(c, partnerSIDHPubKey); err != nil { em := fmt.Sprintf("failed to store contact Auth "+ "Request: %s", err) jww.WARN.Print(em) @@ -349,7 +349,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, var rndNum id.Round if autoConfirm || resetSession { // Call ConfirmRequestAuth to send confirmation - rndNum, err = m.ConfirmRequestAuth(c) + rndNum, err = s.ConfirmRequestAuth(c) if err != nil { jww.ERROR.Printf("Could not ConfirmRequestAuth: %+v", err) @@ -359,7 +359,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, if autoConfirm { jww.INFO.Printf("ConfirmRequestAuth to %s on round %d", partnerID, rndNum) - cbList := m.confirmCallbacks.Get(c.ID) + cbList := s.confirmCallbacks.Get(c.ID) for _, cb := range cbList { ccb := cb.(interfaces.ConfirmCallback) go ccb(c) @@ -368,7 +368,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, if resetSession { jww.INFO.Printf("Reset Auth %s on round %d", partnerID, rndNum) - cbList := m.resetCallbacks.Get(c.ID) + cbList := s.resetCallbacks.Get(c.ID) for _, cb := range cbList { ccb := cb.(interfaces.ResetNotificationCallback) go ccb(c) @@ -377,7 +377,7 @@ func (m *Manager) handleRequest(cmixMsg format.Message, } else { // fixme: if a crash occurs before or during the calls, the notification // will never be sent. - cbList := m.requestCallbacks.Get(c.ID) + cbList := s.requestCallbacks.Get(c.ID) for _, cb := range cbList { rcb := cb.(interfaces.RequestCallback) go rcb(c) @@ -386,17 +386,17 @@ func (m *Manager) handleRequest(cmixMsg format.Message, return } -func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth2.SentRequest, +func (s *State) handleConfirm(cmixMsg format.Message, sr *auth2.SentRequest, grp *cyclic.Group) { - events := m.net.GetEventManager() + events := s.net.GetEventManager() // check if relationship already exists - if mgr, err := m.storage.E2e().GetPartner(sr.GetPartner()); mgr != nil || err == nil { + if mgr, err := s.storage.E2e().GetPartner(sr.GetPartner()); mgr != nil || err == nil { em := fmt.Sprintf("Cannot confirm auth for %s, channel already "+ "exists.", sr.GetPartner()) jww.WARN.Print(em) events.Report(10, "Auth", "ConfirmError", em) - m.storage.Auth().Done(sr.GetPartner()) + s.storage.Auth().Done(sr.GetPartner()) return } @@ -407,7 +407,7 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth2.SentRequest, em := fmt.Sprintf("Failed to handle auth confirm: %s", err) jww.WARN.Print(em) events.Report(10, "Auth", "ConfirmError", em) - m.storage.Auth().Done(sr.GetPartner()) + s.storage.Auth().Done(sr.GetPartner()) return } @@ -426,7 +426,7 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth2.SentRequest, "check") jww.WARN.Print(em) events.Report(10, "Auth", "ConfirmError", em) - m.storage.Auth().Done(sr.GetPartner()) + s.storage.Auth().Done(sr.GetPartner()) return } @@ -436,7 +436,7 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth2.SentRequest, "encrypted payload: %s", err) jww.WARN.Print(em) events.Report(10, "Auth", "ConfirmError", em) - m.storage.Auth().Done(sr.GetPartner()) + s.storage.Auth().Done(sr.GetPartner()) return } @@ -446,26 +446,26 @@ func (m *Manager) handleConfirm(cmixMsg format.Message, sr *auth2.SentRequest, err) jww.WARN.Print(em) events.Report(10, "Auth", "ConfirmError", em) - m.storage.Auth().Done(sr.GetPartner()) + s.storage.Auth().Done(sr.GetPartner()) return } jww.TRACE.Printf("handleConfirm PARTNERSIDHPUBKEY: %v", partnerSIDHPubKey) // finalize the confirmation - if err := m.doConfirm(sr, grp, partnerPubKey, sr.GetMyPrivKey(), + if err := s.doConfirm(sr, grp, partnerPubKey, sr.GetMyPrivKey(), sr.GetPartnerHistoricalPubKey(), ecrFmt.GetOwnership(), partnerSIDHPubKey); err != nil { em := fmt.Sprintf("Confirmation failed: %s", err) jww.WARN.Print(em) events.Report(10, "Auth", "ConfirmError", em) - m.storage.Auth().Done(sr.GetPartner()) + s.storage.Auth().Done(sr.GetPartner()) return } } -func (m *Manager) doConfirm(sr *auth2.SentRequest, grp *cyclic.Group, +func (s *State) doConfirm(sr *auth2.SentRequest, grp *cyclic.Group, partnerPubKey, myPrivateKeyOwnershipProof, partnerPubKeyOwnershipProof *cyclic.Int, ownershipProof []byte, partnerSIDHPubKey *sidh.PublicKey) error { // verify the message came from the intended recipient @@ -477,8 +477,8 @@ func (m *Manager) doConfirm(sr *auth2.SentRequest, grp *cyclic.Group, // fixme: channel can get into a bricked state if the first save occurs and // the second does not - p := m.storage.E2e().GetE2ESessionParams() - if err := m.storage.E2e().AddPartner(sr.GetPartner(), + p := s.storage.E2e().GetE2ESessionParams() + if err := s.storage.E2e().AddPartner(sr.GetPartner(), partnerPubKey, sr.GetMyPrivKey(), partnerSIDHPubKey, sr.GetMySIDHPrivKey(), p, p); err != nil { return errors.Errorf("Failed to create channel with partner (%s) "+ @@ -486,24 +486,24 @@ func (m *Manager) doConfirm(sr *auth2.SentRequest, grp *cyclic.Group, sr.GetPartner(), err) } - m.backupTrigger("received confirmation from request") + s.backupTrigger("received confirmation from request") //remove the confirm fingerprint fp := sr.GetFingerprint() - if err := m.storage.GetEdge().Remove(edge.Preimage{ + if err := s.storage.GetEdge().Remove(edge.Preimage{ Data: preimage.Generate(fp[:], catalog.Confirm), Type: catalog.Confirm, Source: sr.GetPartner()[:], - }, m.storage.GetUser().ReceptionID); err != nil { + }, s.storage.GetUser().ReceptionID); err != nil { jww.WARN.Printf("Failed delete the preimage for confirm from %s: %+v", sr.GetPartner(), err) } - addPreimages(sr.GetPartner(), m.storage) + addPreimages(sr.GetPartner(), s.storage) // delete the in progress negotiation // this undoes the request lock - if err := m.storage.Auth().Delete(sr.GetPartner()); err != nil { + if err := s.storage.Auth().Delete(sr.GetPartner()); err != nil { return errors.Errorf("UNRECOVERABLE! Failed to delete in "+ "progress negotiation with partner (%s) after confirmation: %+v", sr.GetPartner(), err) @@ -519,13 +519,13 @@ func (m *Manager) doConfirm(sr *auth2.SentRequest, grp *cyclic.Group, // fixme: if a crash occurs before or during the calls, the notification // will never be sent. - cbList := m.confirmCallbacks.Get(c.ID) + cbList := s.confirmCallbacks.Get(c.ID) for _, cb := range cbList { ccb := cb.(interfaces.ConfirmCallback) go ccb(c) } - m.net.CheckGarbledMessages() + s.net.CheckGarbledMessages() return nil } @@ -535,22 +535,3 @@ func copySlice(s []byte) []byte { copy(c, s) return c } - -func handleBaseFormat(cmixMsg format.Message, grp *cyclic.Group) (baseFormat, - *cyclic.Int, error) { - - baseFmt, err := unmarshalBaseFormat(cmixMsg.GetContents(), - grp.GetP().ByteLen()) - if err != nil && baseFmt == nil { - return baseFormat{}, nil, errors.WithMessage(err, "Failed to"+ - " unmarshal auth") - } - - if !grp.BytesInside(baseFmt.pubkey) { - return baseFormat{}, nil, errors.WithMessage(err, "Received "+ - "auth confirmation public key is not in the e2e cyclic group") - } - partnerPubKey := grp.NewIntFromBytes(baseFmt.pubkey) - - return *baseFmt, partnerPubKey, nil -} diff --git a/auth/callbacks.go b/auth/callbacks.go index 2168c82d3636bdd9ff25c9d1c4c4cddf606b2445..428cf29db3411417590935014ce5333f3bd8b242 100644 --- a/auth/callbacks.go +++ b/auth/callbacks.go @@ -8,70 +8,45 @@ package auth import ( + "gitlab.com/elixxir/client/network/historical" + "gitlab.com/elixxir/client/network/identity/receptionID" + "gitlab.com/elixxir/crypto/contact" "gitlab.com/xx_network/primitives/id" "sync" ) +type Callback func(requestor contact.Contact, + receptionID receptionID.EphemeralIdentity, round historical.Round) + type callbackMap struct { - generalCallback []interface{} - specificCallback map[id.ID]interface{} - overrideCallback []interface{} - mux sync.RWMutex + callbacks map[id.ID]Callback + mux sync.RWMutex } func newCallbackMap() *callbackMap { return &callbackMap{ - generalCallback: make([]interface{}, 0), - specificCallback: make(map[id.ID]interface{}), - overrideCallback: make([]interface{}, 0), + callbacks: make(map[id.ID]Callback), } } //adds a general callback. This will be preempted by any specific callback -func (cm *callbackMap) AddGeneral(cb interface{}) { - cm.mux.Lock() - cm.generalCallback = append(cm.generalCallback, cb) - cm.mux.Unlock() -} - -//adds an override callback. This will NOT be preempted by any callback -func (cm *callbackMap) AddOverride(cb interface{}) { - cm.mux.Lock() - cm.overrideCallback = append(cm.overrideCallback, cb) - cm.mux.Unlock() -} - -// adds a callback for a specific user ID. Only only callback can exist for a -// user ID. False will be returned if a callback already exists and the new -// one was not added -func (cm *callbackMap) AddSpecific(id *id.ID, cb interface{}) bool { +func (cm *callbackMap) AddCallback(recipeint *id.ID, cb Callback) { cm.mux.Lock() defer cm.mux.Unlock() - if _, ok := cm.specificCallback[*id]; ok { - return false - } - cm.specificCallback[*id] = cb - return true + cm.callbacks[*recipeint] = cb } // removes a callback for a specific user ID if it exists. -func (cm *callbackMap) RemoveSpecific(id *id.ID) { +func (cm *callbackMap) RemoveCallback(id *id.ID) { cm.mux.Lock() defer cm.mux.Unlock() - delete(cm.specificCallback, *id) + delete(cm.callbacks, *id) } //get all callback which fit with the passed id -func (cm *callbackMap) Get(id *id.ID) []interface{} { +func (cm *callbackMap) Get(id *id.ID) (Callback, bool) { cm.mux.RLock() defer cm.mux.RUnlock() - cbList := cm.overrideCallback - - if specific, ok := cm.specificCallback[*id]; ok { - cbList = append(cbList, specific) - } else { - cbList = append(cbList, cm.generalCallback...) - } - - return cbList + cb, exist := cm.callbacks[*id] + return cb, exist } diff --git a/auth/confirm.go b/auth/confirm.go index 59e374b9d589275065118ab6ece63b86aad5614e..40f7f82ec491a9af8ccef5221377fd876e405793 100644 --- a/auth/confirm.go +++ b/auth/confirm.go @@ -9,14 +9,14 @@ package auth import ( "fmt" - "gitlab.com/elixxir/client/catalog" - "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/interfaces/params" - "gitlab.com/elixxir/client/interfaces/preimage" - "gitlab.com/elixxir/client/storage" - "gitlab.com/elixxir/client/storage/edge" + "gitlab.com/elixxir/client/auth/store" + "gitlab.com/elixxir/client/catalog" + "gitlab.com/elixxir/client/e2e/ratchet/partner/session" + "gitlab.com/elixxir/client/event" + "gitlab.com/elixxir/client/network" + "gitlab.com/elixxir/client/network/message" util "gitlab.com/elixxir/client/storage/utility" "gitlab.com/elixxir/crypto/contact" cAuth "gitlab.com/elixxir/crypto/e2e/auth" @@ -24,214 +24,151 @@ import ( "gitlab.com/xx_network/primitives/id" ) -func (m *Manager) ConfirmRequestAuth(partner contact.Contact) (id.Round, error) { - - /*edge checking*/ +func (s *State) ConfirmRequestAuth(partner contact.Contact, me *id.ID) ( + id.Round, error) { // check that messages can be sent over the network - if !m.net.GetHealthTracker().IsHealthy() { + if !s.net.IsHealthy() { return 0, errors.New("Cannot confirm authenticated message " + "when the network is not healthy") } - // Cannot confirm already established channels - if _, err := m.storage.E2e().GetPartner(partner.ID); err == nil { - em := fmt.Sprintf("Cannot ConfirmRequestAuth for %s, "+ - "channel already exists. Ignoring", partner.ID) - jww.WARN.Print(em) - m.net.GetEventManager().Report(5, "Auth", - "ConfirmRequestAuthIgnored", em) - //exit - return 0, errors.New(em) - } - - // check if the partner has an auth in progress - // this takes the lock, from this point forward any errors need to - // release the lock - storedContact, theirSidhKey, err := m.storage.Auth().GetReceivedRequest( - partner.ID) - if err != nil { - return 0, errors.Errorf( - "failed to find a pending Auth Request: %s", - err) - } - defer m.storage.Auth().Done(partner.ID) - - // verify the passed contact matches what is stored - if storedContact.DhPubKey.Cmp(partner.DhPubKey) != 0 { - return 0, errors.WithMessage(err, - "Pending Auth Request has different pubkey than stored") - } + return s.confirmRequestAuth(partner, me) - grp := m.storage.E2e().GetGroup() - - /*cryptographic generation*/ - - // generate ownership proof - ownership := cAuth.MakeOwnershipProof(m.storage.E2e().GetDHPrivateKey(), - partner.DhPubKey, m.storage.E2e().GetGroup()) - - rng := m.rng.GetStream() - - // generate new keypair - dhGrp := grp - dhPriv, dhPub := genDHKeys(dhGrp, rng) - sidhVariant := util.GetCompatibleSIDHVariant(theirSidhKey.Variant()) - sidhPriv, sidhPub := util.GenerateSIDHKeyPair(sidhVariant, rng) +} - rng.Close() +func (s *State) confirmRequestAuth(partner contact.Contact, me *id.ID) ( + id.Round, error) { - /*construct message*/ - // we build the payload before we save because it is technically fallible - // which can get into a bricked state if it fails - cmixMsg := format.NewMessage(m.storage.Cmix().GetGroup().GetP().ByteLen()) - baseFmt := newBaseFormat(cmixMsg.ContentsSize(), grp.GetP().ByteLen()) - ecrFmt := newEcrFormat(baseFmt.GetEcrPayloadLen()) + // check that messages can be sent over the network + if !s.net.IsHealthy() { + return 0, errors.New("Cannot confirm authenticated message " + + "when the network is not healthy") + } - // setup the encrypted payload - ecrFmt.SetOwnership(ownership) - ecrFmt.SetSidHPubKey(sidhPub) - // confirmation has no custom payload + kp := s.registeredIDs[*me] - // encrypt the payload - ecrPayload, mac := cAuth.Encrypt(dhPriv, partner.DhPubKey, - ecrFmt.data, grp) + var sentRound id.Round - // get the fingerprint from the old ownership proof - fp := cAuth.MakeOwnershipProofFP(storedContact.OwnershipProof) - preimg := preimage.Generate(fp[:], catalog.Confirm) + //run the handler + err := s.store.HandleReceivedRequest(partner.ID, me, func(rr *store.ReceivedRequest) error { + // verify the passed contact matches what is stored + if rr.GetContact().DhPubKey.Cmp(partner.DhPubKey) != 0 { + return errors.New("pending Auth Request has different " + + "pubkey than stored") + } - // final construction - baseFmt.SetEcrPayload(ecrPayload) - baseFmt.SetPubKey(dhPub) + /*cryptographic generation*/ + + // generate ownership proof + ownership := cAuth.MakeOwnershipProof(kp.privkey, partner.DhPubKey, + s.e2e.GetGroup()) + + rng := s.rng.GetStream() + + // generate new keypair + dhPriv, dhPub := genDHKeys(s.e2e.GetGroup(), rng) + sidhVariant := util.GetCompatibleSIDHVariant( + rr.GetTheirSidHPubKeyA().Variant()) + sidhPriv, sidhPub := util.GenerateSIDHKeyPair(sidhVariant, rng) + + rng.Close() + + /*construct message*/ + // we build the payload before we save because it is technically fallible + // which can get into a bricked state if it fails + baseFmt := newBaseFormat(s.net.GetMaxMessageLength(), + s.e2e.GetGroup().GetP().ByteLen()) + ecrFmt := newEcrFormat(baseFmt.GetEcrPayloadLen()) + + // setup the encrypted payload + ecrFmt.SetOwnership(ownership) + ecrFmt.SetSidHPubKey(sidhPub) + // confirmation has no custom payload + + // encrypt the payload + ecrPayload, mac := cAuth.Encrypt(dhPriv, partner.DhPubKey, + ecrFmt.data, s.e2e.GetGroup()) + + // get the fingerprint from the old ownership proof + fp := cAuth.MakeOwnershipProofFP(rr.GetContact().OwnershipProof) + + // final construction + baseFmt.SetEcrPayload(ecrPayload) + baseFmt.SetPubKey(dhPub) + + jww.TRACE.Printf("SendConfirm PARTNERPUBKEY: %v", + partner.DhPubKey.Bytes()) + jww.TRACE.Printf("SendConfirm MYPUBKEY: %v", dhPub.Bytes()) + + jww.TRACE.Printf("SendConfirm ECRPAYLOAD: %v", baseFmt.GetEcrPayload()) + jww.TRACE.Printf("SendConfirm MAC: %v", mac) + + // warning: channel can get into a bricked state if the first save occurs and + // the second does not or the two occur and the storage into critical + // messages does not occur + + // create local relationship + p := session.GetDefaultParams() + _, err := s.e2e.AddPartner(me, partner.ID, partner.DhPubKey, dhPriv, + rr.GetTheirSidHPubKeyA(), sidhPriv, p, p) + if err != nil { + em := fmt.Sprintf("Failed to create channel with partner (%s) "+ + "on confirmation, this is likley a replay: %s", + partner.ID, err.Error()) + jww.WARN.Print(em) + s.event.Report(10, "Auth", "SendConfirmError", em) + } - cmixMsg.SetKeyFP(fp) - cmixMsg.SetMac(mac) - cmixMsg.SetContents(baseFmt.Marshal()) + //todo: s.backupTrigger("confirmed authenticated channel") - jww.TRACE.Printf("SendConfirm cMixMsg contents: %v", - cmixMsg.GetContents()) + jww.INFO.Printf("Confirming Auth from %s to %s, msgDigest: %s", + partner.ID, me, format.DigestContents(baseFmt.Marshal())) - jww.TRACE.Printf("SendConfirm PARTNERPUBKEY: %v", - partner.DhPubKey.Bytes()) - jww.TRACE.Printf("SendConfirm MYPUBKEY: %v", dhPub.Bytes()) + //service used for noticiation only - jww.TRACE.Printf("SendConfirm ECRPAYLOAD: %v", baseFmt.GetEcrPayload()) - jww.TRACE.Printf("SendConfirm MAC: %v", mac) + /*send message*/ + if err = s.store.StoreConfirmation(partner.ID, me, baseFmt.Marshal(), + mac, fp); err == nil { + jww.WARN.Printf("Failed to store confirmation for replay "+ + "for relationship between %s and %s, cannot be replayed: %+v", + partner.ID, me, err) + } - // fixme: channel can get into a bricked state if the first save occurs and - // the second does not or the two occur and the storage into critical - // messages does not occur + //send confirmation + sentRound, err = sendAuthConfirm(s.net, partner.ID, me, fp, + baseFmt.Marshal(), mac, s.event) - events := m.net.GetEventManager() + return nil + }) + return sentRound, err +} - // create local relationship - p := m.storage.E2e().GetE2ESessionParams() - if err := m.storage.E2e().AddPartner(partner.ID, partner.DhPubKey, - dhPriv, theirSidhKey, sidhPriv, - p, p); err != nil { - em := fmt.Sprintf("Failed to create channel with partner (%s) "+ - "on confirmation, this is likley a replay: %s", - partner.ID, err.Error()) - jww.WARN.Print(em) - events.Report(10, "Auth", "SendConfirmError", em) +func sendAuthConfirm(net network.Manager, partner, me *id.ID, + fp format.Fingerprint, payload, mac []byte, event event.Manager) ( + id.Round, error) { + svc := message.Service{ + Identifier: partner.Marshal(), + Tag: catalog.Default, + Metadata: nil, } - m.backupTrigger("confirmed authenticated channel") - - addPreimages(partner.ID, m.storage) - - // delete the in progress negotiation - // this unlocks the request lock - // 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) - }*/ - - jww.INFO.Printf("Confirming Auth with %s, msgDigest: %s", - partner.ID, cmixMsg.Digest()) - - param := params.GetDefaultCMIX() - param.IdentityPreimage = preimg - param.DebugTag = "auth.Confirm" - /*send message*/ - round, _, err := m.net.SendCMIX(cmixMsg, partner.ID, param) + cmixParam := network.GetDefaultCMIXParams() + cmixParam.DebugTag = "auth.Confirm" + cmixParam.Critical = true + sentRound, _, err := net.SendCMIX(partner, fp, svc, payload, mac, cmixParam) if err != nil { // if the send fails just set it to failed, it will but automatically // retried - jww.INFO.Printf("Auth Confirm with %s (msgDigest: %s) failed "+ - "to transmit: %+v", partner.ID, cmixMsg.Digest(), err) - return 0, errors.WithMessage(err, "Auth Confirm Failed to transmit") + jww.WARN.Printf("Auth Confirm with %s (msgDigest: %s) failed "+ + "to transmit: %+v, will be handled by critical messages", + partner, format.DigestContents(payload), err) + return 0, nil } em := fmt.Sprintf("Confirm Request with %s (msgDigest: %s) sent on round %d", - partner.ID, cmixMsg.Digest(), round) + partner, format.DigestContents(payload), sentRound) jww.INFO.Print(em) - events.Report(1, "Auth", "SendConfirm", em) - - return round, nil -} - -func addPreimages(partner *id.ID, store *storage.Session) { - // add the preimages - sessionPartner, err := store.E2e().GetPartner(partner) - if err != nil { - jww.FATAL.Panicf("Cannot find %s right after creating: %+v", - partner, err) - } - - // Delete any known pre-existing edges for this partner - existingEdges, _ := store.GetEdge().Get(partner) - for i := range existingEdges { - delete := true - switch existingEdges[i].Type { - case catalog.E2e: - case catalog.Silent: - case catalog.EndFT: - case catalog.GroupRq: - default: - delete = false - } - - if delete { - err = store.GetEdge().Remove(existingEdges[i], partner) - if err != nil { - jww.ERROR.Printf( - "Unable to delete %s edge for %s: %v", - existingEdges[i].Type, partner, err) - } - } - } - - me := store.GetUser().ReceptionID - - // e2e - store.GetEdge().Add(edge.Preimage{ - Data: sessionPartner.GetE2EPreimage(), - Type: catalog.E2e, - Source: partner[:], - }, me) - - // silent (rekey) - store.GetEdge().Add(edge.Preimage{ - Data: sessionPartner.GetSilentPreimage(), - Type: catalog.Silent, - Source: partner[:], - }, me) - - // File transfer end - store.GetEdge().Add(edge.Preimage{ - Data: sessionPartner.GetFileTransferPreimage(), - Type: catalog.EndFT, - Source: partner[:], - }, me) - - // group Request - store.GetEdge().Add(edge.Preimage{ - Data: sessionPartner.GetGroupRequestPreimage(), - Type: catalog.GroupRq, - Source: partner[:], - }, me) + event.Report(1, "Auth", "SendConfirm", em) + return sentRound, nil } diff --git a/auth/fmt.go b/auth/fmt.go index cf38aaed44967d8a825a27451783bf5318038544..6ec925c7efd8be0cbd1b48ff09b1766e0080bd03 100644 --- a/auth/fmt.go +++ b/auth/fmt.go @@ -14,6 +14,7 @@ import ( sidhinterface "gitlab.com/elixxir/client/interfaces/sidh" util "gitlab.com/elixxir/client/storage/utility" "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" ) @@ -250,3 +251,23 @@ func (rf requestFormat) MsgPayloadLen() int { func (rf requestFormat) GetMsgPayload() []byte { return rf.msgPayload } + +//utility functions +func handleBaseFormat(cmixMsg format.Message, grp *cyclic.Group) (baseFormat, + *cyclic.Int, error) { + + baseFmt, err := unmarshalBaseFormat(cmixMsg.GetContents(), + grp.GetP().ByteLen()) + if err != nil && baseFmt == nil { + return baseFormat{}, nil, errors.WithMessage(err, "Failed to"+ + " unmarshal auth") + } + + if !grp.BytesInside(baseFmt.pubkey) { + return baseFormat{}, nil, errors.WithMessage(err, "Received "+ + "auth confirmation public key is not in the e2e cyclic group") + } + partnerPubKey := grp.NewIntFromBytes(baseFmt.pubkey) + + return *baseFmt, partnerPubKey, nil +} diff --git a/auth/manager.go b/auth/manager.go deleted file mode 100644 index 2d817ec301fe4a24f26a41e3b5384ddb43bc3661..0000000000000000000000000000000000000000 --- a/auth/manager.go +++ /dev/null @@ -1,135 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright © 2020 xx network SEZC // -// // -// Use of this source code is governed by a license that can be found in the // -// LICENSE file // -/////////////////////////////////////////////////////////////////////////////// - -package auth - -import ( - "gitlab.com/elixxir/client/auth/store" - "gitlab.com/elixxir/client/e2e" - "gitlab.com/elixxir/client/event" - "gitlab.com/elixxir/client/interfaces" - "gitlab.com/elixxir/client/interfaces/message" - "gitlab.com/elixxir/client/network" - "gitlab.com/elixxir/client/storage" - "gitlab.com/elixxir/client/switchboard" - "gitlab.com/elixxir/crypto/cyclic" - "gitlab.com/elixxir/crypto/fastRNG" - "gitlab.com/xx_network/primitives/id" -) - -type Manager struct { - requestCallbacks *callbackMap - confirmCallbacks *callbackMap - resetCallbacks *callbackMap - - net network.Manager - e2e e2e.Handler - rng *fastRNG.StreamGenerator - - store *store.Store - grp *cyclic.Group - event event.Manager - - registeredIDs map[id.ID]keypair - - replayRequests bool -} - -type keypair struct { - privkey *cyclic.Int - //generated from pubkey on instantiation - pubkey *cyclic.Int -} - -func NewManager(sw interfaces.Switchboard, storage *storage.Session, - net interfaces.NetworkManager, rng *fastRNG.StreamGenerator, - backupTrigger interfaces.TriggerBackup, replayRequests bool) *Manager { - m := &Manager{ - requestCallbacks: newCallbackMap(), - confirmCallbacks: newCallbackMap(), - resetCallbacks: newCallbackMap(), - rawMessages: make(chan message.Receive, 1000), - storage: storage, - net: net, - rng: rng, - backupTrigger: backupTrigger, - replayRequests: replayRequests, - } - - sw.RegisterChannel("Auth", switchboard.AnyUser(), message.Raw, m.rawMessages) - - return m -} - -// Adds a general callback to be used on auth requests. This will be preempted -// by any specific callback -func (m *Manager) AddGeneralRequestCallback(cb interfaces.RequestCallback) { - m.requestCallbacks.AddGeneral(cb) -} - -// Adds a general callback to be used on auth requests. This will not be -// preempted by any specific callback. It is recommended that the specific -// callbacks are used, this is primarily for debugging. -func (m *Manager) AddOverrideRequestCallback(cb interfaces.RequestCallback) { - m.requestCallbacks.AddOverride(cb) -} - -// Adds a specific callback to be used on auth requests. This will preempt a -// general callback, meaning the request will be heard on this callback and not -// the general. Request will still be heard on override callbacks. -func (m *Manager) AddSpecificRequestCallback(id *id.ID, cb interfaces.RequestCallback) { - m.requestCallbacks.AddSpecific(id, cb) -} - -// Removes a specific callback to be used on auth requests. -func (m *Manager) RemoveSpecificRequestCallback(id *id.ID) { - m.requestCallbacks.RemoveSpecific(id) -} - -// Adds a general callback to be used on auth confirms. This will be preempted -// by any specific callback -func (m *Manager) AddGeneralConfirmCallback(cb interfaces.ConfirmCallback) { - m.confirmCallbacks.AddGeneral(cb) -} - -// Adds a general callback to be used on auth confirms. This will not be -// preempted by any specific callback. It is recommended that the specific -// callbacks are used, this is primarily for debugging. -func (m *Manager) AddOverrideConfirmCallback(cb interfaces.ConfirmCallback) { - m.confirmCallbacks.AddOverride(cb) -} - -// Adds a specific callback to be used on auth confirms. This will preempt a -// general callback, meaning the request will be heard on this callback and not -// the general. Request will still be heard on override callbacks. -func (m *Manager) AddSpecificConfirmCallback(id *id.ID, cb interfaces.ConfirmCallback) { - m.confirmCallbacks.AddSpecific(id, cb) -} - -// Removes a specific callback to be used on auth confirm. -func (m *Manager) RemoveSpecificConfirmCallback(id *id.ID) { - m.confirmCallbacks.RemoveSpecific(id) -} - -// Adds a general callback to be used on auth session renegotiations. -func (m *Manager) AddResetNotificationCallback(cb interfaces.ResetNotificationCallback) { - m.resetCallbacks.AddOverride(cb) -} - -// ReplayRequests will iterate through all pending contact requests and resend them -// to the desired contact. -func (m *Manager) ReplayRequests() { - cList := m.storage.Auth().GetAllReceived() - for i := range cList { - c := cList[i] - cbList := m.requestCallbacks.Get(c.ID) - for _, cb := range cbList { - rcb := cb.(interfaces.RequestCallback) - go rcb(c) - } - } -} diff --git a/auth/params.go b/auth/params.go new file mode 100644 index 0000000000000000000000000000000000000000..8832b06d1881b3a6df3cc986996aac9e81012a7e --- /dev/null +++ b/auth/params.go @@ -0,0 +1 @@ +package auth diff --git a/auth/receivedConfirm.go b/auth/receivedConfirm.go new file mode 100644 index 0000000000000000000000000000000000000000..ed6ccdd7654b92705f6e5d4ae82b82f015c6b391 --- /dev/null +++ b/auth/receivedConfirm.go @@ -0,0 +1,119 @@ +package auth + +import ( + "encoding/base64" + "fmt" + jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/client/auth/store" + "gitlab.com/elixxir/client/catalog" + "gitlab.com/elixxir/client/e2e/ratchet/partner/session" + "gitlab.com/elixxir/client/network/historical" + "gitlab.com/elixxir/client/network/identity/receptionID" + "gitlab.com/elixxir/client/network/message" + "gitlab.com/elixxir/crypto/contact" + cAuth "gitlab.com/elixxir/crypto/e2e/auth" + "gitlab.com/elixxir/primitives/fact" + "gitlab.com/elixxir/primitives/format" +) + +type receivedConfirmService struct { + s *State + *store.SentRequest +} + +func (rcs *receivedConfirmService) Process(msg format.Message, + receptionID receptionID.EphemeralIdentity, round historical.Round) { + + state := rcs.s + + //parse the confirm + baseFmt, partnerPubKey, err := handleBaseFormat(msg, state.e2e.GetGroup()) + if err != nil { + em := fmt.Sprintf("Failed to handle auth confirm: %s", err) + jww.WARN.Print(em) + state.event.Report(10, "Auth", "ConfirmError", em) + return + } + + // lookup keypair + kp := state.registeredIDs[*receptionID.Source] + + jww.TRACE.Printf("processing confirm: \n\t MYPUBKEY: %s "+ + "\n\t PARTNERPUBKEY: %s \n\t ECRPAYLOAD: %s \n\t MAC: %s", + kp.pubkey.TextVerbose(16, 0), + partnerPubKey.TextVerbose(16, 0), + base64.StdEncoding.EncodeToString(baseFmt.data), + base64.StdEncoding.EncodeToString(msg.GetMac())) + + // decrypt the payload + success, payload := cAuth.Decrypt(rcs.GetMyPrivKey(), partnerPubKey, + baseFmt.GetEcrPayload(), msg.GetMac(), state.e2e.GetGroup()) + + if !success { + em := fmt.Sprintf("Received auth confirmation failed its mac " + + "check") + jww.WARN.Print(em) + state.event.Report(10, "Auth", "ConfirmError", em) + return + } + + // parse the data + ecrFmt, err := unmarshalEcrFormat(payload) + if err != nil { + em := fmt.Sprintf("Failed to unmarshal auth confirmation's "+ + "encrypted payload: %s", err) + jww.WARN.Print(em) + state.event.Report(10, "Auth", "ConfirmError", em) + return + } + + partnerSIDHPubKey, err := ecrFmt.GetSidhPubKey() + if err != nil { + em := fmt.Sprintf("Could not get auth conf SIDH Pubkey: %s", + err) + jww.WARN.Print(em) + state.event.Report(10, "Auth", "ConfirmError", em) + return + } + + jww.TRACE.Printf("handleConfirm PARTNERSIDHPUBKEY: %v", + partnerSIDHPubKey) + + // check the ownership proof, this verifies the respondent owns the + // initial identity + if !cAuth.VerifyOwnershipProof(kp.privkey, rcs.GetPartnerHistoricalPubKey(), + state.e2e.GetGroup(), ecrFmt.GetOwnership()) { + jww.WARN.Printf("Failed authenticate identity for auth "+ + "confirmation of %s", rcs.GetPartner()) + return + } + + // add the partner + p := session.GetDefaultParams() + _, err = state.e2e.AddPartner(receptionID.Source, rcs.GetPartner(), partnerPubKey, + rcs.GetMyPrivKey(), partnerSIDHPubKey, rcs.GetMySIDHPrivKey(), p, p) + if err != nil { + jww.WARN.Printf("Failed to create channel with partner %s and "+ + "%s : %+v", rcs.GetPartner(), receptionID.Source, err) + } + + //todo: trigger backup + + // remove the service used for notifications of the confirm + confirmFP := rcs.GetFingerprint() + state.net.DeleteService(receptionID.Source, message.Service{ + Identifier: confirmFP[:], + Tag: catalog.Confirm, + }, nil) + + // callbacks + c := contact.Contact{ + ID: rcs.GetPartner().DeepCopy(), + DhPubKey: partnerPubKey.DeepCopy(), + OwnershipProof: ecrFmt.GetOwnership(), + Facts: make([]fact.Fact, 0), + } + if cb, exists := state.confirmCallbacks.Get(receptionID.Source); exists { + cb(c, receptionID, round) + } +} diff --git a/auth/receivedRequest.go b/auth/receivedRequest.go index bb92273031b13c3ef26655e1d7fb21e9d51080a2..327a746ed4b1130e0d95632c526ba01606b306a1 100644 --- a/auth/receivedRequest.go +++ b/auth/receivedRequest.go @@ -6,31 +6,54 @@ import ( "github.com/cloudflare/circl/dh/sidh" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" + "gitlab.com/elixxir/client/auth/store" + "gitlab.com/elixxir/client/e2e/ratchet" "gitlab.com/elixxir/client/network/historical" "gitlab.com/elixxir/client/network/identity/receptionID" + "gitlab.com/elixxir/crypto/contact" cAuth "gitlab.com/elixxir/crypto/e2e/auth" "gitlab.com/elixxir/primitives/fact" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" + "strings" ) +const dummyerr = "dummy error so we dont delete the request" + type receivedRequestService struct { - m *Manager + s *State } func (rrs *receivedRequestService) Process(message format.Message, receptionID receptionID.EphemeralIdentity, round historical.Round) { + state := rrs.s + + // check if the timestamp is before the id was created and therefore + // should be ignored + tid, err := state.net.GetIdentity(receptionID.Source) + if err != nil { + jww.ERROR.Printf("received a request on %s which does not exist, " + + "this should not be possible") + return + } + if tid.Creation.After(round.GetEndTimestamp()) { + jww.INFO.Printf("received a request on %s which was sent before " + + "creation of the identity, dropping because it is likely old " + + "(before a reset from backup") + return + } + //decode the outer format baseFmt, partnerPubKey, err := handleBaseFormat( - message, rrs.m.grp) + message, state.e2e.GetGroup()) if err != nil { jww.WARN.Printf("Failed to handle auth request: %s", err) return } //lookup the keypair - kp := rrs.m.registeredIDs[*receptionID.Source] + kp := state.registeredIDs[*receptionID.Source] jww.TRACE.Printf("processing requests: \n\t MYPUBKEY: %s "+ "\n\t PARTNERPUBKEY: %s \n\t ECRPAYLOAD: %s \n\t MAC: %s", @@ -41,7 +64,7 @@ func (rrs *receivedRequestService) Process(message format.Message, //Attempt to decrypt the payload success, payload := cAuth.Decrypt(kp.privkey, partnerPubKey, - baseFmt.GetEcrPayload(), message.GetMac(), rrs.m.grp) + baseFmt.GetEcrPayload(), message.GetMac(), state.e2e.GetGroup()) if !success { jww.WARN.Printf("Received auth request of %s failed its mac "+ @@ -50,60 +73,226 @@ func (rrs *receivedRequestService) Process(message format.Message, } //extract data from the decrypted payload - partnerID, partnerSIDHPubKey, facts, err := processDecryptedMessage(payload) + partnerID, partnerSIDHPubKey, facts, ownershipProof, err := + processDecryptedMessage(payload) if err != nil { jww.WARN.Printf("Failed to decode the auth request: %+v", err) return } - em := fmt.Sprintf("Received AuthRequest from %s,"+ - " msgDigest: %s", partnerID, format.DigestContents(message.GetContents())) - jww.INFO.Print(em) - rrs.m.event.Report(1, "Auth", "RequestReceived", em) + //create the contact, note that no facts are sent in the payload + c := contact.Contact{ + ID: partnerID.DeepCopy(), + DhPubKey: partnerPubKey.DeepCopy(), + OwnershipProof: copySlice(ownershipProof), + Facts: facts, + } - // check the uniqueness of the request. Requests can be duplicated, so we must - // verify this is is not a duplicate, and drop if it is fp := cAuth.CreateNegotiationFingerprint(partnerPubKey, partnerSIDHPubKey) - newFP, latest := rrs.m.store.CheckIfNegotiationIsNew(partnerID, + em := fmt.Sprintf("Received AuthRequest from %s,"+ + " msgDigest: %s, FP: %s", partnerID, + format.DigestContents(message.GetContents()), + base64.StdEncoding.EncodeToString(fp)) + jww.INFO.Print(em) + state.event.Report(1, "Auth", "RequestReceived", em) + + // check the uniqueness of the request. Requests can be duplicated, so we + // must verify this is is not a duplicate, and drop if it is + newFP, position := state.store.CheckIfNegotiationIsNew(partnerID, receptionID.Source, fp) + if !newFP { + // if its the newest, resend the confirm + if position == 0 { + jww.INFO.Printf("Not new request received from %s to %s "+ + "with fp %s at position %d, resending confirm", partnerID, + receptionID.Source, base64.StdEncoding.EncodeToString(fp), + position) + + // check if we already accepted, if we did, resend the confirm if + // we can load it + if _, err = state.e2e.GetPartner(partnerID, receptionID.Source); err != nil { + //attempt to load the confirm, if we can, resend it + confirmPayload, mac, keyfp, err := + state.store.LoadConfirmation(partnerID, receptionID.Source) + if err != nil { + jww.ERROR.Printf("Could not reconfirm a duplicate "+ + "request of an accepted confirm from %s to %s because "+ + "the confirm could not be loaded: %+v", partnerID, + receptionID.Source, err) + } + // resend the confirm. It sends as a critical message, so errors + // do not need to be handled + _, _ = sendAuthConfirm(state.net, partnerID, receptionID.Source, + keyfp, confirmPayload, mac, state.event) + } else if state.replayRequests { + //if we did not already accept, auto replay the request + if cb, exist := state.requestCallbacks.Get(receptionID.Source); exist { + cb(c, receptionID, round) + } + } + //if not confirm, and params.replay requests is true, we need to replay + } else { + jww.INFO.Printf("Not new request received from %s to %s "+ + "with fp %s at position %d, dropping", partnerID, + receptionID.Source, base64.StdEncoding.EncodeToString(fp), + position) + } + return + } + + reset := false + // check if we have a relationship, given this is a new request, if we have + // a relationship, this must be a reset, which which case we delete all + // state and then continue like a new request + // delete only deletes if the partner is present, so we can just call delete + // instead of checking if it exists and then calling delete, and check the + // error to see if it did or didnt exist + // Note: due to the newFP handling above, this can ONLY run in the event of + // a reset or when the partner doesnt exist, so it is safe + if err = state.e2e.DeletePartner(partnerID, receptionID.Source); err != nil { + if !strings.Contains(err.Error(), ratchet.NoPartnerErrorStr) { + jww.FATAL.Panicf("Failed to do actual partner deletion: %+v", err) + } + } else { + reset = true + _ = state.store.DeleteConfirmation(partnerID, receptionID.Source) + _ = state.store.DeleteSentRequest(partnerID, receptionID.Source) + } + + // if a new, unique request is received when one already exists, delete the + // old one and process the new one + if err = state.store.DeleteReceivedRequest(partnerID, receptionID.Source); err != nil { + if !strings.Contains(err.Error(), store.NoRequestFound) { + jww.FATAL.Panicf("Failed to delete old received request: %+v", + err) + } + } + + // if a sent request already exists, that means we requested at the same + // time they did. We need to auto-confirm if we are randomly selected + // (SIDH keys have polarity, so both sent keys cannot be used together) + autoConfirm := false + bail := false + err = state.store.HandleSentRequest(partnerID, receptionID.Source, + func(request *store.SentRequest) error { + + //if this code is running, then we know we sent a request and can + //auto accept + //This runner will auto delete the sent request if successful + + //verify ownership proof + if !cAuth.VerifyOwnershipProof(kp.pubkey, partnerPubKey, + state.e2e.GetGroup(), ownershipProof) { + jww.WARN.Printf("Invalid ownership proof from %s to %s "+ + "received, discarding msdDigest: %s, fp: %s", + partnerID, receptionID.Source, + format.DigestContents(message.GetContents()), + base64.StdEncoding.EncodeToString(fp)) + } + + if !iShouldResend(partnerID, receptionID.Source) { + // return an error so the store layer does not delete the request + // because the other side will confirm it + bail = true + return errors.Errorf(dummyerr) + } + + jww.INFO.Printf("Received AuthRequest from %s to %s,"+ + " msgDigest: %s, fp: %s which has been requested, auto-confirming", + partnerID, receptionID.Source, + format.DigestContents(message.GetContents()), + base64.StdEncoding.EncodeToString(fp)) + return nil + }) + if bail { + jww.INFO.Printf("Received AuthRequest from %s to %s,"+ + " msgDigest: %s, fp: %s which has been requested, not auto-confirming, "+ + " is other's responsibility", + partnerID, receptionID.Source, + format.DigestContents(message.GetContents()), + base64.StdEncoding.EncodeToString(fp)) + return + } + //set the autoconfirm + autoConfirm = err == nil + + // warning: the client will never be notified of the channel creation if a + // crash occurs after the store but before the conclusion of the callback + //create the auth storage + if err = state.store.AddReceived(receptionID.Source, c, partnerSIDHPubKey); err != nil { + em := fmt.Sprintf("failed to store contact Auth "+ + "Request: %s", err) + jww.WARN.Print(em) + state.event.Report(10, "Auth", "RequestError", em) + return + } + + //autoconfirm if we should + if autoConfirm || reset { + _, _ = state.confirmRequestAuth(c, receptionID.Source) + //handle callbacks + if autoConfirm { + if cb, exist := state.confirmCallbacks.Get(receptionID.Source); exist { + cb(c, receptionID, round) + } + } else if reset { + if cb, exist := state.requestCallbacks.Get(receptionID.Source); exist { + cb(c, receptionID, round) + } + } + } else { + //otherwise call callbacks + if cb, exist := state.requestCallbacks.Get(receptionID.Source); exist { + cb(c, receptionID, round) + } + } } func processDecryptedMessage(b []byte) (*id.ID, *sidh.PublicKey, fact.FactList, - error) { + []byte, error) { //decode the ecr format ecrFmt, err := unmarshalEcrFormat(b) if err != nil { - return nil, nil, nil, errors.WithMessage(err, "Failed to "+ + return nil, nil, nil, nil, errors.WithMessage(err, "Failed to "+ "unmarshal auth request's encrypted payload") } partnerSIDHPubKey, err := ecrFmt.GetSidhPubKey() if err != nil { - return nil, nil, nil, errors.WithMessage(err, "Could not "+ + return nil, nil, nil, nil, errors.WithMessage(err, "Could not "+ "unmarshal partner SIDH Pubkey") } //decode the request format requestFmt, err := newRequestFormat(ecrFmt) if err != nil { - return nil, nil, nil, errors.WithMessage(err, "Failed to "+ + return nil, nil, nil, nil, errors.WithMessage(err, "Failed to "+ "unmarshal auth request's internal payload") } partnerID, err := requestFmt.GetID() if err != nil { - return nil, nil, nil, errors.WithMessage(err, "Failed to "+ + return nil, nil, nil, nil, errors.WithMessage(err, "Failed to "+ "unmarshal auth request's sender ID") } facts, _, err := fact.UnstringifyFactList( string(requestFmt.msgPayload)) if err != nil { - return nil, nil, nil, errors.WithMessage(err, "Failed to "+ + return nil, nil, nil, nil, errors.WithMessage(err, "Failed to "+ "unmarshal auth request's facts") } - return partnerID, partnerSIDHPubKey, facts, nil + return partnerID, partnerSIDHPubKey, facts, ecrFmt.GetOwnership(), nil +} + +func iShouldResend(partner, me *id.ID) bool { + myBytes := me.Bytes() + theirBytes := partner.Bytes() + i := 0 + for ; myBytes[i] == theirBytes[i] && i < len(myBytes); i++ { + } + return myBytes[i] < theirBytes[i] } diff --git a/auth/request.go b/auth/request.go index daaa3f071e334a08aa3ab8545000f6dcb089a93d..cf34b7c0830577a031a7214a493a777a33b0a8b1 100644 --- a/auth/request.go +++ b/auth/request.go @@ -9,67 +9,59 @@ package auth import ( "fmt" - auth2 "gitlab.com/elixxir/client/auth/store" - "gitlab.com/elixxir/client/catalog" - e2e2 "gitlab.com/elixxir/client/e2e/ratchet" - "gitlab.com/elixxir/client/network" - "gitlab.com/elixxir/client/network/message" - "gitlab.com/elixxir/primitives/format" - "gitlab.com/xx_network/crypto/signature/rsa" - "io" - "strings" - "github.com/cloudflare/circl/dh/sidh" "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" - "gitlab.com/elixxir/client/interfaces" - "gitlab.com/elixxir/client/interfaces/params" - "gitlab.com/elixxir/client/interfaces/preimage" - "gitlab.com/elixxir/client/storage" - "gitlab.com/elixxir/client/storage/edge" + "gitlab.com/elixxir/client/catalog" + "gitlab.com/elixxir/client/e2e/ratchet" + "gitlab.com/elixxir/client/network" + "gitlab.com/elixxir/client/network/message" util "gitlab.com/elixxir/client/storage/utility" "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/xx_network/primitives/id" + "io" + "strings" ) const terminator = ";" -func (m *Manager) RequestAuth(partner, me contact.Contact, +func (s *State) RequestAuth(partner, me contact.Contact, originDHPrivKey *cyclic.Int) (id.Round, error) { // check that an authenticated channel does not already exist - if _, err := m.e2e.GetPartner(partner.ID, me.ID); err == nil || - !strings.Contains(err.Error(), e2e2.NoPartnerErrorStr) { + if _, err := s.e2e.GetPartner(partner.ID, me.ID); err == nil || + !strings.Contains(err.Error(), ratchet.NoPartnerErrorStr) { return 0, errors.Errorf("Authenticated channel already " + "established with partner") } - return m.requestAuth(partner, me, originDHPrivKey) + return s.requestAuth(partner, me, originDHPrivKey) } // requestAuth internal helper -func (m *Manager) requestAuth(partner, me contact.Contact, +func (s *State) requestAuth(partner, me contact.Contact, originDHPrivKey *cyclic.Int) (id.Round, error) { //do key generation - rng := m.rng.GetStream() + rng := s.rng.GetStream() defer rng.Close() - dhPriv, dhPub := genDHKeys(m.grp, rng) + dhPriv, dhPub := genDHKeys(s.e2e.GetGroup(), rng) sidhPriv, sidhPub := util.GenerateSIDHKeyPair( sidh.KeyVariantSidhA, rng) ownership := cAuth.MakeOwnershipProof(originDHPrivKey, partner.DhPubKey, - m.grp) + s.e2e.GetGroup()) confirmFp := cAuth.MakeOwnershipProofFP(ownership) // Add the sent request and use the return to build the send. This will // replace the send with an old one if one was in process, wasting the key // generation above. This is considered a reasonable loss due to the increase // in code simplicity of this approach - sr, err := m.store.AddSent(partner.ID, me.ID, partner.DhPubKey, dhPriv, dhPub, + sr, err := s.store.AddSent(partner.ID, me.ID, partner.DhPubKey, dhPriv, dhPub, sidhPriv, sidhPub, confirmFp) if err != nil { if sr == nil { @@ -91,14 +83,24 @@ func (m *Manager) requestAuth(partner, me contact.Contact, // Create the request packet. request, mac, err := createRequestAuth(partner.ID, msgPayload, ownership, dhPriv, dhPub, partner.DhPubKey, sidhPub, - m.grp, m.net.GetMaxMessageLength()) + s.e2e.GetGroup(), s.net.GetMaxMessageLength()) if err != nil { return 0, err } contents := request.Marshal() - //todo-register correct service - m.net.AddService(me.ID, message.Service{ + //register the confirm fingerprint to pick up confirm + err = s.net.AddFingerprint(me.ID, confirmFp, &receivedConfirmService{ + s: s, + SentRequest: sr, + }) + if err != nil { + return 0, errors.Errorf("Failed to register fingperint request "+ + "to %s from %s, bailing request", partner.ID, me) + } + + //register service for notification on confirmation + s.net.AddService(me.ID, message.Service{ Identifier: confirmFp[:], Tag: catalog.Confirm, Metadata: partner.ID[:], @@ -112,12 +114,12 @@ func (m *Manager) requestAuth(partner, me contact.Contact, p := network.GetDefaultCMIXParams() p.DebugTag = "auth.Request" - s := message.Service{ + svc := message.Service{ Identifier: partner.ID.Marshal(), Tag: catalog.Default, Metadata: nil, } - round, _, err := m.net.SendCMIX(partner.ID, requestfp, s, contents, mac, p) + round, _, err := s.net.SendCMIX(partner.ID, requestfp, svc, contents, mac, p) if err != nil { // if the send fails just set it to failed, it will // but automatically retried @@ -129,7 +131,7 @@ func (m *Manager) requestAuth(partner, me contact.Contact, em := fmt.Sprintf("Auth Request with %s (msgDigest: %s) sent"+ " on round %d", partner.ID, format.DigestContents(contents), round) jww.INFO.Print(em) - m.event.Report(1, "Auth", "RequestSent", em) + s.event.Report(1, "Auth", "RequestSent", em) return round, nil } diff --git a/auth/reset.go b/auth/reset.go index 2a28016164b72f03816cbb6cdeba25686b6a1d8e..c257a274b7e3bc1343452b0cb4a7d7da73195a44 100644 --- a/auth/reset.go +++ b/auth/reset.go @@ -2,31 +2,23 @@ package auth import ( jww "github.com/spf13/jwalterweatherman" - auth2 "gitlab.com/elixxir/client/auth/store" - "gitlab.com/elixxir/client/interfaces" - "gitlab.com/elixxir/client/storage" "gitlab.com/elixxir/crypto/contact" "gitlab.com/xx_network/primitives/id" - "io" ) -func (m *Manager) ResetSession(partner, me contact.Contact, rng io.Reader) (id.Round, error) { +func (s *State) ResetSession(partner contact.Contact, me *id.ID) (id.Round, error) { // Delete authenticated channel if it exists. - if err := storage.E2e().DeletePartner(partner.ID); err != nil { + if err := s.e2e.DeletePartner(partner.ID, me); err != nil { jww.WARN.Printf("Unable to delete partner when "+ "resetting session: %+v", err) - } else { - // Delete any stored sent/received requests - storage.Auth().Delete(partner.ID) } - rqType, _, _, err := storage.Auth().GetRequest(partner.ID) - if err == nil && rqType == auth2.Sent { - return 0, errors.New("Cannot reset a session after " + - "sending request, caller must resend request instead") - } + //clean any data which is present + _ = s.store.DeleteConfirmation(partner.ID, me) + _ = s.store.DeleteSentRequest(partner.ID, me) + _ = s.store.DeleteReceivedRequest(partner.ID, me) // Try to initiate a clean session request - return requestAuth(partner, me, rng, true, storage, net) + return s.confirmRequestAuth(partner, me) } diff --git a/auth/state.go b/auth/state.go new file mode 100644 index 0000000000000000000000000000000000000000..6cb7f5ebc1453d5cc6a7acb8b5bb4475e768f546 --- /dev/null +++ b/auth/state.go @@ -0,0 +1,79 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2020 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// + +package auth + +import ( + "gitlab.com/elixxir/client/auth/store" + "gitlab.com/elixxir/client/e2e" + "gitlab.com/elixxir/client/event" + "gitlab.com/elixxir/client/interfaces" + "gitlab.com/elixxir/client/interfaces/message" + "gitlab.com/elixxir/client/network" + "gitlab.com/elixxir/client/storage" + "gitlab.com/elixxir/client/switchboard" + "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/crypto/fastRNG" + "gitlab.com/xx_network/primitives/id" +) + +type State struct { + requestCallbacks *callbackMap + confirmCallbacks *callbackMap + resetCallbacks *callbackMap + + net network.Manager + e2e e2e.Handler + rng *fastRNG.StreamGenerator + + store *store.Store + event event.Manager + + registeredIDs map[id.ID]keypair + + replayRequests bool +} + +type keypair struct { + privkey *cyclic.Int + //generated from pubkey on instantiation + pubkey *cyclic.Int +} + +func NewManager(sw interfaces.Switchboard, storage *storage.Session, + net interfaces.NetworkManager, rng *fastRNG.StreamGenerator, + backupTrigger interfaces.TriggerBackup, replayRequests bool) *State { + m := &State{ + requestCallbacks: newCallbackMap(), + confirmCallbacks: newCallbackMap(), + resetCallbacks: newCallbackMap(), + rawMessages: make(chan message.Receive, 1000), + storage: storage, + net: net, + rng: rng, + backupTrigger: backupTrigger, + replayRequests: replayRequests, + } + + sw.RegisterChannel("Auth", switchboard.AnyUser(), message.Raw, m.rawMessages) + + return m +} + +// ReplayRequests will iterate through all pending contact requests and resend them +// to the desired contact. +func (s *State) ReplayRequests() { + cList := s.storage.Auth().GetAllReceived() + for i := range cList { + c := cList[i] + cbList := s.requestCallbacks.Get(c.ID) + for _, cb := range cbList { + rcb := cb.(interfaces.RequestCallback) + go rcb(c) + } + } +} diff --git a/auth/manager_test.go b/auth/state_test.go similarity index 99% rename from auth/manager_test.go rename to auth/state_test.go index 2e384f83ffa6829624b07ab35ac2ef7b259b0e34..d023abfad0542ce7374ef57f796e0dd5d831d45b 100644 --- a/auth/manager_test.go +++ b/auth/state_test.go @@ -31,7 +31,7 @@ func TestManager_ReplayRequests(t *testing.T) { numReceived := 10 // Construct barebones manager - m := Manager{ + m := State{ requestCallbacks: newCallbackMap(), storage: s, replayRequests: true, diff --git a/auth/store/confirmation.go b/auth/store/confirmation.go index a321c354c5258f7e0613fd4d4cf67429672b9a88..ba61ec4efedc746c79f185e1b1d55e37571d409a 100644 --- a/auth/store/confirmation.go +++ b/auth/store/confirmation.go @@ -9,7 +9,9 @@ package store import ( "encoding/base64" + "encoding/json" "gitlab.com/elixxir/client/storage/versioned" + "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" ) @@ -19,43 +21,69 @@ const ( currentConfirmationVersion = 0 ) +type storedConfirm struct { + Payload []byte + Mac []byte + Keyfp []byte +} + // StoreConfirmation saves the confirmation to storage for the given partner and // fingerprint. -func (s *Store) StoreConfirmation( - partner *id.ID, fingerprint, confirmation []byte) error { +func (s *Store) StoreConfirmation(partner *id.ID, me *id.ID, + confirmationPayload, mac []byte, fp format.Fingerprint) error { + confirm := storedConfirm{ + Payload: confirmationPayload, + Mac: mac, + Keyfp: fp[:], + } + + confirmBytes, err := json.Marshal(&confirm) + if err != nil { + return err + } + obj := &versioned.Object{ Version: currentConfirmationVersion, Timestamp: netTime.Now(), - Data: confirmation, + Data: confirmBytes, } - return s.kv.Set(makeConfirmationKey(partner, fingerprint), + return s.kv.Set(makeConfirmationKey(partner, me), currentConfirmationVersion, obj) } // LoadConfirmation loads the confirmation for the given partner and fingerprint // from storage. -func (s *Store) LoadConfirmation(partner *id.ID, fingerprint []byte) ( - []byte, error) { +func (s *Store) LoadConfirmation(partner, me *id.ID) ( + []byte, []byte, format.Fingerprint, error) { obj, err := s.kv.Get( - makeConfirmationKey(partner, fingerprint), currentConfirmationVersion) + makeConfirmationKey(partner, me), currentConfirmationVersion) if err != nil { - return nil, err + return nil, nil, format.Fingerprint{}, err } - return obj.Data, nil + confirm := storedConfirm{} + if err = json.Unmarshal(obj.Data, &confirm); err != nil { + return nil, nil, format.Fingerprint{}, err + } + + fp := format.Fingerprint{} + copy(fp[:], confirm.Keyfp) + + return confirm.Payload, confirm.Mac, fp, nil } -// deleteConfirmation deletes the confirmation for the given partner and +// DeleteConfirmation deletes the confirmation for the given partner and // fingerprint from storage. -func (s *Store) deleteConfirmation(partner *id.ID, fingerprint []byte) error { +func (s *Store) DeleteConfirmation(partner, me *id.ID) error { return s.kv.Delete( - makeConfirmationKey(partner, fingerprint), currentConfirmationVersion) + makeConfirmationKey(partner, me), currentConfirmationVersion) } // makeConfirmationKey generates the key used to load and store confirmations // for the partner and fingerprint. -func makeConfirmationKey(partner *id.ID, fingerprint []byte) string { +func makeConfirmationKey(partner, me *id.ID) string { return confirmationKeyPrefix + base64.StdEncoding.EncodeToString( - partner.Marshal()) + "/" + base64.StdEncoding.EncodeToString(fingerprint) + partner.Marshal()) + base64.StdEncoding.EncodeToString( + me.Marshal()) } diff --git a/auth/store/confirmation_test.go b/auth/store/confirmation_test.go index 6e53a62958bad90184be184d9ab10ee543fe82fe..b33ec582f2242fc963f2b67ca76385e463345575 100644 --- a/auth/store/confirmation_test.go +++ b/auth/store/confirmation_test.go @@ -78,7 +78,7 @@ func TestStore_StoreConfirmation_LoadConfirmation(t *testing.T) { } } -// Tests that Store.deleteConfirmation deletes the correct confirmation from +// Tests that Store.DeleteConfirmation deletes the correct confirmation from // storage and that it cannot be loaded from storage. func TestStore_deleteConfirmation(t *testing.T) { s := &Store{kv: versioned.NewKV(make(ekv.Memstore))} @@ -120,9 +120,9 @@ func TestStore_deleteConfirmation(t *testing.T) { } for i, val := range testValues { - err := s.deleteConfirmation(val.partner, val.fingerprint) + err := s.DeleteConfirmation(val.partner, val.fingerprint) if err != nil { - t.Errorf("deleteConfirmation returned an error (%d): %+v", i, err) + t.Errorf("DeleteConfirmation returned an error (%d): %+v", i, err) } loadedConfirmation, err := s.LoadConfirmation(val.partner, val.fingerprint) diff --git a/auth/store/deletion.go b/auth/store/deletion.go index 140a9940c8aefd9f97fd04afd0319a544ebdd636..1eff026fbbe940b7c2f90a5a95dc5059ae8c8bb9 100644 --- a/auth/store/deletion.go +++ b/auth/store/deletion.go @@ -7,6 +7,8 @@ import ( "gitlab.com/xx_network/primitives/id" ) +const NoRequestFound = "no request found" + // DeleteAllRequests clears the request map and all associated storage objects // containing request data. func (s *Store) DeleteAllRequests() error { @@ -74,6 +76,59 @@ func (s *Store) DeleteSentRequests() error { return nil } +// DeleteReceivedRequest deletes the received request for the given partnerID +// pair. +func (s *Store) DeleteReceivedRequest(partner, me *id.ID) error { + + aid := makeAuthIdentity(partner, me) + s.mux.Lock() + rr, exist := s.receivedByID[aid] + s.mux.Unlock() + + if !exist { + return errors.New(NoRequestFound) + } + + rr.mux.Lock() + s.mux.Lock() + _, exist = s.receivedByID[aid] + delete(s.receivedByID, aid) + rr.mux.Unlock() + s.mux.Unlock() + + if !exist { + return errors.New(NoRequestFound) + } + + return nil +} + +// DeleteSentRequest deletes the sent request for the given partnerID pair. +func (s *Store) DeleteSentRequest(partner, me *id.ID) error { + + aid := makeAuthIdentity(partner, me) + s.mux.Lock() + sr, exist := s.sentByID[aid] + s.mux.Unlock() + + if !exist { + return errors.New(NoRequestFound) + } + + sr.mux.Lock() + s.mux.Lock() + _, exist = s.sentByID[aid] + delete(s.receivedByID, aid) + s.mux.Unlock() + sr.mux.Unlock() + + if !exist { + return errors.New(NoRequestFound) + } + + return nil +} + // DeleteReceiveRequests deletes all Receive receivedByID from Store. func (s *Store) DeleteReceiveRequests() error { s.mux.Lock() diff --git a/auth/store/previousNegotiations.go b/auth/store/previousNegotiations.go index 80db8cab9fe42d37116af2c4a35311e1484dfc95..5eb1cb1ec1bc71245aef9271eec5101703c5428e 100644 --- a/auth/store/previousNegotiations.go +++ b/auth/store/previousNegotiations.go @@ -31,10 +31,11 @@ const ( // If the partner does not exist, it will add it and the new fingerprint and // return newFingerprint = true. // If the partner exists and the fingerprint does not exist, add it adds it as -// the latest fingerprint and returns newFingerprint = true, latest = true +// the latest fingerprint and returns newFingerprint = true, // If the partner exists and the fingerprint exists, return -// newFingerprint = false, latest = false or latest = true if it is the last one -// in the list. +// newFingerprint = false +// in all cases it will return the position of the fingerprint, with the newest +// always at position 0 func (s *Store) CheckIfNegotiationIsNew(partner, myID *id.ID, negotiationFingerprint []byte) ( newFingerprint bool, position uint) { s.mux.Lock() @@ -62,8 +63,7 @@ func (s *Store) CheckIfNegotiationIsNew(partner, myID *id.ID, negotiationFingerp } newFingerprint = true - latest = true - + position = 0 return } @@ -81,7 +81,8 @@ func (s *Store) CheckIfNegotiationIsNew(partner, myID *id.ID, negotiationFingerp newFingerprint = false // Latest = true if it is the last fingerprint in the list - latest = i == len(fingerprints)-1 + lastPost := len(fingerprints) - 1 + position = uint(lastPost - i) return } @@ -97,7 +98,7 @@ func (s *Store) CheckIfNegotiationIsNew(partner, myID *id.ID, negotiationFingerp } newFingerprint = true - latest = true + position = 0 return } diff --git a/bindings/ud.go b/bindings/ud.go index df34f572de41569a8c2969c24c9fc24b869348a0..9ca14b91815e2ccf92a8037ebbd23ef54a355cb3 100644 --- a/bindings/ud.go +++ b/bindings/ud.go @@ -35,12 +35,12 @@ type UserDiscovery struct { func NewUserDiscovery(client *Client) (*UserDiscovery, error) { single, err := client.getSingle() if err != nil { - return nil, errors.WithMessage(err, "Failed to create User Discovery Manager") + return nil, errors.WithMessage(err, "Failed to create User Discovery State") } m, err := ud.NewManager(&client.api, single) if err != nil { - return nil, errors.WithMessage(err, "Failed to create User Discovery Manager") + return nil, errors.WithMessage(err, "Failed to create User Discovery State") } else { return &UserDiscovery{ud: m}, nil } @@ -335,7 +335,7 @@ func (ud *UserDiscovery) SetAlternativeUserDiscovery(address, cert, contactFile } // UnsetAlternativeUserDiscovery clears out the information from -// the Manager object. +// the State object. func (ud *UserDiscovery) UnsetAlternativeUserDiscovery() error { return ud.ud.UnsetAlternativeUserDiscovery() } diff --git a/dummy/send_test.go b/dummy/send_test.go index 6a5a91feff0c152b70982e60e769aae53c37813e..ba299018a2b0d117d1037bc50b66ecf99f3c6aa3 100644 --- a/dummy/send_test.go +++ b/dummy/send_test.go @@ -19,7 +19,7 @@ import ( "time" ) -// Tests that Manager.sendThread sends multiple sets of messages. +// Tests that State.sendThread sends multiple sets of messages. func TestManager_sendThread(t *testing.T) { m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t) @@ -86,7 +86,7 @@ func TestManager_sendThread(t *testing.T) { } -// Tests that Manager.sendMessages sends all the messages with the correct +// Tests that State.sendMessages sends all the messages with the correct // recipient. func TestManager_sendMessages(t *testing.T) { m := newTestManager(100, 0, 0, false, t) @@ -135,7 +135,7 @@ func TestManager_sendMessages(t *testing.T) { } } -// Tests that Manager.newRandomMessages creates a non-empty map of messages and +// Tests that State.newRandomMessages creates a non-empty map of messages and // that each message is unique. func TestManager_newRandomMessages(t *testing.T) { m := newTestManager(10, 0, 0, false, t) @@ -161,7 +161,7 @@ func TestManager_newRandomMessages(t *testing.T) { } } -// Tests that Manager.newRandomCmixMessage generates a cMix message with +// Tests that State.newRandomCmixMessage generates a cMix message with // populated contents, fingerprint, and MAC. func TestManager_newRandomCmixMessage(t *testing.T) { m := newTestManager(0, 0, 0, false, t) diff --git a/dummy/utils_test.go b/dummy/utils_test.go index 8a0b0ab9786b7f527fb1fd767fe3d2d6c2d6640d..12af098f4046497b493c2fc7b3a06f383883706b 100644 --- a/dummy/utils_test.go +++ b/dummy/utils_test.go @@ -65,7 +65,7 @@ func newTestManager(maxNumMessages int, avgSendDelta, randomRange time.Duration, } //////////////////////////////////////////////////////////////////////////////// -// Test Network Manager // +// Test Network State // //////////////////////////////////////////////////////////////////////////////// // testNetworkManager is a test implementation of NetworkManager interface. diff --git a/e2e/ratchet/partner/manager.go b/e2e/ratchet/partner/manager.go index 9bded0aa5856f4f9b7482c66e0096f1074f4ccca..c0a4c153ac37c8fb0a7aa94dbf4d88b7bcac98d0 100644 --- a/e2e/ratchet/partner/manager.go +++ b/e2e/ratchet/partner/manager.go @@ -25,7 +25,7 @@ import ( "golang.org/x/crypto/blake2b" ) -const managerPrefix = "Manager{partner:%s}" +const managerPrefix = "State{partner:%s}" const originMyPrivKeyKey = "originMyPrivKey" const originPartnerPubKey = "originPartnerPubKey" diff --git a/e2e/ratchet/partner/manager_test.go b/e2e/ratchet/partner/manager_test.go index 776f48f707a3a190cb7be490e54245ea6edb5efa..797aca1d46b29be41f07283f26abe84cb59657ee 100644 --- a/e2e/ratchet/partner/manager_test.go +++ b/e2e/ratchet/partner/manager_test.go @@ -39,7 +39,7 @@ func Test_newManager(t *testing.T) { // Check if the new relationship matches the expected if !managersEqual(expectedM, m, t) { - t.Errorf("newManager() did not produce the expected Manager."+ + t.Errorf("newManager() did not produce the expected State."+ "\n\texpected: %+v\n\treceived: %+v", expectedM, m) } } @@ -58,7 +58,7 @@ func TestLoadManager(t *testing.T) { // Check if the loaded relationship matches the expected if !managersEqual(expectedM, m, t) { - t.Errorf("LoadManager() did not produce the expected Manager."+ + t.Errorf("LoadManager() did not produce the expected State."+ "\n\texpected: %+v\n\treceived: %+v", expectedM, m) } } @@ -166,7 +166,7 @@ func TestManager_NewSendSession(t *testing.T) { } } -//Tests happy path of Manager.GetKeyForSending. +//Tests happy path of State.GetKeyForSending. func TestManager_GetKeyForSending(t *testing.T) { // Set up test values m, _ := newTestManager(t) @@ -213,7 +213,7 @@ func TestManager_GetKeyForSending(t *testing.T) { } } -// Tests that Manager.GetKeyForSending returns an error for invalid SendType. +// Tests that State.GetKeyForSending returns an error for invalid SendType. func TestManager_GetKeyForSending_Error(t *testing.T) { // Set up test values m, _ := newTestManager(t) diff --git a/e2e/ratchet/partner/session/session.go b/e2e/ratchet/partner/session/session.go index a62cf91618ce7706b0838b7ec5c0ff6d816da5a0..dcb72b84ad1da1f31a3d890c36a7d6bd068ab4ab 100644 --- a/e2e/ratchet/partner/session/session.go +++ b/e2e/ratchet/partner/session/session.go @@ -387,7 +387,7 @@ func (s *Session) Status() Status { // Moving from Unconfirmed to Sending and from Confirmed to NewSessionTriggered // is handled by Session.TriggerNegotiation() which is called by the -// Manager as part of Manager.TriggerNegotiations() and will be rejected +// State as part of State.TriggerNegotiations() and will be rejected // from this function var legalStateChanges = [][]bool{ diff --git a/e2e/ratchet/partner/session/session_test.go b/e2e/ratchet/partner/session/session_test.go index c22fdc582fcebf1a29b021bdafc6ed8b5cebd127..049d4ecea617c8932bfc50a331259caae3325499 100644 --- a/e2e/ratchet/partner/session/session_test.go +++ b/e2e/ratchet/partner/session/session_test.go @@ -157,7 +157,7 @@ func TestSession_Serialization(t *testing.T) { sDeserialized := &Session{ //relationship: &ratchet.relationship{ - // manager: &partner.Manager{ctx: ctx}, + // manager: &partner.State{ctx: ctx}, //}, grp: s.grp, kv: s.kv, diff --git a/e2e/ratchet/partner/utils_test.go b/e2e/ratchet/partner/utils_test.go index 70f056f31d4fe12951b738bd459af051d507f2cc..3667f4d7e67de1a6bb18e46b88eab53a46c4ff8e 100644 --- a/e2e/ratchet/partner/utils_test.go +++ b/e2e/ratchet/partner/utils_test.go @@ -89,31 +89,31 @@ func newTestManager(t *testing.T) (*Manager, *versioned.KV) { func managersEqual(expected, received *Manager, t *testing.T) bool { equal := true if !reflect.DeepEqual(expected.cyHandler, received.cyHandler) { - t.Errorf("Did not Receive expected Manager.ctx."+ + t.Errorf("Did not Receive expected State.ctx."+ "\n\texpected: %+v\n\treceived: %+v", expected.cyHandler, received.cyHandler) equal = false } if !reflect.DeepEqual(expected.kv, received.kv) { - t.Errorf("Did not Receive expected Manager.kv."+ + t.Errorf("Did not Receive expected State.kv."+ "\n\texpected: %+v\n\treceived: %+v", expected.kv, received.kv) equal = false } if !expected.partner.Cmp(received.partner) { - t.Errorf("Did not Receive expected Manager.partner."+ + t.Errorf("Did not Receive expected State.partner."+ "\n\texpected: %+v\n\treceived: %+v", expected.partner, received.partner) equal = false } if !relationshipsEqual(expected.receive, received.receive) { - t.Errorf("Did not Receive expected Manager.Receive."+ + t.Errorf("Did not Receive expected State.Receive."+ "\n\texpected: %+v\n\treceived: %+v", expected.receive, received.receive) equal = false } if !relationshipsEqual(expected.send, received.send) { - t.Errorf("Did not Receive expected Manager.Send."+ + t.Errorf("Did not Receive expected State.Send."+ "\n\texpected: %+v\n\treceived: %+v", expected.send, received.send) equal = false diff --git a/e2e/ratchet/ratchet_test.go b/e2e/ratchet/ratchet_test.go index 1b87c88acda50c3725660bfbb0270aa9a5d0f827..c73ebca4c675934ec0d2a87faa8156ac064144c5 100644 --- a/e2e/ratchet/ratchet_test.go +++ b/e2e/ratchet/ratchet_test.go @@ -115,7 +115,7 @@ func TestStore_AddPartner(t *testing.T) { m, exists := r.managers[relationshipId] if !exists { - t.Errorf("Manager does not exist in map.\n\tmap: %+v", + t.Errorf("State does not exist in map.\n\tmap: %+v", r.managers) } @@ -183,7 +183,7 @@ func TestStore_GetPartner(t *testing.T) { } if !reflect.DeepEqual(expectedManager, m) { - t.Errorf("GetPartner() returned wrong Manager."+ + t.Errorf("GetPartner() returned wrong State."+ "\n\texpected: %v\n\treceived: %v", expectedManager, m) } } diff --git a/e2e/ratchet/utils_test.go b/e2e/ratchet/utils_test.go index 2856948e6f8a67d1566f907e679b1d168f7609c9..8e61934e4851c15e7cc851146c74e7b98b29ca2e 100644 --- a/e2e/ratchet/utils_test.go +++ b/e2e/ratchet/utils_test.go @@ -45,34 +45,34 @@ func makeTestRatchet() (*Ratchet, *versioned.KV, error) { func managersEqual(expected, received *partner.Manager, t *testing.T) bool { equal := true if !reflect.DeepEqual(expected.GetPartnerID(), received.GetPartnerID()) { - t.Errorf("Did not Receive expected Manager.partnerID."+ + t.Errorf("Did not Receive expected State.partnerID."+ "\n\texpected: %+v\n\treceived: %+v", expected.GetPartnerID(), received.GetPartnerID()) equal = false } if !strings.EqualFold(expected.GetRelationshipFingerprint(), received.GetRelationshipFingerprint()) { - t.Errorf("Did not Receive expected Manager.Receive."+ + t.Errorf("Did not Receive expected State.Receive."+ "\n\texpected: %+v\n\treceived: %+v", expected.GetRelationshipFingerprint(), received.GetRelationshipFingerprint()) equal = false } if !reflect.DeepEqual(expected.GetMyID(), received.GetMyID()) { - t.Errorf("Did not Receive expected Manager.myId."+ + t.Errorf("Did not Receive expected State.myId."+ "\n\texpected: %+v\n\treceived: %+v", expected.GetMyID(), received.GetPartnerID()) equal = false } if !reflect.DeepEqual(expected.GetMyOriginPrivateKey(), received.GetMyOriginPrivateKey()) { - t.Errorf("Did not Receive expected Manager.MyPrivateKey."+ + t.Errorf("Did not Receive expected State.MyPrivateKey."+ "\n\texpected: %+v\n\treceived: %+v", expected.GetMyOriginPrivateKey(), received.GetMyOriginPrivateKey()) equal = false } if !reflect.DeepEqual(expected.GetSendRelationshipFingerprint(), received.GetSendRelationshipFingerprint()) { - t.Errorf("Did not Receive expected Manager.SendRelationshipFingerprint."+ + t.Errorf("Did not Receive expected State.SendRelationshipFingerprint."+ "\n\texpected: %+v\n\treceived: %+v", expected.GetSendRelationshipFingerprint(), received.GetSendRelationshipFingerprint()) equal = false diff --git a/fileTransfer/oldTransferRecovery_test.go b/fileTransfer/oldTransferRecovery_test.go index 561785100d4611e7923b6eb6bd6e4e80d48ea4d1..5a352a1d3bc839cd490843448d53739f5ee16061 100644 --- a/fileTransfer/oldTransferRecovery_test.go +++ b/fileTransfer/oldTransferRecovery_test.go @@ -25,7 +25,7 @@ import ( "time" ) -// Tests that Manager.oldTransferRecovery adds all unsent parts to the queue. +// Tests that State.oldTransferRecovery adds all unsent parts to the queue. func TestManager_oldTransferRecovery(t *testing.T) { kv := versioned.NewKV(make(ekv.Memstore)) m, sti, _ := newTestManagerWithTransfers( @@ -188,7 +188,7 @@ func TestManager_oldTransferRecovery(t *testing.T) { } } -// Tests that Manager.updateSentRounds updates the status of each round +// Tests that State.updateSentRounds updates the status of each round // correctly by using the part tracker and checks that all the correct parts // were added to the queue. func TestManager_updateSentRounds(t *testing.T) { @@ -312,7 +312,7 @@ func TestManager_updateSentRounds(t *testing.T) { } } -// Error path: tests that Manager.updateSentRounds returns the expected error +// Error path: tests that State.updateSentRounds returns the expected error // when getRoundResults returns only errors. func TestManager_updateSentRounds_Error(t *testing.T) { kv := versioned.NewKV(make(ekv.Memstore)) diff --git a/fileTransfer/receiveNew_test.go b/fileTransfer/receiveNew_test.go index 4aea311faa6e0fedadf6f627e8f4b43eb544753e..abc470cd0636db4c5235dc77b38eb69599087fbe 100644 --- a/fileTransfer/receiveNew_test.go +++ b/fileTransfer/receiveNew_test.go @@ -19,7 +19,7 @@ import ( "time" ) -// Tests that Manager.receiveNewFileTransfer receives the sent message and that +// Tests that State.receiveNewFileTransfer receives the sent message and that // it reports the correct data to the callback. func TestManager_receiveNewFileTransfer(t *testing.T) { // Create new ReceiveCallback that sends the results on a channel @@ -88,7 +88,7 @@ func TestManager_receiveNewFileTransfer(t *testing.T) { } } -// Tests that Manager.receiveNewFileTransfer stops receiving messages when the +// Tests that State.receiveNewFileTransfer stops receiving messages when the // stoppable is triggered. func TestManager_receiveNewFileTransfer_Stop(t *testing.T) { // Create new ReceiveCallback that sends the results on a channel @@ -149,7 +149,7 @@ func TestManager_receiveNewFileTransfer_Stop(t *testing.T) { } } -// Tests that Manager.receiveNewFileTransfer does not report on the callback +// Tests that State.receiveNewFileTransfer does not report on the callback // when the received message is of the wrong type. func TestManager_receiveNewFileTransfer_InvalidMessageError(t *testing.T) { // Create new ReceiveCallback that sends the results on a channel @@ -191,7 +191,7 @@ func TestManager_receiveNewFileTransfer_InvalidMessageError(t *testing.T) { } } -// Tests that Manager.readNewFileTransferMessage returns the expected sender ID, +// Tests that State.readNewFileTransferMessage returns the expected sender ID, // file size, and preview. func TestManager_readNewFileTransferMessage(t *testing.T) { m := newTestManager(false, nil, nil, nil, nil, t) @@ -251,7 +251,7 @@ func TestManager_readNewFileTransferMessage(t *testing.T) { } } -// Error path: tests that Manager.readNewFileTransferMessage returns the +// Error path: tests that State.readNewFileTransferMessage returns the // expected error when the message.Receive has the wrong MessageType. func TestManager_readNewFileTransferMessage_MessageTypeError(t *testing.T) { m := newTestManager(false, nil, nil, nil, nil, t) @@ -271,7 +271,7 @@ func TestManager_readNewFileTransferMessage_MessageTypeError(t *testing.T) { } } -// Error path: tests that Manager.readNewFileTransferMessage returns the +// Error path: tests that State.readNewFileTransferMessage returns the // expected error when the payload of the message.Receive cannot be // unmarshalled. func TestManager_readNewFileTransferMessage_ProtoUnmarshalError(t *testing.T) { diff --git a/fileTransfer/receive_test.go b/fileTransfer/receive_test.go index cc28fc24f1b910128ceba15d1486b1ef9e120966..5a24712cebd7efe9642d9493caf326de9a57148c 100644 --- a/fileTransfer/receive_test.go +++ b/fileTransfer/receive_test.go @@ -20,7 +20,7 @@ import ( "time" ) -// Tests that Manager.receive returns the correct progress on the callback when +// Tests that State.receive returns the correct progress on the callback when // receiving a single message. func TestManager_receive(t *testing.T) { // Build a manager for sending and a manger for receiving @@ -133,7 +133,7 @@ func TestManager_receive(t *testing.T) { <-done } -// Tests that Manager.receive the progress callback is not called when the +// Tests that State.receive the progress callback is not called when the // stoppable is triggered. func TestManager_receive_Stop(t *testing.T) { // Build a manager for sending and a manger for receiving @@ -232,7 +232,7 @@ func TestManager_receive_Stop(t *testing.T) { <-done1 } -// Tests that Manager.readMessage reads the message without errors and that it +// Tests that State.readMessage reads the message without errors and that it // reports the correct progress on the callback. It also gets the file and // checks that the part is where it should be. func TestManager_readMessage(t *testing.T) { diff --git a/fileTransfer/sendNew_test.go b/fileTransfer/sendNew_test.go index 8a4da00a6d666001813c728311496ba39fcf9a1b..f7accd75b04723c2edd9e2fd50af8d328bbe2bfb 100644 --- a/fileTransfer/sendNew_test.go +++ b/fileTransfer/sendNew_test.go @@ -23,7 +23,7 @@ import ( "testing" ) -// Tests that the E2E message sent via Manager.sendNewFileTransfer matches +// Tests that the E2E message sent via State.sendNewFileTransfer matches // expected. func TestManager_sendNewFileTransfer(t *testing.T) { m := newTestManager(false, nil, nil, nil, nil, t) @@ -69,7 +69,7 @@ func TestManager_sendNewFileTransfer(t *testing.T) { } } -// Error path: tests that Manager.sendNewFileTransfer returns the expected error +// Error path: tests that State.sendNewFileTransfer returns the expected error // when SendE2E fails. func TestManager_sendNewFileTransfer_E2eError(t *testing.T) { // Create new test manager with a SendE2E error triggered diff --git a/fileTransfer/send_test.go b/fileTransfer/send_test.go index 35e1f239a8c4a3249cbd91a3ac05d3e96e47cce9..c4c2a4132f811fc9f8d9b75220cfc069bda455fc 100644 --- a/fileTransfer/send_test.go +++ b/fileTransfer/send_test.go @@ -35,7 +35,7 @@ import ( "time" ) -// Tests that Manager.sendThread successfully sends the parts and reports their +// Tests that State.sendThread successfully sends the parts and reports their // progress on the callback. func TestManager_sendThread(t *testing.T) { m, sti, _ := newTestManagerWithTransfers( @@ -114,7 +114,7 @@ func TestManager_sendThread(t *testing.T) { } } -// Tests that Manager.sendThread successfully sends the parts and reports their +// Tests that State.sendThread successfully sends the parts and reports their // progress on the callback. func TestManager_sendThread_NetworkNotHealthy(t *testing.T) { m, _, _ := newTestManagerWithTransfers( @@ -156,7 +156,7 @@ func TestManager_sendThread_NetworkNotHealthy(t *testing.T) { } } -// Tests that Manager.sendThread successfully sends a partially filled batch +// Tests that State.sendThread successfully sends a partially filled batch // of the correct length when its times out waiting for messages. func TestManager_sendThread_Timeout(t *testing.T) { m, sti, _ := newTestManagerWithTransfers( @@ -232,7 +232,7 @@ func TestManager_sendThread_Timeout(t *testing.T) { } } -// Tests that Manager.sendParts sends all the correct cMix messages and calls +// Tests that State.sendParts sends all the correct cMix messages and calls // the progress callbacks with the correct values. func TestManager_sendParts(t *testing.T) { m, sti, _ := newTestManagerWithTransfers( @@ -316,7 +316,7 @@ func TestManager_sendParts(t *testing.T) { wg.Wait() } -// Error path: tests that, on SendManyCMIX failure, Manager.sendParts adds the +// Error path: tests that, on SendManyCMIX failure, State.sendParts adds the // parts back into the queue, does not call the callback, and does not update // the progress. func TestManager_sendParts_SendManyCmixError(t *testing.T) { @@ -374,7 +374,7 @@ func TestManager_sendParts_SendManyCmixError(t *testing.T) { wg.Wait() } -// Error path: tests that Manager.sendParts returns the expected error whe +// Error path: tests that State.sendParts returns the expected error whe // getRoundResults returns an error. func TestManager_sendParts_RoundResultsError(t *testing.T) { m, sti, _ := newTestManagerWithTransfers( @@ -410,7 +410,7 @@ func TestManager_sendParts_RoundResultsError(t *testing.T) { } } -// Tests that Manager.buildMessages returns the expected values for a group +// Tests that State.buildMessages returns the expected values for a group // of 11 file parts from three different transfers. func TestManager_buildMessages(t *testing.T) { m, sti, _ := newTestManagerWithTransfers( @@ -505,7 +505,7 @@ func TestManager_buildMessages(t *testing.T) { } } -// Tests that Manager.buildMessages skips file parts with deleted transfers or +// Tests that State.buildMessages skips file parts with deleted transfers or // transfers that have run out of fingerprints. func TestManager_buildMessages_MessageBuildFailureError(t *testing.T) { m := newTestManager(false, nil, nil, nil, nil, t) @@ -601,7 +601,7 @@ func TestManager_buildMessages_MessageBuildFailureError(t *testing.T) { } } -// Tests that Manager.buildMessages returns the expected error when a queued +// Tests that State.buildMessages returns the expected error when a queued // part has an invalid part number. func TestManager_buildMessages_NewCmixMessageError(t *testing.T) { m := newTestManager(false, nil, nil, nil, nil, t) @@ -631,7 +631,7 @@ func TestManager_buildMessages_NewCmixMessageError(t *testing.T) { } -// Tests that Manager.newCmixMessage returns a format.Message with the correct +// Tests that State.newCmixMessage returns a format.Message with the correct // MAC, fingerprint, and contents. func TestManager_newCmixMessage(t *testing.T) { m := newTestManager(false, nil, nil, nil, nil, t) @@ -679,7 +679,7 @@ func TestManager_newCmixMessage(t *testing.T) { } } -// Tests that Manager.makeRoundEventCallback returns a callback that calls the +// Tests that State.makeRoundEventCallback returns a callback that calls the // progress callback when a round succeeds. func TestManager_makeRoundEventCallback(t *testing.T) { sendE2eChan := make(chan message.Receive, 100) @@ -783,7 +783,7 @@ func TestManager_makeRoundEventCallback(t *testing.T) { } } -// Tests that Manager.makeRoundEventCallback returns a callback that calls the +// Tests that State.makeRoundEventCallback returns a callback that calls the // progress callback with no parts sent on round failure. Also checks that the // file parts were added back into the queue. func TestManager_makeRoundEventCallback_RoundFailure(t *testing.T) { @@ -873,7 +873,7 @@ func TestManager_makeRoundEventCallback_RoundFailure(t *testing.T) { } } -// Tests that Manager.sendEndE2eMessage sends an E2E message with the expected +// Tests that State.sendEndE2eMessage sends an E2E message with the expected // recipient and message type. This does not test round tracking or critical // messages. func TestManager_sendEndE2eMessage(t *testing.T) { @@ -918,7 +918,7 @@ func TestManager_sendEndE2eMessage(t *testing.T) { } } -// Tests that Manager.queueParts adds all the expected parts to the sendQueue +// Tests that State.queueParts adds all the expected parts to the sendQueue // channel. func TestManager_queueParts(t *testing.T) { m := newTestManager(false, nil, nil, nil, nil, t) @@ -996,7 +996,7 @@ func Test_makeListOfPartNums(t *testing.T) { } } -// Tests that the part size returned by Manager.GetPartSize matches the manually +// Tests that the part size returned by State.GetPartSize matches the manually // calculated part size. func TestManager_getPartSize(t *testing.T) { m := newTestManager(false, nil, nil, nil, nil, t) diff --git a/fileTransfer/utils_test.go b/fileTransfer/utils_test.go index 0ea0e5386b39c9a926fad4a774a11cd103b86410..fc07d1394b9120ff39a9e39bf28c1637b61d14b4 100644 --- a/fileTransfer/utils_test.go +++ b/fileTransfer/utils_test.go @@ -392,7 +392,7 @@ type receivedTransferInfo struct { } //////////////////////////////////////////////////////////////////////////////// -// Test Network Manager // +// Test Network State // //////////////////////////////////////////////////////////////////////////////// func newTestNetworkManager(sendErr bool, sendChan, diff --git a/groupChat/makeGroup_test.go b/groupChat/makeGroup_test.go index 056355d31a0dbe49fa0189f3314d39edd76827c9..e4a0ca4c4a0676ccd24ed8ef519a20ccd999c07a 100644 --- a/groupChat/makeGroup_test.go +++ b/groupChat/makeGroup_test.go @@ -130,7 +130,7 @@ func TestManager_MakeGroup_AddGroupError(t *testing.T) { } } -// Unit test of Manager.buildMembership. +// Unit test of State.buildMembership. func TestManager_buildMembership(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, _ := newTestManager(prng, t) diff --git a/groupChat/manager_test.go b/groupChat/manager_test.go index b3367230a80faaf3b2f752e627414914d8c8fbfe..0688539249fc4af3cd8ebf59ce612d99fec45061 100644 --- a/groupChat/manager_test.go +++ b/groupChat/manager_test.go @@ -20,7 +20,7 @@ import ( "time" ) -// Unit test of Manager.newManager. +// Unit test of State.newManager. func Test_newManager(t *testing.T) { kv := versioned.NewKV(make(ekv.Memstore)) user := group.Member{ @@ -64,7 +64,7 @@ func Test_newManager(t *testing.T) { } } -// Tests that Manager.newManager loads a group storage when it exists. +// Tests that State.newManager loads a group storage when it exists. func Test_newManager_LoadStorage(t *testing.T) { prng := rand.New(rand.NewSource(42)) kv := versioned.NewKV(make(ekv.Memstore)) diff --git a/groupChat/receive_test.go b/groupChat/receive_test.go index 1592f19f2185852de918a76ba17f5dd767f62018..718ec51b76c99ac1e4f1c3275b2f61395e69974f 100644 --- a/groupChat/receive_test.go +++ b/groupChat/receive_test.go @@ -22,13 +22,13 @@ import ( "time" ) -// Tests that Manager.receive returns the correct message on the callback. +// Tests that State.receive returns the correct message on the callback. func TestManager_receive(t *testing.T) { // Setup callback msgChan := make(chan MessageReceive) receiveFunc := func(msg MessageReceive) { msgChan <- msg } - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, receiveFunc, t) @@ -86,7 +86,7 @@ func TestManager_receive_ReadMessageError(t *testing.T) { msgChan := make(chan MessageReceive) receiveFunc := func(msg MessageReceive) { msgChan <- msg } - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, receiveFunc, t) @@ -108,7 +108,7 @@ func TestManager_receive_ReadMessageError(t *testing.T) { // Tests that the quit channel exits the function. func TestManager_receive_QuitChan(t *testing.T) { - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t) @@ -132,10 +132,10 @@ func TestManager_receive_QuitChan(t *testing.T) { } } -// Tests that Manager.readMessage returns the message data for the correct +// Tests that State.readMessage returns the message data for the correct // group. func TestManager_readMessage(t *testing.T) { - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, expectedGrp := newTestManagerWithStore(prng, 10, 0, nil, nil, t) @@ -204,7 +204,7 @@ func TestManager_readMessage(t *testing.T) { // Error path: an error is returned when a group with a matching group // fingerprint cannot be found. func TestManager_readMessage_FindGroupKpError(t *testing.T) { - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t) @@ -238,10 +238,10 @@ func TestManager_readMessage_FindGroupKpError(t *testing.T) { } } -// Tests that a cMix message created by Manager.newCmixMsg can be read by -// Manager.readMessage. +// Tests that a cMix message created by State.newCmixMsg can be read by +// State.readMessage. func TestManager_decryptMessage(t *testing.T) { - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, g := newTestManager(prng, t) @@ -297,7 +297,7 @@ func TestManager_decryptMessage(t *testing.T) { // Error path: an error is returned when the wrong timestamp is passed in and // the decryption key cannot be generated because of the wrong epoch. func TestManager_decryptMessage_GetCryptKeyError(t *testing.T) { - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, g := newTestManager(prng, t) @@ -327,7 +327,7 @@ func TestManager_decryptMessage_GetCryptKeyError(t *testing.T) { // Error path: an error is returned when the decrypted payload cannot be // unmarshalled. func TestManager_decryptMessage_UnmarshalInternalMsgError(t *testing.T) { - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, g := newTestManager(prng, t) diff --git a/groupChat/sendRequests_test.go b/groupChat/sendRequests_test.go index c5ec225a4d4638e518fca793da97bdfabfea5162..f52544e53b9d654fcef0d54a12a64c3d59ab2f7c 100644 --- a/groupChat/sendRequests_test.go +++ b/groupChat/sendRequests_test.go @@ -120,7 +120,7 @@ func TestManager_ResendRequest_GetGroupError(t *testing.T) { } } -// Tests that Manager.sendRequests sends all expected requests successfully. +// Tests that State.sendRequests sends all expected requests successfully. func TestManager_sendRequests(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t) @@ -197,7 +197,7 @@ func TestManager_sendRequests(t *testing.T) { } } -// Tests that Manager.sendRequests returns the correct status when all sends +// Tests that State.sendRequests returns the correct status when all sends // fail. func TestManager_sendRequests_SendAllFail(t *testing.T) { prng := rand.New(rand.NewSource(42)) @@ -226,7 +226,7 @@ func TestManager_sendRequests_SendAllFail(t *testing.T) { } } -// Tests that Manager.sendRequests returns the correct status when some sends +// Tests that State.sendRequests returns the correct status when some sends // fail. func TestManager_sendRequests_SendPartialSent(t *testing.T) { prng := rand.New(rand.NewSource(42)) @@ -268,7 +268,7 @@ func TestManager_sendRequests_SendPartialSent(t *testing.T) { } } -// Unit test of Manager.sendRequest. +// Unit test of State.sendRequest. func TestManager_sendRequest(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManagerWithStore(prng, 10, 0, nil, nil, t) diff --git a/groupChat/send_test.go b/groupChat/send_test.go index 38042203e9ee2f42a922307e16e1891eaf38821c..0a8bbefe9307b531930fe41f1ed16bfc3ffa790d 100644 --- a/groupChat/send_test.go +++ b/groupChat/send_test.go @@ -137,7 +137,7 @@ func TestManager_Send_SendManyCMIXError(t *testing.T) { } } -// Tests that Manager.createMessages generates the messages for the correct +// Tests that State.createMessages generates the messages for the correct // group. func TestManager_createMessages(t *testing.T) { prng := rand.New(rand.NewSource(42)) @@ -200,7 +200,7 @@ func TestManager_createMessages(t *testing.T) { func TestManager_createMessages_InvalidGroupIdError(t *testing.T) { expectedErr := strings.SplitN(newNoGroupErr, "%", 2)[0] - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, _ := newTestManagerWithStore(prng, 10, 0, nil, nil, t) @@ -213,7 +213,7 @@ func TestManager_createMessages_InvalidGroupIdError(t *testing.T) { } } -// Tests that Manager.newMessage returns messages with correct data. +// Tests that State.newMessage returns messages with correct data. func TestGroup_newMessages(t *testing.T) { prng := rand.New(rand.NewSource(42)) m, g := newTestManager(prng, t) @@ -276,7 +276,7 @@ func TestGroup_newMessages(t *testing.T) { } } -// Error path: an error is returned when Manager.neCmixMsg returns an error. +// Error path: an error is returned when State.neCmixMsg returns an error. func TestGroup_newMessages_NewCmixMsgError(t *testing.T) { expectedErr := strings.SplitN(newCmixErr, "%", 2)[0] prng := rand.New(rand.NewSource(42)) @@ -291,7 +291,7 @@ func TestGroup_newMessages_NewCmixMsgError(t *testing.T) { // Tests that the message returned by newCmixMsg has all the expected parts. func TestGroup_newCmixMsg(t *testing.T) { - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, g := newTestManager(prng, t) @@ -388,7 +388,7 @@ func TestGroup_newCmixMsg_SaltReaderError(t *testing.T) { func TestGroup_newCmixMsg_InternalMsgSizeError(t *testing.T) { expectedErr := strings.SplitN(messageLenErr, "%", 2)[0] - // Create new test Manager and Group + // Create new test State and Group prng := rand.New(rand.NewSource(42)) m, g := newTestManager(prng, t) diff --git a/interfaces/auth.go b/interfaces/auth.go index d82625c723150b433959d22c83241c909fb3781e..60ba0d311342b154238caf251d2eb0c22f339d53 100644 --- a/interfaces/auth.go +++ b/interfaces/auth.go @@ -9,42 +9,6 @@ package interfaces import ( "gitlab.com/elixxir/crypto/contact" - "gitlab.com/xx_network/primitives/id" ) type RequestCallback func(requestor contact.Contact) -type ConfirmCallback func(partner contact.Contact) -type ResetNotificationCallback func(partner contact.Contact) - -type Auth interface { - // Adds a general callback to be used on auth requests. This will be preempted - // by any specific callback - AddGeneralRequestCallback(cb RequestCallback) - // Adds a general callback to be used on auth requests. This will not be - // preempted by any specific callback. It is recommended that the specific - // callbacks are used, this is primarily for debugging. - AddOverrideRequestCallback(cb RequestCallback) - // Adds a specific callback to be used on auth requests. This will preempt a - // general callback, meaning the request will be heard on this callback and not - // the general. Request will still be heard on override callbacks. - AddSpecificRequestCallback(id *id.ID, cb RequestCallback) - // Removes a specific callback to be used on auth requests. - RemoveSpecificRequestCallback(id *id.ID) - // Adds a general callback to be used on auth confirms. This will be preempted - // by any specific callback - AddGeneralConfirmCallback(cb ConfirmCallback) - // Adds a general callback to be used on auth confirms. This will not be - // preempted by any specific callback. It is recommended that the specific - // callbacks are used, this is primarily for debugging. - AddOverrideConfirmCallback(cb ConfirmCallback) - // Adds a specific callback to be used on auth confirms. This will preempt a - // general callback, meaning the request will be heard on this callback and not - // the general. Request will still be heard on override callbacks. - AddSpecificConfirmCallback(id *id.ID, cb ConfirmCallback) - // Removes a specific callback to be used on auth confirm. - RemoveSpecificConfirmCallback(id *id.ID) - // Add a callback to receive session renegotiation notifications - AddResetNotificationCallback(cb ResetNotificationCallback) - //Replays all pending received requests over tha callbacks - ReplayRequests() -} diff --git a/interfaces/networkManager.go b/interfaces/networkManager.go index b5104d1018151632d4d1ae41767378333990d1bd..2450f4038a0233d9c6bafd14b1aa37b4cbea0526 100644 --- a/interfaces/networkManager.go +++ b/interfaces/networkManager.go @@ -137,7 +137,7 @@ type NetworkManager interface { /*===Nodes================================================================*/ /* Keys must be registed with nodes in order to send messages throug them. - this process is in general automatically handled by the Network Manager*/ + this process is in general automatically handled by the Network State*/ // HasNode can be used to determine if a keying relationship exists with a // node. @@ -153,7 +153,7 @@ type NetworkManager interface { /*===Historical Rounds====================================================*/ /* A complete set of round info is not kept on the client, and sometimes the network will need to be queried to get round info. Historical rounds - is the system internal to the Network Manager to do this. + is the system internal to the Network State to do this. It can be used externally as well.*/ // LookupHistoricalRound - looks up the passed historical round on the diff --git a/network/identity/tracker.go b/network/identity/tracker.go index 5dd895176dbbbaba5c62564c431db5ffb8b8915e..c19144301c8dcb166dc8003d7d68de200889fe14 100644 --- a/network/identity/tracker.go +++ b/network/identity/tracker.go @@ -9,6 +9,7 @@ package identity import ( "encoding/json" + "github.com/pkg/errors" "io" "os" "sync" @@ -52,29 +53,30 @@ type Tracker interface { } type manager struct { - tracked []trackedID + tracked []TrackedID store *receptionID.Store session storage.Session - newIdentity chan trackedID + newIdentity chan TrackedID deleteIdentity chan *id.ID addrSpace address.Space mux *sync.Mutex } -type trackedID struct { +type TrackedID struct { NextGeneration time.Time LastGeneration time.Time Source *id.ID ValidUntil time.Time Persistent bool + Creation time.Time } 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), + newIdentity: make(chan TrackedID, trackedIDChanSize), deleteIdentity: make(chan *id.ID, deleteIDChanSize), addrSpace: addrSpace, mux: &sync.Mutex{}, @@ -88,7 +90,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(), @@ -103,7 +105,7 @@ func NewOrLoadTracker(session storage.Session, addrSpace address.Space) *manager "stored timestamp found; creating a new tracked identity " + "from scratch.") - 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(), @@ -137,12 +139,13 @@ func (t manager) StartProcesses() stoppable.Stoppable { // AddIdentity adds an identity to be tracked. func (t *manager) AddIdentity(id *id.ID, validUntil time.Time, persistent bool) { - t.newIdentity <- trackedID{ + t.newIdentity <- TrackedID{ NextGeneration: netTime.Now().Add(-time.Second), LastGeneration: time.Time{}, Source: id, ValidUntil: validUntil, Persistent: persistent, + Creation: netTime.Now(), } } @@ -157,6 +160,18 @@ func (t *manager) GetEphemeralIdentity(rng io.Reader, addressSize uint8) ( return t.store.GetIdentity(rng, addressSize) } +// GetIdentity returns a currently tracked identity +func (t *manager) GetIdentity(get *id.ID) (TrackedID, error) { + t.mux.Lock() + defer t.mux.Unlock() + for i := range t.tracked { + if get.Cmp(t.tracked[i].Source) { + return t.tracked[i], nil + } + } + return TrackedID{}, errors.Errorf("could not find id %s", get) +} + func (t *manager) track(stop *stoppable.Single) { // Wait until the ID size is retrieved from the network addressSize := t.addrSpace.GetAddressSpace() @@ -227,7 +242,7 @@ trackerLoop: // 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]) @@ -352,7 +367,7 @@ func generateIdentitiesOverRange(lastGeneration, generateThrough time.Time, func (t *manager) save() { t.mux.Lock() defer t.mux.Unlock() - persistent := make([]trackedID, 0, len(t.tracked)) + persistent := make([]TrackedID, 0, len(t.tracked)) for i := range t.tracked { if t.tracked[i].Persistent { @@ -366,7 +381,7 @@ func (t *manager) save() { data, err := json.Marshal(&persistent) if err != nil { - jww.FATAL.Panicf("Unable to marshal trackedID list: %+v", err) + jww.FATAL.Panicf("Unable to marshal TrackedID list: %+v", err) } obj := &versioned.Object{ @@ -377,7 +392,7 @@ func (t *manager) save() { err = t.session.GetKV().Set(TrackerListKey, TrackerListVersion, obj) if err != nil { - jww.FATAL.Panicf("Unable to save trackedID list: %+v", err) + jww.FATAL.Panicf("Unable to save TrackedID list: %+v", err) } } diff --git a/network/interface.go b/network/interface.go index 3a6f8dbf7d3cb0f40c9c3c881b4ba14f3aa5c34d..6992bd3f3bc48440bd0e83f68421a8f09283f141 100644 --- a/network/interface.go +++ b/network/interface.go @@ -3,6 +3,7 @@ package network import ( "gitlab.com/elixxir/client/network/gateway" "gitlab.com/elixxir/client/network/historical" + "gitlab.com/elixxir/client/network/identity" "gitlab.com/elixxir/client/network/message" "gitlab.com/elixxir/client/stoppable" "gitlab.com/elixxir/comms/network" @@ -91,6 +92,9 @@ type Manager interface { // RemoveIdentity removes a currently tracked identity. RemoveIdentity(id *id.ID) + //GetIdentity returns a currently tracked identity + GetIdentity(get *id.ID) (identity.TrackedID, error) + /* Fingerprints are the primary mechanism of identifying a picked up message over cMix. They are a unique one time use a 255-bit vector generally associated with a specific encryption key, but can be used for an @@ -200,7 +204,7 @@ type Manager interface { /* === Nodes ============================================================ */ /* Keys must be registered with nodes in order to send messages through them. This process is, in general, automatically handled by the Network - Manager. */ + State. */ // HasNode can be used to determine if a keying relationship exists with a // node. @@ -217,7 +221,7 @@ type Manager interface { /* === Rounds =========================================================== */ /* A complete set of round info is not kept on the client, and sometimes the network will need to be queried to get round info. Historical rounds - is the system internal to the Network Manager to do this. It can be used + is the system internal to the Network State to do this. It can be used externally as well. */ // GetRoundResults adjudicates on the rounds requested. Checks if they are diff --git a/single/manager_test.go b/single/manager_test.go index 1af9467c086613d77adfc0aad4c6e71e6cd3b46c..754433c161eed7cc87b8ab619452e087df09edc1 100644 --- a/single/manager_test.go +++ b/single/manager_test.go @@ -52,7 +52,7 @@ func Test_newManager(t *testing.T) { if e.client != m.client || e.store != m.store || e.net != m.net || e.rng != m.rng || !reflect.DeepEqual(e.p, m.p) { - t.Errorf("NewHandler() did not return the expected new Manager."+ + t.Errorf("NewHandler() did not return the expected new State."+ "\nexpected: %+v\nreceived: %+v", e, m) } } diff --git a/storage/ud/facts.go b/storage/ud/facts.go index 9762bc068b915c4d5138226bf827157911508332..db60c88191477cf1ff50c5779009c652ce01e49c 100644 --- a/storage/ud/facts.go +++ b/storage/ud/facts.go @@ -23,7 +23,7 @@ const ( factNotInStoreErr = "Fact %v does not exist in store" ) -// Store is the storage object for the higher level ud.Manager object. +// Store is the storage object for the higher level ud.State object. // This storage implementation is written for client side. type Store struct { // confirmedFacts contains facts that have been confirmed diff --git a/ud/addFact_test.go b/ud/addFact_test.go index 7fecfc4d6d59a3a15666e662cbb149af52c6795d..9e9699a989a3ef2e358a71dc233ad2a2ab3b1422 100644 --- a/ud/addFact_test.go +++ b/ud/addFact_test.go @@ -45,7 +45,7 @@ func TestAddFact(t *testing.T) { t.Errorf("Failed to start client comms: %+v", err) } - // Create our Manager object + // Create our State object m := Manager{ comms: comms, net: newTestNetworkManager(t), diff --git a/ud/manager.go b/ud/manager.go index e0c0d8ea3dd6349e7e7b961a694d5bd5d592fdd4..b8cee0a4928de9850ea0a5e6cd7a8620c0e2066f 100644 --- a/ud/manager.go +++ b/ud/manager.go @@ -63,7 +63,7 @@ func NewManager(client *api.Client, single *single.Manager) (*Manager, error) { jww.INFO.Println("ud.NewManager()") if client.NetworkFollowerStatus() != api.Running { return nil, errors.New( - "cannot start UD Manager when network follower is not running.") + "cannot start UD State when network follower is not running.") } m := &Manager{ diff --git a/ud/manager_test.go b/ud/manager_test.go index 1dcb6c273df1c6ec7ed92980b15fc8990cfab01a..e7ddfe11110c3ff35a017622186e773f643e5273 100644 --- a/ud/manager_test.go +++ b/ud/manager_test.go @@ -67,7 +67,7 @@ func TestManager_SetAlternativeUserDiscovery(t *testing.T) { t.Errorf("Failed to start client comms: %+v", err) } - // Create our Manager object + // Create our State object m := Manager{ comms: comms, net: newTestNetworkManager(t), diff --git a/ud/search_test.go b/ud/search_test.go index d0a1edfb9c9dbd1623ae5e5b9e1234c421c87b44..5fb6b33cefe636422d1deee8161db714bbbc1f8b 100644 --- a/ud/search_test.go +++ b/ud/search_test.go @@ -105,7 +105,7 @@ func TestManager_Search(t *testing.T) { // func TestManager_Search_CallbackError(t *testing.T) { // isReg := uint32(1) // // Set up manager -// m := &Manager{ +// m := &State{ // rng: fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG), // grp: cyclic.NewGroup(large.NewInt(107), large.NewInt(2)), // storage: storage.InitTestingSession(t), @@ -172,7 +172,7 @@ func TestManager_Search(t *testing.T) { // func TestManager_Search_EventChanTimeout(t *testing.T) { // isReg := uint32(1) // // Set up manager -// m := &Manager{ +// m := &State{ // rng: fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG), // grp: cyclic.NewGroup(large.NewInt(107), large.NewInt(2)), // storage: storage.InitTestingSession(t),