From 22265a9f038d27ea283cdf753feb46094b38cfe4 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Wed, 29 Apr 2020 12:39:41 +0300 Subject: [PATCH] session: refactor token store This commit: * changes the set and signatures of TokenStore interface methods; * adds unit test for map storage. --- session/service.go | 21 ------------- session/store.go | 70 +++++++++++++------------------------------ session/store_test.go | 34 ++++++++++++++++++++- session/types.go | 20 +++++++++++++ 4 files changed, 74 insertions(+), 71 deletions(-) diff --git a/session/service.go b/session/service.go index 915abb4..ecbd6f5 100644 --- a/session/service.go +++ b/session/service.go @@ -13,27 +13,6 @@ type ( KeyStore interface { Get(ctx context.Context, id refs.OwnerID) ([]*ecdsa.PublicKey, error) } - - // TokenStore is a PToken storage manipulation interface. - TokenStore interface { - // New returns new token with specified parameters. - New(p TokenParams) PrivateToken - - // Fetch tries to fetch a token with specified id. - Fetch(id TokenID) PrivateToken - - // Remove removes token with id from store. - Remove(id TokenID) - } - - // TokenParams contains params to create new PToken. - TokenParams struct { - FirstEpoch uint64 - LastEpoch uint64 - Address Address - OwnerID OwnerID - Verb Verb - } ) // NewInitRequest returns new initialization CreateRequest from passed Token. diff --git a/session/store.go b/session/store.go index 440fbb5..fa3ca69 100644 --- a/session/store.go +++ b/session/store.go @@ -1,16 +1,11 @@ package session import ( - "crypto/ecdsa" "crypto/elliptic" - "crypto/rand" "sync" - - "github.com/nspcc-dev/neofs-api-go/refs" - crypto "github.com/nspcc-dev/neofs-crypto" ) -type simpleStore struct { +type mapTokenStore struct { *sync.RWMutex tokens map[TokenID]PrivateToken @@ -21,61 +16,38 @@ func defaultCurve() elliptic.Curve { return elliptic.P256() } -// NewSimpleStore creates simple token storage -func NewSimpleStore() TokenStore { - return &simpleStore{ +// NewMapTokenStore creates new PrivateTokenStore instance. +// +// The elements of the instance are stored in the map. +func NewMapTokenStore() PrivateTokenStore { + return &mapTokenStore{ RWMutex: new(sync.RWMutex), tokens: make(map[TokenID]PrivateToken), } } -// New returns new token with specified parameters. -func (s *simpleStore) New(p TokenParams) PrivateToken { - tid, err := refs.NewUUID() - if err != nil { - return nil - } - - key, err := ecdsa.GenerateKey(defaultCurve(), rand.Reader) - if err != nil { - return nil - } - - if p.FirstEpoch > p.LastEpoch || p.OwnerID.Empty() { - return nil - } - - token := new(Token) - token.SetID(tid) - token.SetOwnerID(p.OwnerID) - token.SetVerb(p.Verb) - token.SetAddress(p.Address) - token.SetCreationEpoch(p.FirstEpoch) - token.SetExpirationEpoch(p.LastEpoch) - token.SetSessionKey(crypto.MarshalPublicKey(&key.PublicKey)) - - t := &pToken{ - sessionKey: key, - } - +// Store adds passed token to the map. +// +// Resulting error is always nil. +func (s *mapTokenStore) Store(id TokenID, token PrivateToken) error { s.Lock() - s.tokens[tid] = t + s.tokens[id] = token s.Unlock() - return t + return nil } -// Fetch tries to fetch a token with specified id. -func (s *simpleStore) Fetch(id TokenID) PrivateToken { +// Fetch returns the map element corresponding to the given key. +// +// Returns ErrPrivateTokenNotFound is there is no element in map. +func (s *mapTokenStore) Fetch(id TokenID) (PrivateToken, error) { s.RLock() defer s.RUnlock() - return s.tokens[id] -} + t, ok := s.tokens[id] + if !ok { + return nil, ErrPrivateTokenNotFound + } -// Remove removes token with id from store. -func (s *simpleStore) Remove(id TokenID) { - s.Lock() - delete(s.tokens, id) - s.Unlock() + return t, nil } diff --git a/session/store_test.go b/session/store_test.go index f51fb18..37d742e 100644 --- a/session/store_test.go +++ b/session/store_test.go @@ -1,3 +1,35 @@ package session -// TODO: write unit tests +import ( + "testing" + + "github.com/nspcc-dev/neofs-api-go/refs" + "github.com/stretchr/testify/require" +) + +func TestMapTokenStore(t *testing.T) { + // create new private token + pToken, err := NewPrivateToken() + require.NoError(t, err) + + // create map token store + s := NewMapTokenStore() + + // create new storage key + id, err := refs.NewUUID() + require.NoError(t, err) + + // ascertain that there is no record for the key + _, err = s.Fetch(id) + require.EqualError(t, err, ErrPrivateTokenNotFound.Error()) + + // save private token record + require.NoError(t, s.Store(id, pToken)) + + // fetch private token by the key + res, err := s.Fetch(id) + require.NoError(t, err) + + // ascertain that returned token equals to initial + require.Equal(t, pToken, res) +} diff --git a/session/types.go b/session/types.go index e7e4b2a..bacc770 100644 --- a/session/types.go +++ b/session/types.go @@ -33,6 +33,26 @@ type PrivateToken interface { Sign([]byte) ([]byte, error) } +// PrivateTokenSource is an interface of private token storage with read access. +type PrivateTokenSource interface { + // Fetch must return the storage record corresponding to the passed key. + // + // Resulting error must be ErrPrivateTokenNotFound if there is no corresponding record. + Fetch(TokenID) (PrivateToken, error) +} + +// PrivateTokenStore is an interface of the storage of private tokens addressable by TokenID. +type PrivateTokenStore interface { + PrivateTokenSource + + // Store must save passed private token in the storage under the given key. + // + // Resulting error must be nil if private token was stored successfully. + Store(TokenID, PrivateToken) error +} + +const ErrPrivateTokenNotFound = internal.Error("private token not found") + const ( // ErrWrongFirstEpoch is raised when passed Token contains wrong first epoch. // First epoch is an epoch since token is valid