diff --git a/token/delegation/delegation.go b/token/delegation/delegation.go index 599f773..b2a2ca2 100644 --- a/token/delegation/delegation.go +++ b/token/delegation/delegation.go @@ -153,6 +153,24 @@ func (t *Token) Expiration() *time.Time { return t.expiration } +// IsValidNow verifies that the token can be used at the current time, based on expiration or "not before" fields. +// This does NOT do any other kind of verifications. +func (t *Token) IsValidNow() bool { + return t.IsValidAt(time.Now()) +} + +// IsValidNow verifies that the token can be used at the given time, based on expiration or "not before" fields. +// This does NOT do any other kind of verifications. +func (t *Token) IsValidAt(ti time.Time) bool { + if t.expiration == nil && ti.After(*t.expiration) { + return false + } + if t.notBefore != nil && ti.Before(*t.notBefore) { + return false + } + return true +} + func (t *Token) validate() error { var errs error diff --git a/token/interface.go b/token/interface.go index 3079f56..6865ccf 100644 --- a/token/interface.go +++ b/token/interface.go @@ -2,11 +2,11 @@ package token import ( "io" + "time" "github.com/ipfs/go-cid" "github.com/ipld/go-ipld-prime/codec" "github.com/libp2p/go-libp2p/core/crypto" - "github.com/ucan-wg/go-ucan/did" "github.com/ucan-wg/go-ucan/pkg/meta" ) @@ -18,6 +18,19 @@ type Token interface { Issuer() did.DID // Meta returns the Token's metadata. Meta() meta.ReadOnly + // TODO: not sure we actually need that interface + + // IsValidNow verifies that the token can be used at the current time, based on expiration or "not before" fields. + // This does NOT do any other kind of verifications. + IsValidNow() bool + // IsValidNow verifies that the token can be used at the given time, based on expiration or "not before" fields. + // This does NOT do any other kind of verifications. + IsValidAt(t time.Time) bool + + // // Issuer returns the did.DID representing the Token's issuer. + // Issuer() did.DID + // // Meta returns the Token's metadata. + // Meta() *meta.Meta } type Marshaller interface { diff --git a/token/internal/envelope/ipld.go b/token/internal/envelope/ipld.go index 6e9533d..5b6ed15 100644 --- a/token/internal/envelope/ipld.go +++ b/token/internal/envelope/ipld.go @@ -187,8 +187,7 @@ func FromIPLD[T Tokener](node datamodel.Node) (T, error) { return zero, errors.New("the VarsigHeader key type doesn't match the issuer's key type") } - // TODO: this re-encode the payload! Is there a less wasteful way? - + // TODO: can we use the already serialized CBOR data here, instead of encoding again the payload? data, err := ipld.Encode(info.sigPayloadNode, dagcbor.Encode) if err != nil { return zero, err diff --git a/token/invocation/invocation.go b/token/invocation/invocation.go index c48121f..4b67dfa 100644 --- a/token/invocation/invocation.go +++ b/token/invocation/invocation.go @@ -18,6 +18,7 @@ import ( "github.com/ucan-wg/go-ucan/pkg/args" "github.com/ucan-wg/go-ucan/pkg/command" "github.com/ucan-wg/go-ucan/pkg/meta" + "github.com/ucan-wg/go-ucan/token/delegation" "github.com/ucan-wg/go-ucan/token/internal/nonce" "github.com/ucan-wg/go-ucan/token/internal/parse" ) @@ -33,11 +34,12 @@ type Token struct { // The Command command command.Command - // The Command's Arguments + // The Command's arguments arguments *args.Args - // Delegations that prove the chain of authority + // CIDs of the delegation.Token that prove the chain of authority + // They need to form a strictly linear chain, and being ordered starting from the root Delegation (issued by the Subject), + // in a strict sequence where the aud of the previous Delegation matches the iss of the next Delegation. proof []cid.Cid - // Arbitrary Metadata meta *meta.Meta @@ -98,6 +100,22 @@ func New(iss, sub did.DID, cmd command.Command, prf []cid.Cid, opts ...Option) ( return &tkn, nil } +type DelegationLoader interface { + GetDelegation(cid cid.Cid) (*delegation.Token, error) +} + +func (t *Token) ExecutionAllowed(loader DelegationLoader) bool { + return t.executionAllowed(loader, t.arguments) +} + +func (t *Token) ExecutionAllowedWithArgsHook(loader DelegationLoader, hook func(*args.Args) *args.Args) bool { + return t.executionAllowed(loader, hook(t.arguments)) +} + +func (t *Token) executionAllowed(loader DelegationLoader, arguments *args.Args) bool { + panic("TODO") +} + // Issuer returns the did.DID representing the Token's issuer. func (t *Token) Issuer() did.DID { return t.issuer @@ -157,6 +175,21 @@ func (t *Token) Cause() *cid.Cid { return t.cause } +// IsValidNow verifies that the token can be used at the current time, based on expiration or "not before" fields. +// This does NOT do any other kind of verifications. +func (t *Token) IsValidNow() bool { + return t.IsValidAt(time.Now()) +} + +// IsValidNow verifies that the token can be used at the given time, based on expiration or "not before" fields. +// This does NOT do any other kind of verifications. +func (t *Token) IsValidAt(ti time.Time) bool { + if t.expiration == nil && ti.After(*t.expiration) { + return false + } + return true +} + func (t *Token) validate() error { var errs error