124 lines
2.6 KiB
Go
124 lines
2.6 KiB
Go
|
package pool
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"crypto/ecdsa"
|
||
|
"math"
|
||
|
|
||
|
"github.com/nspcc-dev/neofs-api-go/refs"
|
||
|
"github.com/nspcc-dev/neofs-api-go/service"
|
||
|
"github.com/nspcc-dev/neofs-api-go/session"
|
||
|
crypto "github.com/nspcc-dev/neofs-crypto"
|
||
|
"github.com/pkg/errors"
|
||
|
"google.golang.org/grpc"
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
queryParams struct {
|
||
|
key *ecdsa.PrivateKey
|
||
|
addr refs.Address
|
||
|
verb service.Token_Info_Verb
|
||
|
}
|
||
|
|
||
|
SessionParams struct {
|
||
|
Addr refs.Address
|
||
|
Conn *grpc.ClientConn
|
||
|
Verb service.Token_Info_Verb
|
||
|
}
|
||
|
)
|
||
|
|
||
|
func (p *pool) fetchToken(ctx context.Context, con *grpc.ClientConn) (*session.Token, error) {
|
||
|
p.Lock()
|
||
|
defer p.Unlock()
|
||
|
|
||
|
// if we had token for current connection - return it
|
||
|
if tkn, ok := p.tokens[con.Target()]; ok {
|
||
|
return tkn, nil
|
||
|
}
|
||
|
|
||
|
// try to generate token for connection
|
||
|
tkn, err := generateToken(ctx, con, p.key)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
p.tokens[con.Target()] = tkn
|
||
|
return tkn, nil
|
||
|
}
|
||
|
|
||
|
// SessionToken returns session token for connection
|
||
|
func (p *pool) SessionToken(ctx context.Context, params *SessionParams) (*service.Token, error) {
|
||
|
var (
|
||
|
err error
|
||
|
tkn *session.Token
|
||
|
)
|
||
|
|
||
|
if params.Conn == nil {
|
||
|
return nil, errors.New("empty connection")
|
||
|
} else if tkn, err = p.fetchToken(ctx, params.Conn); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return prepareToken(tkn, queryParams{
|
||
|
key: p.key,
|
||
|
addr: params.Addr,
|
||
|
verb: params.Verb,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// creates token using
|
||
|
func generateToken(ctx context.Context, con *grpc.ClientConn, key *ecdsa.PrivateKey) (*service.Token, error) {
|
||
|
owner, err := refs.NewOwnerID(&key.PublicKey)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
token := new(service.Token)
|
||
|
token.SetOwnerID(owner)
|
||
|
token.SetExpirationEpoch(math.MaxUint64)
|
||
|
token.SetOwnerKey(crypto.MarshalPublicKey(&key.PublicKey))
|
||
|
|
||
|
creator, err := session.NewGRPCCreator(con, key)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
res, err := creator.Create(ctx, token)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
token.SetID(res.GetID())
|
||
|
token.SetSessionKey(res.GetSessionKey())
|
||
|
|
||
|
return token, nil
|
||
|
}
|
||
|
|
||
|
func prepareToken(t *service.Token, p queryParams) (*service.Token, error) {
|
||
|
sig := make([]byte, len(t.Signature))
|
||
|
copy(sig, t.Signature)
|
||
|
|
||
|
token := &service.Token{
|
||
|
Token_Info: service.Token_Info{
|
||
|
ID: t.ID,
|
||
|
OwnerID: t.OwnerID,
|
||
|
Verb: t.Verb,
|
||
|
Address: t.Address,
|
||
|
TokenLifetime: t.TokenLifetime,
|
||
|
SessionKey: t.SessionKey,
|
||
|
OwnerKey: t.OwnerKey,
|
||
|
},
|
||
|
Signature: sig,
|
||
|
}
|
||
|
|
||
|
token.SetAddress(p.addr)
|
||
|
token.SetVerb(p.verb)
|
||
|
|
||
|
err := service.AddSignatureWithKey(p.key, service.NewSignedSessionToken(token))
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return token, nil
|
||
|
}
|