diff --git a/auth/state.go b/auth/state.go index f77da163641d59a5be7004c8f52b498e3c2cb6bb..e226a01e7bdf0cf2575e6f3d0ed13983ef38c0f7 100644 --- a/auth/state.go +++ b/auth/state.go @@ -110,7 +110,8 @@ func NewStateLegacy(kv *versioned.KV, net cmix.Client, e2e e2e.Handler, }, &receivedRequestService{s: s, reset: true}) if err != nil { - return nil, errors.Errorf("Failed to make Auth State manager") + return nil, errors.WithMessage(err, + "Failed to make Auth State manager") } return s, nil diff --git a/auth/store/previousNegotiations.go b/auth/store/previousNegotiations.go index 6b0c0d6ddf9135c21cb25170b1b13de3f0a20d5d..be8d701f082ef99de72cd67f9a1d4c0b01b6bd9f 100644 --- a/auth/store/previousNegotiations.go +++ b/auth/store/previousNegotiations.go @@ -9,20 +9,21 @@ package store import ( "bytes" - "encoding/base64" "encoding/binary" "encoding/json" + + "github.com/pkg/errors" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/e2e/auth" + "gitlab.com/elixxir/ekv" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" - "strings" ) const ( negotiationPartnersKey = "NegotiationPartners" - negotiationPartnersVersion = 0 + negotiationPartnersVersion = 1 negotiationFingerprintsKeyPrefix = "NegotiationFingerprints/" currentNegotiationFingerprintsVersion = 0 ) @@ -119,20 +120,22 @@ func (s *Store) savePreviousNegotiations() error { func (s *Store) newOrLoadPreviousNegotiations() (map[id.ID]bool, error) { obj, err := s.kv.Get(negotiationPartnersKey, negotiationPartnersVersion) - if err != nil { - if strings.Contains(err.Error(), "object not found") { - newPreviousNegotiations := make(map[id.ID]bool) - obj := &versioned.Object{ - Version: negotiationPartnersVersion, - Timestamp: netTime.Now(), - Data: marshalPreviousNegotiations(newPreviousNegotiations), - } - err = s.kv.Set(negotiationPartnersKey, negotiationPartnersVersion, obj) - if err != nil { - return nil, err - } - return newPreviousNegotiations, nil + + // V0 Upgrade Path + if !ekv.Exists(err) { + upgradeErr := upgradePreviousNegotiationsV0(s.kv) + if upgradeErr != nil { + return nil, errors.Wrapf(err, "%+v", upgradeErr) } + obj, err = s.kv.Get(negotiationPartnersKey, + negotiationPartnersVersion) + } + + // Note: if it still doesn't exist, return an empty one. + if err != nil && !ekv.Exists(err) { + newPreviousNegotiations := make(map[id.ID]bool) + return newPreviousNegotiations, nil + } else if err != nil { return nil, err } @@ -192,8 +195,8 @@ func saveNegotiationFingerprints( // loadNegotiationFingerprints loads the list of sentByFingerprints for the given // partner from storage. func loadNegotiationFingerprints(partner *id.ID, kv *versioned.KV) ([][]byte, error) { - obj, err := kv.Get(makeNegotiationFingerprintsKey(partner), - currentNegotiationFingerprintsVersion) + fpKey := makeNegotiationFingerprintsKey(partner) + obj, err := kv.Get(fpKey, currentNegotiationFingerprintsVersion) if err != nil { return nil, err } @@ -239,6 +242,50 @@ func unmarshalNegotiationFingerprints(buf []byte) [][]byte { // makeOldNegotiationFingerprintsKey generates the key used to load and store // negotiation sentByFingerprints for the partner. func makeNegotiationFingerprintsKey(partner *id.ID) string { - return negotiationFingerprintsKeyPrefix + - string(base64.StdEncoding.EncodeToString(partner.Marshal())) + return negotiationFingerprintsKeyPrefix + partner.String() +} + +// Historical functions + +// unmarshalPreviousNegotiations unmarshalls the marshalled byte slice into a +// list of partner IDs. +func unmarshalPreviousNegotiationsV0(buf []byte) map[id.ID]struct{} { + buff := bytes.NewBuffer(buf) + + numberOfPartners := binary.LittleEndian.Uint64(buff.Next(8)) + partners := make(map[id.ID]struct{}, numberOfPartners) + + for i := uint64(0); i < numberOfPartners; i++ { + partner, err := id.Unmarshal(buff.Next(id.ArrIDLen)) + if err != nil { + jww.FATAL.Panicf( + "Failed to unmarshal negotiation partner ID: %+v", err) + } + + partners[*partner] = struct{}{} + } + + return partners +} + +// upgradePreviousNegotiationsV0 upgrades the negotiations Partners key from V0 +// to V1 +func upgradePreviousNegotiationsV0(kv *versioned.KV) error { + obj, err := kv.Get(negotiationPartnersKey, 0) + if !ekv.Exists(err) { + return nil + } + + old := unmarshalPreviousNegotiationsV0(obj.Data) + newPrevNegotiations := make(map[id.ID]bool) + for id := range old { + newPrevNegotiations[id] = true + } + obj = &versioned.Object{ + Version: negotiationPartnersVersion, + Timestamp: netTime.Now(), + Data: marshalPreviousNegotiations( + newPrevNegotiations), + } + return kv.Set(negotiationPartnersKey, negotiationPartnersVersion, obj) } diff --git a/auth/store/receivedRequest.go b/auth/store/receivedRequest.go index 2a9eaa56dcfc868bf42ee2141cec1c6112b33ca0..4bb0c5216a6abd2b48d7fdc779c493d5a69b6597 100644 --- a/auth/store/receivedRequest.go +++ b/auth/store/receivedRequest.go @@ -1,7 +1,6 @@ package store import ( - "encoding/base64" "sync" "github.com/cloudflare/circl/dh/sidh" @@ -11,6 +10,7 @@ import ( util "gitlab.com/elixxir/client/storage/utility" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/contact" + "gitlab.com/elixxir/ekv" "gitlab.com/xx_network/primitives/id" ) @@ -77,10 +77,12 @@ func loadReceivedRequest(kv *versioned.KV, partner *id.ID) ( } round, err := rounds.LoadRound(kv, makeRoundKey(partner)) - if err != nil { + if err != nil && ekv.Exists(err) { return nil, errors.WithMessagef(err, "Failed to Load "+ "round request was received on with %s", partner) + } else if err != nil && !ekv.Exists(err) { + jww.WARN.Printf("No round info for partner %s", partner) } return &ReceivedRequest{ @@ -120,6 +122,5 @@ func (rr *ReceivedRequest) getType() RequestType { } func makeRoundKey(partner *id.ID) string { - return "receivedRequestRound:" + - base64.StdEncoding.EncodeToString(partner.Marshal()) + return "receivedRequestRound:" + partner.String() } diff --git a/auth/store/sentRequest.go b/auth/store/sentRequest.go index c6080a9e059946ff9d04de06ad936b5650ea0cdb..5f5b8a69e1e193ada63726e1f24c31e03a37973c 100644 --- a/auth/store/sentRequest.go +++ b/auth/store/sentRequest.go @@ -8,9 +8,9 @@ package store import ( - "encoding/base64" "encoding/hex" "encoding/json" + "fmt" "sync" "github.com/cloudflare/circl/dh/sidh" @@ -19,12 +19,13 @@ import ( sidhinterface "gitlab.com/elixxir/client/interfaces/sidh" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/cyclic" + "gitlab.com/elixxir/ekv" "gitlab.com/elixxir/primitives/format" "gitlab.com/xx_network/primitives/id" "gitlab.com/xx_network/primitives/netTime" ) -const currentSentRequestVersion = 0 +const currentSentRequestVersion = 1 type SentRequest struct { kv *versioned.KV @@ -73,8 +74,16 @@ func newSentRequest(kv *versioned.KV, partner *id.ID, partnerHistoricalPubKey, func loadSentRequest(kv *versioned.KV, partner *id.ID, grp *cyclic.Group) (*SentRequest, error) { srKey := makeSentRequestKey(partner) - obj, err := kv.Get(srKey, - currentSentRequestVersion) + obj, err := kv.Get(srKey, currentSentRequestVersion) + + // V0 Upgrade Path + if !ekv.Exists(err) { + upgradeErr := upgradeSentRequestKeyV0(kv, partner) + if upgradeErr != nil { + return nil, errors.Wrapf(err, "%+v", upgradeErr) + } + obj, err = kv.Get(srKey, currentSentRequestVersion) + } if err != nil { return nil, errors.WithMessagef(err, "Failed to Load "+ @@ -260,6 +269,37 @@ func (sr *SentRequest) getType() RequestType { return Sent } +// makeSentRequestKey makes the key string for accessing the +// partners sent request object from the key value store. func makeSentRequestKey(partner *id.ID) string { - return "sentRequest:" + base64.StdEncoding.EncodeToString(partner.Marshal()) + return "sentRequest:" + partner.String() +} + +// V0 Utility Functions + +// makeSentRequestKeyV0 The old key used the string pattern +// "Partner:PartnerID" instead of "sentRequest:PartnerID". +func makeSentRequestKeyV0(partner *id.ID) string { + return fmt.Sprintf("Partner:%v", partner.String()) +} + +// upgradeSentRequestKeyV0 upgrads the srKey from version 0 to 1 by +// changing the version number. +func upgradeSentRequestKeyV0(kv *versioned.KV, partner *id.ID) error { + oldKey := makeSentRequestKeyV0(partner) + obj, err := kv.Get(oldKey, 0) + if err != nil { + return err + } + + jww.INFO.Printf("Upgrading legacy srKey for %s", partner) + + // Note: uses same encoding, just different keys + obj.Version = 1 + err = kv.Set(makeSentRequestKey(partner), 1, obj) + if err != nil { + return err + } + + return kv.Delete(oldKey, 0) } diff --git a/e2e/ratchet/ratchet.go b/e2e/ratchet/ratchet.go index aa5fd2c185cec46568655fc9a765850a04715dfa..9995ba4eba11052ced441d53b897a1e310bccc60 100644 --- a/e2e/ratchet/ratchet.go +++ b/e2e/ratchet/ratchet.go @@ -104,10 +104,11 @@ func (r *Ratchet) AddPartner(partnerID *id.ID, myID := r.myID - jww.INFO.Printf("Adding Partner %s:\n\tMy Private Key: %s"+ + myPubKey := diffieHellman.GeneratePublicKey(myPrivKey, r.grp) + jww.INFO.Printf("Adding Partner %s:\n\tMy Public Key: %s"+ "\n\tPartner Public Key: %s to %s", partnerID, - myPrivKey.TextVerbose(16, 0), + myPubKey.TextVerbose(16, 0), partnerPubKey.TextVerbose(16, 0), myID) mid := *partnerID diff --git a/storage/utility/contact.go b/storage/utility/contact.go index cccfef3483c47fc83579563e29b18e0578a17610..2050efd8a2664a41bb34c557c807f73d94879a57 100644 --- a/storage/utility/contact.go +++ b/storage/utility/contact.go @@ -9,6 +9,7 @@ package utility import ( "fmt" + "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/contact" "gitlab.com/xx_network/primitives/id" @@ -17,6 +18,14 @@ import ( const currentContactVersion = 0 +// StoreContact writes a contact into a versioned.KV using the +// contact ID as the key. +// +// Parameters: +// * kv - the key value store to write the contact. +// * c - the contact object to store. +// Returns: +// * error if the write fails to succeed for any reason. func StoreContact(kv *versioned.KV, c contact.Contact) error { now := netTime.Now() @@ -29,6 +38,15 @@ func StoreContact(kv *versioned.KV, c contact.Contact) error { return kv.Set(makeContactKey(c.ID), currentContactVersion, &obj) } +// LoadContact reads a contact from a versioned.KV vie their contact ID. +// +// Parameters: +// * kv - the key value store to read the contact +// * cid - the contacts unique *id.ID to load +// Returns: +// * contact.Contact object populated with the user info, or empty on error. +// * version number of the contact loaded. +// * error if an error occurs, or nil otherwise func LoadContact(kv *versioned.KV, cid *id.ID) (contact.Contact, error) { vo, err := kv.Get(makeContactKey(cid), currentContactVersion) if err != nil { @@ -38,6 +56,13 @@ func LoadContact(kv *versioned.KV, cid *id.ID) (contact.Contact, error) { return contact.Unmarshal(vo.Data) } +// DeleteContact removes the contact identified by cid from the kv. +// +// Parameters: +// - kv - the key value store to delete from +// - cid - the contacts unique *id.ID to delete +// Returns: +// - error if an error occurs or nil otherwise func DeleteContact(kv *versioned.KV, cid *id.ID) error { return kv.Delete(makeContactKey(cid), currentContactVersion) } diff --git a/xxdk/e2e.go b/xxdk/e2e.go index 980d00fe8b9463ff94c4ce7efbbcf8fb79cf8cfe..722195e9aa47fce2726ad01a19f36db3a9738411 100644 --- a/xxdk/e2e.go +++ b/xxdk/e2e.go @@ -93,9 +93,10 @@ func loginLegacy(net *Cmix, callbacks AuthCallbacks, return nil, errors.WithMessage(err, "Failed to add the e2e processes") } - m.auth, err = auth.NewState(net.GetStorage().GetKV(), net.GetCmix(), - m.e2e, net.GetRng(), net.GetEventReporter(), params.Auth, - params.Session, MakeAuthCallbacksAdapter(callbacks, m), + m.auth, err = auth.NewStateLegacy(net.GetStorage().GetKV(), + net.GetCmix(), m.e2e, net.GetRng(), net.GetEventReporter(), + params.Auth, params.Session, + MakeAuthCallbacksAdapter(callbacks, m), m.backup.TriggerBackup) if err != nil { return nil, err