diff --git a/storage/auth/authID.go b/storage/auth/authID.go index 41a4e6c5cc34329c71622924f33114e2adee9560..360bc3e6beb9824612f38c39bed7a28ea4946b86 100644 --- a/storage/auth/authID.go +++ b/storage/auth/authID.go @@ -30,6 +30,10 @@ func (ai authIdentity) String() string { return base64.StdEncoding.EncodeToString(ai[:]) } -func makeRequestPrefix(aid authIdentity) string { - return base64.StdEncoding.EncodeToString(aid[:]) +func makeReceiveRequestPrefix(aid authIdentity) string { + return "receiveRequest:" + base64.StdEncoding.EncodeToString(aid[:]) +} + +func makeSentRequestKey(aid authIdentity) string { + return "sentRequest:" + base64.StdEncoding.EncodeToString(aid[:]) } diff --git a/storage/auth/receivedRequest.go b/storage/auth/receivedRequest.go index 4f56526005cd71c9a4d7060776aeaf873aaeb245..d83f7556a175665902ff8291aa544df9eb905320 100644 --- a/storage/auth/receivedRequest.go +++ b/storage/auth/receivedRequest.go @@ -3,10 +3,12 @@ package auth import ( "github.com/cloudflare/circl/dh/sidh" "github.com/pkg/errors" + jww "github.com/spf13/jwalterweatherman" util "gitlab.com/elixxir/client/storage/utility" "gitlab.com/elixxir/client/storage/versioned" "gitlab.com/elixxir/crypto/contact" "gitlab.com/xx_network/primitives/id" + "sync" ) type ReceivedRequest struct { @@ -22,6 +24,34 @@ type ReceivedRequest struct { //sidHPublic key of partner theirSidHPubKeyA *sidh.PublicKey + + //lock to make sure only one operator at a time + mux *sync.Mutex +} + +func newReceivedRequest(kv *versioned.KV, myID *id.ID, c contact.Contact, + key *sidh.PublicKey) *ReceivedRequest { + + aid := makeAuthIdentity(c.ID, myID) + kv = kv.Prefix(makeReceiveRequestPrefix(aid)) + + if err := util.StoreContact(kv, c); err != nil { + jww.FATAL.Panicf("Failed to save contact for partner %s", c.ID.String()) + } + + storeKey := util.MakeSIDHPublicKeyKey(c.ID) + if err := util.StoreSIDHPublicKey(kv, key, storeKey); err != nil { + jww.FATAL.Panicf("Failed to save contact pubKey for partner %s", + c.ID.String()) + } + + return &ReceivedRequest{ + kv: kv, + aid: aid, + myID: myID, + partner: c, + theirSidHPubKeyA: key, + } } func loadReceivedRequest(kv *versioned.KV, partner *id.ID, myID *id.ID) ( @@ -36,7 +66,7 @@ func loadReceivedRequest(kv *versioned.KV, partner *id.ID, myID *id.ID) ( // at their own paths aid := makeAuthIdentity(partner, myID) newKV := kv - oldKV := kv.Prefix(makeRequestPrefix(aid)) + oldKV := kv.Prefix(makeReceiveRequestPrefix(aid)) c, err := util.LoadContact(newKV, partner) @@ -74,3 +104,15 @@ func loadReceivedRequest(kv *versioned.KV, partner *id.ID, myID *id.ID) ( func (rr *ReceivedRequest) getType() RequestType { return Receive } + +func (rr *ReceivedRequest) GetMyID() *id.ID { + return rr.myID +} + +func (rr *ReceivedRequest) GetContact() contact.Contact { + return rr.partner +} + +func (rr *ReceivedRequest) GetTheirSidHPubKeyA() *sidh.PublicKey { + return rr.theirSidHPubKeyA +} diff --git a/storage/auth/sentRequest.go b/storage/auth/sentRequest.go index 70b13b1522bbc735fab27dd5e04fc39bf2eafb4c..ce177ee0d7f3e1b17be96d3c08155cfd0818ebe2 100644 --- a/storage/auth/sentRequest.go +++ b/storage/auth/sentRequest.go @@ -47,6 +47,27 @@ type sentRequestDisk struct { Fingerprint []byte } +func newSentRequest(kv *versioned.KV, partner, myID *id.ID, partnerHistoricalPubKey, myPrivKey, + myPubKey *cyclic.Int, sidHPrivA *sidh.PrivateKey, sidHPubA *sidh.PublicKey, + fp format.Fingerprint) (*SentRequest, error) { + + aid := makeAuthIdentity(partner, myID) + + sr := &SentRequest{ + kv: kv, + aid: aid, + partner: partner, + partnerHistoricalPubKey: partnerHistoricalPubKey, + myPrivKey: myPrivKey, + myPubKey: myPubKey, + mySidHPubKeyA: sidHPubA, + mySidHPrivKeyA: sidHPrivA, + fingerprint: fp, + } + + return sr, sr.save() +} + func loadSentRequest(kv *versioned.KV, partner *id.ID, myID *id.ID, grp *cyclic.Group) (*SentRequest, error) { // try the load with both the new prefix and the old, which one is @@ -57,24 +78,24 @@ func loadSentRequest(kv *versioned.KV, partner *id.ID, myID *id.ID, grp *cyclic. // partnerID,MyID. Old receivedByID always have the same myID so they can be left // at their own paths aid := makeAuthIdentity(partner, myID) - oldKV := kv - newKV := kv.Prefix(makeRequestPrefix(aid)) - obj, err := newKV.Get(versioned.MakePartnerPrefix(partner), + obj, err := kv.Get(makeSentRequestKey(aid), currentSentRequestVersion) //loading with the new prefix path failed, try with the new if err != nil { - obj, err = oldKV.Get(versioned.MakePartnerPrefix(partner), + obj, err = kv.Get(versioned.MakePartnerPrefix(partner), currentSentRequestVersion) if err != nil { return nil, errors.WithMessagef(err, "Failed to Load "+ "SentRequest Auth with %s", partner) } else { - kv = oldKV + err = kv.Set(makeSentRequestKey(aid), currentSentRequestVersion, obj) + if err != nil { + return nil, errors.WithMessagef(err, "Failed to update "+ + "from old store SentRequest Auth with %s", partner) + } } - } else { - kv = newKV } srd := &sentRequestDisk{} diff --git a/storage/auth/sentRequestHandler.go b/storage/auth/sentRequestHandler.go new file mode 100644 index 0000000000000000000000000000000000000000..792d6d7d2e4c777aff344e9ac35dbfacffd841b9 --- /dev/null +++ b/storage/auth/sentRequestHandler.go @@ -0,0 +1,6 @@ +package auth + +type SentRequestHandler interface { + Add(sr *SentRequest) + Delete(sr *SentRequest) +} diff --git a/storage/auth/store.go b/storage/auth/store.go index 40e1c9dd5dd7e7cddb20a1cc4a48237f8025c0ef..8582c7571bf2886b0770f63f99a3b105a8304044 100644 --- a/storage/auth/store.go +++ b/storage/auth/store.go @@ -39,12 +39,14 @@ type Store struct { defaultID *id.ID + srh SentRequestHandler + mux sync.RWMutex } // NewStore creates a new store. All passed in private keys are added as // sentByFingerprints so they can be used to trigger receivedByID. -func NewStore(kv *versioned.KV, grp *cyclic.Group) error { +func NewStore(kv *versioned.KV, grp *cyclic.Group, srh SentRequestHandler) error { kv = kv.Prefix(storePrefix) s := &Store{ kv: kv, @@ -52,6 +54,7 @@ func NewStore(kv *versioned.KV, grp *cyclic.Group) error { receivedByID: make(map[authIdentity]*ReceivedRequest), sentByID: make(map[authIdentity]*SentRequest), previousNegotiations: make(map[id.ID]struct{}), + srh: srh, } err := s.savePreviousNegotiations() @@ -65,7 +68,7 @@ func NewStore(kv *versioned.KV, grp *cyclic.Group) error { // LoadStore loads an extant new store. All passed in private keys are added as // sentByFingerprints so they can be used to trigger receivedByID. -func LoadStore(kv *versioned.KV, defaultID *id.ID, grp *cyclic.Group) (*Store, error) { +func LoadStore(kv *versioned.KV, defaultID *id.ID, grp *cyclic.Group, srh SentRequestHandler) (*Store, error) { kv = kv.Prefix(storePrefix) s := &Store{ @@ -75,6 +78,7 @@ func LoadStore(kv *versioned.KV, defaultID *id.ID, grp *cyclic.Group) (*Store, e sentByID: make(map[authIdentity]*SentRequest), previousNegotiations: make(map[id.ID]struct{}), defaultID: defaultID, + srh: srh, } var requestList []requestDisk @@ -122,6 +126,7 @@ func LoadStore(kv *versioned.KV, defaultID *id.ID, grp *cyclic.Group) (*Store, e } s.sentByID[sr.getAuthID()] = sr + s.srh.Add(sr) case Receive: rr, err := loadReceivedRequest(kv, partner, myID) if err != nil { @@ -180,63 +185,45 @@ func (s *Store) save() error { func (s *Store) AddSent(partner, myID *id.ID, partnerHistoricalPubKey, myPrivKey, myPubKey *cyclic.Int, sidHPrivA *sidh.PrivateKey, sidHPubA *sidh.PublicKey, - fp format.Fingerprint) error { + fp format.Fingerprint) (*SentRequest, error) { s.mux.Lock() defer s.mux.Unlock() aid := makeAuthIdentity(partner, myID) if _, ok := s.sentByID[aid]; ok { - return errors.Errorf("Cannot make new sentRequest for partner "+ + return nil, errors.Errorf("Cannot make new sentRequest for partner "+ "%s, one already exists", partner) } - sr := &SentRequest{ - kv: s.kv, - partner: partner, - partnerHistoricalPubKey: partnerHistoricalPubKey, - myPrivKey: myPrivKey, - myPubKey: myPubKey, - mySidHPubKeyA: sidHPubA, - mySidHPrivKeyA: sidHPrivA, - fingerprint: fp, - } + sr, err := newSentRequest(s.kv, partner, myID, partnerHistoricalPubKey, myPrivKey, + myPubKey, sidHPrivA, sidHPubA, fp) - if err := sr.save(); err != nil { - jww.FATAL.Panicf("Failed to save Sent Request for partner %s", partner) + if err != nil { + return nil, err } - return nil + s.sentByID[sr.getAuthID()] = sr + s.srh.Add(sr) + + return sr, nil } -func (s *Store) AddReceived(c contact.Contact, key *sidh.PublicKey) error { +func (s *Store) AddReceived(myID *id.ID, c contact.Contact, key *sidh.PublicKey) error { s.mux.Lock() defer s.mux.Unlock() - jww.DEBUG.Printf("AddReceived new contact: %s", c.ID) - if _, ok := s.receivedByID[*c.ID]; ok { - return errors.Errorf("Cannot add contact for partner "+ - "%s, one already exists", c.ID) - } + jww.DEBUG.Printf("AddReceived new contact: %s with %s", c.ID, myID) - if err := util.StoreContact(s.kv, c); err != nil { - jww.FATAL.Panicf("Failed to save contact for partner %s", c.ID.String()) - } + aih := makeAuthIdentity(c.ID, myID) - storeKey := util.MakeSIDHPublicKeyKey(c.ID) - if err := util.StoreSIDHPublicKey(s.kv, key, storeKey); err != nil { - jww.FATAL.Panicf("Failed to save contact pubKey for partner %s", - c.ID.String()) + if _, ok := s.receivedByID[aih]; ok { + return errors.Errorf("Cannot add contact for partner "+ + "%s, one already exists", c.ID) } - r := &ReceivedRequest{ - rt: Receive, - sent: nil, - partner: &c, - theirSidHPubKeyA: key, - mux: sync.Mutex{}, - } + r := newReceivedRequest(s.kv, myID, c, key) - s.receivedByID[*c.ID] = r + s.receivedByID[r.aid] = r if err := s.save(); err != nil { jww.FATAL.Panicf("Failed to save Sent Request Map after adding "+ "partner %s", c.ID) @@ -245,73 +232,19 @@ func (s *Store) AddReceived(c contact.Contact, key *sidh.PublicKey) error { return nil } -// GetAllReceived returns all pending received contact receivedByID from storage. -func (s *Store) GetAllReceived() []contact.Contact { - s.mux.RLock() - defer s.mux.RUnlock() - cList := make([]contact.Contact, 0, len(s.receivedByID)) - for key := range s.receivedByID { - r := s.receivedByID[key] - if r.rt == Receive { - cList = append(cList, *r.partner) - } - } - return cList -} - -// GetFingerprint can return either a private key or a sentRequest if the -// fingerprint is found. If it returns a sentRequest, then it takes the lock to -// ensure there is only one operator at a time. The user of the API must release -// the lock by calling store.delete() or store.Failed() with the partner ID. -func (s *Store) GetFingerprint(fp format.Fingerprint) (FingerprintType, - *SentRequest, *cyclic.Int, error) { - - s.mux.RLock() - r, ok := s.sentByFingerprints[fp] - s.mux.RUnlock() - if !ok { - return 0, nil, nil, errors.Errorf("Fingerprint cannot be found: %v", fp) - } - - switch r.Type { - // If it is general, then just return the private key - case General: - return General, nil, r.PrivKey, nil - - // If it is specific, then take the request lock and return it - case Specific: - r.Request.mux.Lock() - // Check that the request still exists; it could have been deleted - // while the lock was taken - s.mux.RLock() - _, ok := s.receivedByID[*r.Request.sent.partner] - s.mux.RUnlock() - if !ok { - r.Request.mux.Unlock() - return 0, nil, nil, errors.Errorf("request associated with "+ - "fingerprint cannot be found: %s", fp) - } - // Return the request - return Specific, r.Request.sent, nil, nil - - default: - jww.WARN.Printf("Auth request message ignored due to unknown "+ - "fingerprint type %d on lookup; should be impossible", r.Type) - return 0, nil, nil, errors.New("Unknown fingerprint type") - } -} - // GetReceivedRequest returns the contact representing the partner request, if // it exists. If it returns, then it takes the lock to ensure that there is only // one operator at a time. The user of the API must release the lock by calling // store.delete() or store.Failed() with the partner ID. -func (s *Store) GetReceivedRequest(partner *id.ID) (contact.Contact, *sidh.PublicKey, error) { +func (s *Store) GetReceivedRequest(partner, myID *id.ID) (*ReceivedRequest, error) { + aid := makeAuthIdentity(partner, myID) + s.mux.RLock() - r, ok := s.receivedByID[*partner] + r, ok := s.receivedByID[aid] s.mux.RUnlock() if !ok { - return contact.Contact{}, nil, errors.Errorf("Received request not "+ + return nil, errors.Errorf("Received request not "+ "found: %s", partner) } @@ -321,71 +254,56 @@ func (s *Store) GetReceivedRequest(partner *id.ID) (contact.Contact, *sidh.Publi // Check that the request still exists; it could have been deleted while the // lock was taken s.mux.RLock() - _, ok = s.receivedByID[*partner] + _, ok = s.receivedByID[aid] s.mux.RUnlock() if !ok { r.mux.Unlock() - return contact.Contact{}, nil, errors.Errorf("Received request not "+ + return nil, errors.Errorf("Received request not "+ "found: %s", partner) } - return *r.partner, r.theirSidHPubKeyA, nil + return r, nil } // GetReceivedRequestData returns the contact representing the partner request // if it exists. It does not take the lock. It is only meant to return the // contact to an external API user. -func (s *Store) GetReceivedRequestData(partner *id.ID) (contact.Contact, error) { - s.mux.RLock() - r, ok := s.receivedByID[*partner] - s.mux.RUnlock() - - if !ok || r.partner == nil { - return contact.Contact{}, errors.Errorf("Received request not "+ - "found: %s", partner) +func (s *Store) GetReceivedRequestData(partner, myID *id.ID) (contact.Contact, error) { + if myID == nil { + myID = s.defaultID } - return *r.partner, nil -} + aid := makeAuthIdentity(partner, myID) -// GetRequest returns request with its type and data. The lock is not taken. -func (s *Store) GetRequest(partner *id.ID) (RequestType, *SentRequest, contact.Contact, error) { s.mux.RLock() - r, ok := s.receivedByID[*partner] + r, ok := s.receivedByID[aid] s.mux.RUnlock() if !ok { - return 0, nil, contact.Contact{}, errors.New(NoRequest) + return contact.Contact{}, errors.Errorf("Received request not "+ + "found: %s", partner) } - switch r.rt { - case Sent: - return Sent, r.sent, contact.Contact{}, nil - case Receive: - return Receive, nil, *r.partner, nil - default: - return 0, nil, contact.Contact{}, - errors.Errorf("invalid Tag: %d", r.rt) - } + return r.partner, nil } // Done is one of two calls after using a request. This one is to be used when // the use is unsuccessful. It will allow any thread waiting on access to // continue using the structure. // It does not return an error because an error is not handleable. -func (s *Store) Done(partner *id.ID) { +func (s *Store) Done(rr *ReceivedRequest) { s.mux.RLock() - r, ok := s.receivedByID[*partner] + r, ok := s.receivedByID[rr.aid] s.mux.RUnlock() + r.mux.Unlock() + if !ok { jww.ERROR.Panicf("Request cannot be finished, not "+ - "found: %s", partner) + "found: %s, %s", rr.partner, rr.myID) return } - - r.mux.Unlock() } // Delete is one of two calls after using a request. This one is to be used when