diff --git a/pkg/services/session/storage/executor.go b/pkg/services/session/storage/executor.go new file mode 100644 index 0000000000..435070dfd2 --- /dev/null +++ b/pkg/services/session/storage/executor.go @@ -0,0 +1,54 @@ +package storage + +import ( + "context" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + + "github.com/google/uuid" + "github.com/mr-tron/base58" + "github.com/nspcc-dev/neofs-api-go/v2/session" + crypto "github.com/nspcc-dev/neofs-crypto" + "github.com/pkg/errors" +) + +func (s *TokenStore) Create(ctx context.Context, body *session.CreateRequestBody) (*session.CreateResponseBody, error) { + ownerBytes, err := body.GetOwnerID().StableMarshal(nil) + if err != nil { + panic(err) + } + + uid, err := uuid.NewRandom() + if err != nil { + return nil, errors.Wrap(err, "could not generate token ID") + } + + uidBytes, err := uid.MarshalBinary() + if err != nil { + return nil, errors.Wrap(err, "could not marshal token ID") + } + + sk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, err + } + + s.mtx.Lock() + s.tokens[key{ + tokenID: base58.Encode(uidBytes), + ownerID: base58.Encode(ownerBytes), + }] = &PrivateToken{ + sessionKey: sk, + exp: body.GetExpiration(), + } + s.mtx.Unlock() + + res := new(session.CreateResponseBody) + res.SetID(uidBytes) + res.SetSessionKey( + crypto.MarshalPublicKey(&sk.PublicKey), + ) + + return res, nil +} diff --git a/pkg/services/session/storage/storage.go b/pkg/services/session/storage/storage.go new file mode 100644 index 0000000000..ec671349c4 --- /dev/null +++ b/pkg/services/session/storage/storage.go @@ -0,0 +1,51 @@ +package storage + +import ( + "errors" + "sync" + + "github.com/mr-tron/base58" + "github.com/nspcc-dev/neofs-api-go/v2/refs" +) + +type key struct { + tokenID string + ownerID string +} + +type TokenStore struct { + mtx *sync.RWMutex + + tokens map[key]*PrivateToken +} + +var ErrNotFound = errors.New("private token not found") + +// New creates, initializes and returns a new TokenStore instance. +// +// The elements of the instance are stored in the map. +func New() *TokenStore { + return &TokenStore{ + mtx: new(sync.RWMutex), + tokens: make(map[key]*PrivateToken), + } +} + +// Get returns private token corresponding to the given identifiers. +// +// Returns nil is there is no element in storage. +func (s *TokenStore) Get(ownerID *refs.OwnerID, tokenID []byte) *PrivateToken { + ownerBytes, err := ownerID.StableMarshal(nil) + if err != nil { + panic(err) + } + + s.mtx.RLock() + t := s.tokens[key{ + tokenID: base58.Encode(tokenID), + ownerID: base58.Encode(ownerBytes), + }] + s.mtx.RUnlock() + + return t +} diff --git a/pkg/services/session/storage/types.go b/pkg/services/session/storage/types.go new file mode 100644 index 0000000000..0332a05129 --- /dev/null +++ b/pkg/services/session/storage/types.go @@ -0,0 +1,17 @@ +package storage + +import ( + "crypto/ecdsa" +) + +// PrivateToken represents private session info. +type PrivateToken struct { + sessionKey *ecdsa.PrivateKey + + exp uint64 +} + +// SessionKey returns the private session key. +func (t *PrivateToken) SessionKey() *ecdsa.PrivateKey { + return t.sessionKey +}