diff --git a/pkg/token/bearer.go b/pkg/token/bearer.go new file mode 100644 index 00000000..13e26cbd --- /dev/null +++ b/pkg/token/bearer.go @@ -0,0 +1,109 @@ +package token + +import ( + "crypto/ecdsa" + "errors" + + "github.com/nspcc-dev/neofs-api-go/pkg/acl/eacl" + "github.com/nspcc-dev/neofs-api-go/pkg/owner" + "github.com/nspcc-dev/neofs-api-go/util/signature" + "github.com/nspcc-dev/neofs-api-go/v2/acl" + "github.com/nspcc-dev/neofs-api-go/v2/refs" + v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature" +) + +type BearerToken struct { + token acl.BearerToken +} + +func (b BearerToken) ToV2() *acl.BearerToken { + return &b.token +} + +func (b *BearerToken) SetLifetime(exp, nbf, iat uint64) { + body := b.token.GetBody() + if body == nil { + body = new(acl.BearerTokenBody) + } + + lt := new(acl.TokenLifetime) + lt.SetExp(exp) + lt.SetNbf(nbf) + lt.SetIat(iat) + + body.SetLifetime(lt) + b.token.SetBody(body) +} + +func (b *BearerToken) SetEACLTable(table *eacl.Table) { + body := b.token.GetBody() + if body == nil { + body = new(acl.BearerTokenBody) + } + + body.SetEACL(table.ToV2()) + b.token.SetBody(body) +} + +func (b *BearerToken) SetOwner(id *owner.ID) { + body := b.token.GetBody() + if body == nil { + body = new(acl.BearerTokenBody) + } + + body.SetOwnerID(id.ToV2()) + b.token.SetBody(body) +} + +func (b *BearerToken) SignToken(key *ecdsa.PrivateKey) error { + err := sanityCheck(b) + if err != nil { + return err + } + + signWrapper := v2signature.StableMarshalerWrapper{SM: b.token.GetBody()} + return signature.SignDataWithHandler(key, signWrapper, func(key []byte, sig []byte) { + bearerSignature := new(refs.Signature) + bearerSignature.SetKey(key) + bearerSignature.SetSign(sig) + b.token.SetSignature(bearerSignature) + }) +} + +func NewBearerToken() *BearerToken { + b := new(BearerToken) + b.token = acl.BearerToken{} + b.token.SetBody(new(acl.BearerTokenBody)) + + return b +} + +func NewBearerTokenFromV2(v2 *acl.BearerToken) *BearerToken { + if v2 == nil { + v2 = new(acl.BearerToken) + } + + return &BearerToken{ + token: *v2, + } +} + +// sanityCheck if bearer token is ready to be issued +func sanityCheck(b *BearerToken) error { + switch { + case b == nil: + return errors.New("bearer token is not set") + case b.token.GetBody() == nil: + return errors.New("bearer token body is not set") + case b.token.GetBody().GetLifetime() == nil: + return errors.New("bearer token lifetime is not set") + case b.token.GetBody().GetEACL() == nil: + return errors.New("bearer token EACL table is not set") + case b.token.GetBody().GetOwnerID() == nil: + return errors.New("bearer token owner is not set") + } + + // consider checking EACL sanity there, lifetime correctness, etc. + + return nil +}