Skip to content
Snippets Groups Projects
Select Git revision
  • edb401b212c28a07e78f83363a1446e36e2b1b27
  • release default
  • 11-22-implement-kv-interface-defined-in-collectiveversionedkvgo
  • master protected
  • XX-4688/DbEncoding
  • hotfix/update
  • @XX-4682/Files
  • hotfix/XX-4655
  • dev protected
  • project/HavenNotifications
  • XX-4602/SilentMessageType
  • jono/npmTest
  • wasmTest2
  • XX-4461/FileUpload
  • XX-4505/blockuser
  • XX-4441
  • Jakub/Emoji-CI-Test
  • testing/websockets
  • fastReg
  • fast-registration
  • NewHostPool
  • v0.3.22
  • v0.3.21
  • v0.3.20
  • v0.3.18
  • v0.3.17
  • v0.3.16
  • v0.3.15
  • v0.3.14
  • v0.3.13
  • v0.3.12
  • v0.3.11
  • v0.3.10
  • v0.3.9
  • v0.3.8
  • v0.3.7
  • v0.3.6
  • v0.3.5
  • v0.3.4
  • 812b395df518ce096d01d5292596ca26f8fe92d9c4487ddfa515e190a51aa1a1
  • 76ba08e2dfa1798412a265404fa271840b52c035869111fce8e8cdb23a036a5a
41 results

indexedDbList_test.go

