package session import ( "crypto/ecdsa" "github.com/nspcc-dev/neofs-api-go/v2/refs" "github.com/nspcc-dev/neofs-api-go/v2/session" v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature" "github.com/nspcc-dev/neofs-sdk-go/owner" "github.com/nspcc-dev/neofs-sdk-go/signature" sigutil "github.com/nspcc-dev/neofs-sdk-go/util/signature" ) // Token represents NeoFS API v2-compatible // session token. type Token session.SessionToken // NewTokenFromV2 wraps session.SessionToken message structure // into Token. // // Nil session.SessionToken converts to nil. func NewTokenFromV2(tV2 *session.SessionToken) *Token { return (*Token)(tV2) } // NewToken creates and returns blank Token. // // Defaults: // - body: nil; // - id: nil; // - ownerId: nil; // - sessionKey: nil; // - exp: 0; // - iat: 0; // - nbf: 0; func NewToken() *Token { return NewTokenFromV2(new(session.SessionToken)) } // ToV2 converts Token to session.SessionToken message structure. // // Nil Token converts to nil. func (t *Token) ToV2() *session.SessionToken { return (*session.SessionToken)(t) } func (t *Token) setBodyField(setter func(*session.SessionTokenBody)) { token := (*session.SessionToken)(t) body := token.GetBody() if body == nil { body = new(session.SessionTokenBody) token.SetBody(body) } setter(body) } // ID returns Token identifier. func (t *Token) ID() []byte { return (*session.SessionToken)(t). GetBody(). GetID() } // SetID sets Token identifier. func (t *Token) SetID(v []byte) { t.setBodyField(func(body *session.SessionTokenBody) { body.SetID(v) }) } // OwnerID returns Token's owner identifier. func (t *Token) OwnerID() *owner.ID { return owner.NewIDFromV2( (*session.SessionToken)(t). GetBody(). GetOwnerID(), ) } // SetOwnerID sets Token's owner identifier. func (t *Token) SetOwnerID(v *owner.ID) { t.setBodyField(func(body *session.SessionTokenBody) { body.SetOwnerID(v.ToV2()) }) } // SessionKey returns public key of the session // in a binary format. func (t *Token) SessionKey() []byte { return (*session.SessionToken)(t). GetBody(). GetSessionKey() } // SetSessionKey sets public key of the session // in a binary format. func (t *Token) SetSessionKey(v []byte) { t.setBodyField(func(body *session.SessionTokenBody) { body.SetSessionKey(v) }) } func (t *Token) setLifetimeField(f func(*session.TokenLifetime)) { t.setBodyField(func(body *session.SessionTokenBody) { lt := body.GetLifetime() if lt == nil { lt = new(session.TokenLifetime) body.SetLifetime(lt) } f(lt) }) } // Exp returns epoch number of the token expiration. func (t *Token) Exp() uint64 { return (*session.SessionToken)(t). GetBody(). GetLifetime(). GetExp() } // SetExp sets epoch number of the token expiration. func (t *Token) SetExp(exp uint64) { t.setLifetimeField(func(lt *session.TokenLifetime) { lt.SetExp(exp) }) } // Nbf returns starting epoch number of the token. func (t *Token) Nbf() uint64 { return (*session.SessionToken)(t). GetBody(). GetLifetime(). GetNbf() } // SetNbf sets starting epoch number of the token. func (t *Token) SetNbf(nbf uint64) { t.setLifetimeField(func(lt *session.TokenLifetime) { lt.SetNbf(nbf) }) } // Iat returns starting epoch number of the token. func (t *Token) Iat() uint64 { return (*session.SessionToken)(t). GetBody(). GetLifetime(). GetIat() } // SetIat sets the number of the epoch in which the token was issued. func (t *Token) SetIat(iat uint64) { t.setLifetimeField(func(lt *session.TokenLifetime) { lt.SetIat(iat) }) } // Sign calculates and writes signature of the Token data. // // Returns signature calculation errors. func (t *Token) Sign(key *ecdsa.PrivateKey) error { tV2 := (*session.SessionToken)(t) signedData := v2signature.StableMarshalerWrapper{ SM: tV2.GetBody(), } return sigutil.SignDataWithHandler(key, signedData, func(key, sig []byte) { tSig := tV2.GetSignature() if tSig == nil { tSig = new(refs.Signature) } tSig.SetKey(key) tSig.SetSign(sig) tV2.SetSignature(tSig) }) } // VerifySignature checks if token signature is // presented and valid. func (t *Token) VerifySignature() bool { tV2 := (*session.SessionToken)(t) signedData := v2signature.StableMarshalerWrapper{ SM: tV2.GetBody(), } return sigutil.VerifyDataWithSource(signedData, func() (key, sig []byte) { tSig := tV2.GetSignature() return tSig.GetKey(), tSig.GetSign() }) == nil } // Signature returns Token signature. func (t *Token) Signature() *signature.Signature { return signature.NewFromV2( (*session.SessionToken)(t). GetSignature(), ) } // SetContext sets context of the Token. // // Supported contexts: // - *ContainerContext. // // Resets context if it is not supported. func (t *Token) SetContext(v interface{}) { var cV2 session.SessionTokenContext switch c := v.(type) { case *ContainerContext: cV2 = c.ToV2() } t.setBodyField(func(body *session.SessionTokenBody) { body.SetContext(cV2) }) } // Context returns context of the Token. // // Supports same contexts as SetContext. // // Returns nil if context is not supported. func (t *Token) Context() interface{} { switch v := (*session.SessionToken)(t). GetBody(). GetContext(); c := v.(type) { default: return nil case *session.ContainerSessionContext: return ContainerContextFromV2(c) case *session.ObjectSessionContext: return ObjectContextFromV2(c) } } // GetContainerContext is a helper function that casts // Token context to ContainerContext. // // Returns nil if context is not a ContainerContext. func GetContainerContext(t *Token) *ContainerContext { c, _ := t.Context().(*ContainerContext) return c } // Marshal marshals Token into a protobuf binary form. func (t *Token) Marshal() ([]byte, error) { return (*session.SessionToken)(t). StableMarshal(nil) } // Unmarshal unmarshals protobuf binary representation of Token. func (t *Token) Unmarshal(data []byte) error { return (*session.SessionToken)(t). Unmarshal(data) } // MarshalJSON encodes Token to protobuf JSON format. func (t *Token) MarshalJSON() ([]byte, error) { return (*session.SessionToken)(t). MarshalJSON() } // UnmarshalJSON decodes Token from protobuf JSON format. func (t *Token) UnmarshalJSON(data []byte) error { return (*session.SessionToken)(t). UnmarshalJSON(data) }