forked from TrueCloudLab/frostfs-s3-gw
132 lines
2.6 KiB
Go
132 lines
2.6 KiB
Go
|
package handler
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"crypto/ecdsa"
|
||
|
"math"
|
||
|
|
||
|
"github.com/minio/minio/neofs/api"
|
||
|
"github.com/minio/minio/neofs/pool"
|
||
|
"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"
|
||
|
"go.uber.org/zap"
|
||
|
)
|
||
|
|
||
|
type (
|
||
|
handler struct {
|
||
|
log *zap.Logger
|
||
|
cli pool.Client
|
||
|
uid refs.OwnerID
|
||
|
tkn *service.Token
|
||
|
key *ecdsa.PrivateKey
|
||
|
}
|
||
|
|
||
|
Params struct {
|
||
|
Cli pool.Client
|
||
|
Log *zap.Logger
|
||
|
Key *ecdsa.PrivateKey
|
||
|
}
|
||
|
|
||
|
queryParams struct {
|
||
|
key *ecdsa.PrivateKey
|
||
|
addr refs.Address
|
||
|
verb service.Token_Info_Verb
|
||
|
}
|
||
|
)
|
||
|
|
||
|
var _ api.Handler = (*handler)(nil)
|
||
|
|
||
|
func New(ctx context.Context, p Params) (api.Handler, error) {
|
||
|
var (
|
||
|
err error
|
||
|
uid refs.OwnerID
|
||
|
tkn *service.Token
|
||
|
)
|
||
|
|
||
|
switch {
|
||
|
case p.Key == nil:
|
||
|
return nil, errors.New("empty private key")
|
||
|
case p.Cli == nil:
|
||
|
return nil, errors.New("empty gRPC client")
|
||
|
case p.Log == nil:
|
||
|
return nil, errors.New("empty logger")
|
||
|
}
|
||
|
|
||
|
if uid, err = refs.NewOwnerID(&p.Key.PublicKey); err != nil {
|
||
|
return nil, errors.Wrap(err, "could not fetch OwnerID")
|
||
|
} else if tkn, err = generateToken(ctx, p.Cli, p.Key); err != nil {
|
||
|
return nil, errors.Wrap(err, "could not prepare session token")
|
||
|
}
|
||
|
|
||
|
return &handler{
|
||
|
uid: uid,
|
||
|
tkn: tkn,
|
||
|
key: p.Key,
|
||
|
log: p.Log,
|
||
|
cli: p.Cli,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func generateToken(ctx context.Context, cli pool.Client, 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))
|
||
|
|
||
|
conn, err := cli.GetConnection(ctx)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
creator, err := session.NewGRPCCreator(conn, 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
|
||
|
}
|