Blame
  • previousNegotiations.go 8.83 KiB
    ////////////////////////////////////////////////////////////////////////////////
    // Copyright © 2020 xx network SEZC                                           //
    //                                                                            //
    // Use of this source code is governed by a license that can be found in the  //
    // LICENSE file                                                               //
    ////////////////////////////////////////////////////////////////////////////////
    
    ////////////////////////////////////////////////////////////////////////////////
    // 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 (
    	"bytes"
    	"encoding/binary"
    	jww "github.com/spf13/jwalterweatherman"
    	"gitlab.com/elixxir/client/storage/versioned"
    	"gitlab.com/elixxir/crypto/e2e/auth"
    	"gitlab.com/xx_network/primitives/id"
    	"gitlab.com/xx_network/primitives/netTime"
    	"strings"
    )
    
    const (
    	negotiationPartnersKey                = "NegotiationPartners"
    	negotiationPartnersVersion            = 0
    	negotiationFingerprintsKeyPrefix      = "NegotiationFingerprints/"
    	currentNegotiationFingerprintsVersion = 0
    )
    
    // AddIfNew adds a new negotiation fingerprint if it is new.
    // If the partner does not exist, it will add it and the new fingerprint and
    // return newFingerprint = true, latest = 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
    // 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.
    func (s *Store) AddIfNew(partner *id.ID, negotiationFingerprint []byte) (
    	newFingerprint, latest bool) {
    	s.mux.Lock()
    	defer s.mux.Unlock()
    
    	// If the partner does not exist, add it to the list and store a new
    	// fingerprint to storage
    	_, exists := s.previousNegotiations[*partner]
    	if !exists {
    		s.previousNegotiations[*partner] = struct{}{}
    
    		// Save fingerprint to storage
    		err := s.saveNegotiationFingerprints(partner, negotiationFingerprint)
    		if err != nil {
    			jww.FATAL.Panicf("Failed to save negotiation fingerprints for "+
    				"partner %s: %+v", partner, err)
    		}
    
    		// Save partner list to storage
    		err = s.savePreviousNegotiations()
    		if err != nil {
    			jww.FATAL.Panicf(
    				"Failed to save negotiation partners %s: %+v", partner, err)
    		}
    
    		newFingerprint = true
    		latest = true
    
    		return
    	}
    
    	// Get the fingerprint list from storage
    	fingerprints, err := s.loadNegotiationFingerprints(partner)
    	if err != nil {
    		jww.FATAL.Panicf("Failed to load negotiation fingerprints for "+
    			"partner %s: %+v", partner, err)
    	}
    
    	// If the partner does exist and the fingerprint exists, then make no
    	// changes to the list
    	for i, fp := range fingerprints {
    		if bytes.Equal(fp, negotiationFingerprint) {
    			newFingerprint = false
    
    			// Latest = true if it is the last fingerprint in the list
    			latest = i == len(fingerprints)-1
    
    			return
    		}
    	}
    
    	// If the partner does exist and the fingerprint does not exist, then add
    	// the fingerprint to the list as latest
    	fingerprints = append(fingerprints, negotiationFingerprint)
    	err = s.saveNegotiationFingerprints(partner, fingerprints...)
    	if err != nil {
    		jww.FATAL.Panicf("Failed to save negotiation fingerprints for "+
    			"partner %s: %+v", partner, err)
    	}
    
    	newFingerprint = true
    	latest = true
    
    	return
    }
    
    // deletePreviousNegotiationPartner removes the partner, its fingerprints, and
    // its confirmations from memory and storage.
    func (s *Store) deletePreviousNegotiationPartner(partner *id.ID) error {
    
    	// Do nothing if the partner does not exist
    	if _, exists := s.previousNegotiations[*partner]; !exists {
    		return nil
    	}
    
    	// Delete partner from memory
    	delete(s.previousNegotiations, *partner)
    
    	// Delete partner from storage and return an error
    	err := s.savePreviousNegotiations()
    	if err != nil {
    		return err
    	}
    
    	// Check if fingerprints exist
    	fingerprints, err := s.loadNegotiationFingerprints(partner)
    
    	// If fingerprints exist for this partner, delete them from storage and any
    	// accompanying confirmations
    	if err == nil {
    		// Delete the fingerprint list from storage but do not return the error
    		// until after attempting to delete the confirmations
    		err = s.kv.Delete(makeNegotiationFingerprintsKey(partner),
    			currentNegotiationFingerprintsVersion)
    
    		// Delete all confirmations from storage
    		for _, fp := range fingerprints {
    			// Ignore the error since confirmations rarely exist
    			_ = s.deleteConfirmation(partner, fp)
    		}
    	}
    
    	// Return any error from loading or deleting fingerprints
    	return err
    }
    
    // savePreviousNegotiations saves the list of previousNegotiations partners to
    // storage.
    func (s *Store) savePreviousNegotiations() error {
    	obj := &versioned.Object{
    		Version:   negotiationPartnersVersion,
    		Timestamp: netTime.Now(),
    		Data:      marshalPreviousNegotiations(s.previousNegotiations),
    	}
    
    	return s.kv.Set(negotiationPartnersKey, negotiationPartnersVersion, obj)
    }
    
    // newOrLoadPreviousNegotiations loads the list of previousNegotiations partners
    // from storage.
    func (s *Store) newOrLoadPreviousNegotiations() (map[id.ID]struct{}, error) {
    	obj, err := s.kv.Get(negotiationPartnersKey, negotiationPartnersVersion)
    	if err != nil {
    		if strings.Contains(err.Error(), "object not found") {
    			return make(map[id.ID]struct{}), nil
    		}
    		return nil, err
    	}
    
    	return unmarshalPreviousNegotiations(obj.Data), nil
    }
    
    // marshalPreviousNegotiations marshals the list of partners into a byte slice.
    func marshalPreviousNegotiations(partners map[id.ID]struct{}) []byte {
    	buff := bytes.NewBuffer(nil)
    	buff.Grow(8 + (len(partners) * id.ArrIDLen))
    
    	// Write number of partners to buffer
    	b := make([]byte, 8)
    	binary.LittleEndian.PutUint64(b, uint64(len(partners)))
    	buff.Write(b)
    
    	// Write each partner ID to buffer
    	for partner := range partners {
    		buff.Write(partner.Marshal())
    	}
    
    	return buff.Bytes()
    }
    
    // unmarshalPreviousNegotiations unmarshalls the marshalled byte slice into a
    // list of partner IDs.
    func unmarshalPreviousNegotiations(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
    }
    
    // saveNegotiationFingerprints saves the list of fingerprints for the given
    // partner to storage.
    func (s *Store) saveNegotiationFingerprints(
    	partner *id.ID, fingerprints ...[]byte) error {
    
    	obj := &versioned.Object{
    		Version:   currentNegotiationFingerprintsVersion,
    		Timestamp: netTime.Now(),
    		Data:      marshalNegotiationFingerprints(fingerprints...),
    	}
    
    	return s.kv.Set(makeNegotiationFingerprintsKey(partner),
    		currentNegotiationFingerprintsVersion, obj)
    }
    
    // loadNegotiationFingerprints loads the list of fingerprints for the given
    // partner from storage.
    func (s *Store) loadNegotiationFingerprints(partner *id.ID) ([][]byte, error) {
    	obj, err := s.kv.Get(makeNegotiationFingerprintsKey(partner),
    		currentNegotiationFingerprintsVersion)
    	if err != nil {
    		return nil, err
    	}
    
    	return unmarshalNegotiationFingerprints(obj.Data), nil
    }
    
    // marshalNegotiationFingerprints marshals the list of fingerprints into a byte
    // slice for storage.
    func marshalNegotiationFingerprints(fingerprints ...[]byte) []byte {
    	buff := bytes.NewBuffer(nil)
    	buff.Grow(8 + (len(fingerprints) * auth.NegotiationFingerprintLen))
    
    	// Write number of fingerprints to buffer
    	b := make([]byte, 8)
    	binary.LittleEndian.PutUint64(b, uint64(len(fingerprints)))
    	buff.Write(b)
    
    	for _, fp := range fingerprints {
    		// Write fingerprint to buffer
    		buff.Write(fp[:auth.NegotiationFingerprintLen])
    	}
    
    	return buff.Bytes()
    }
    
    // unmarshalNegotiationFingerprints unmarshalls the marshalled byte slice into a
    // list of fingerprints.
    func unmarshalNegotiationFingerprints(buf []byte) [][]byte {
    	buff := bytes.NewBuffer(buf)
    
    	listLen := binary.LittleEndian.Uint64(buff.Next(8))
    	fingerprints := make([][]byte, listLen)
    
    	for i := range fingerprints {
    		fingerprints[i] = make([]byte, auth.NegotiationFingerprintLen)
    		copy(fingerprints[i], buff.Next(auth.NegotiationFingerprintLen))
    	}
    
    	return fingerprints
    }
    
    // makeNegotiationFingerprintsKey generates the key used to load and store
    // negotiation fingerprints for the partner.
    func makeNegotiationFingerprintsKey(partner *id.ID) string {
    	return negotiationFingerprintsKeyPrefix + partner.String()
    }