meta: make a read-only version to enforce token immutability

This commit is contained in:
Michael Muré
2024-11-06 15:17:35 +01:00
parent cfb4446a05
commit 6aeb6a8b70
5 changed files with 54 additions and 8 deletions

View File

@@ -1,7 +1,6 @@
package meta package meta
import ( import (
"errors"
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
@@ -12,9 +11,9 @@ import (
"github.com/ipld/go-ipld-prime/printer" "github.com/ipld/go-ipld-prime/printer"
) )
var ErrUnsupported = errors.New("failure adding unsupported type to meta") var ErrUnsupported = fmt.Errorf("failure adding unsupported type to meta")
var ErrNotFound = errors.New("key-value not found in meta") var ErrNotFound = fmt.Errorf("key-value not found in meta")
// Meta is a container for meta key-value pairs in a UCAN token. // Meta is a container for meta key-value pairs in a UCAN token.
// This also serves as a way to construct the underlying IPLD data with minimum allocations and transformations, // This also serves as a way to construct the underlying IPLD data with minimum allocations and transformations,
@@ -160,6 +159,11 @@ func (m *Meta) String() string {
return buf.String() return buf.String()
} }
// ReadOnly returns a read-only version of Meta.
func (m *Meta) ReadOnly() ReadOnly {
return ReadOnly{m: m}
}
func fqtn(val any) string { func fqtn(val any) string {
var name string var name string

42
pkg/meta/readonly.go Normal file
View File

@@ -0,0 +1,42 @@
package meta
import (
"github.com/ipld/go-ipld-prime"
)
// ReadOnly wraps a Meta into a read-only facade.
type ReadOnly struct {
m *Meta
}
func (r ReadOnly) GetBool(key string) (bool, error) {
return r.m.GetBool(key)
}
func (r ReadOnly) GetString(key string) (string, error) {
return r.m.GetString(key)
}
func (r ReadOnly) GetInt64(key string) (int64, error) {
return r.m.GetInt64(key)
}
func (r ReadOnly) GetFloat64(key string) (float64, error) {
return r.m.GetFloat64(key)
}
func (r ReadOnly) GetBytes(key string) ([]byte, error) {
return r.m.GetBytes(key)
}
func (r ReadOnly) GetNode(key string) (ipld.Node, error) {
return r.m.GetNode(key)
}
func (r ReadOnly) Equals(other ReadOnly) bool {
return r.m.Equals(other.m)
}
func (r ReadOnly) String() string {
return r.m.String()
}

View File

@@ -142,8 +142,8 @@ func (t *Token) Nonce() []byte {
} }
// Meta returns the Token's metadata. // Meta returns the Token's metadata.
func (t *Token) Meta() *meta.Meta { func (t *Token) Meta() meta.ReadOnly {
return t.meta return t.meta.ReadOnly()
} }
// NotBefore returns the time at which the Token becomes "active". // NotBefore returns the time at which the Token becomes "active".

View File

@@ -17,7 +17,7 @@ type Token interface {
// Issuer returns the did.DID representing the Token's issuer. // Issuer returns the did.DID representing the Token's issuer.
Issuer() did.DID Issuer() did.DID
// Meta returns the Token's metadata. // Meta returns the Token's metadata.
Meta() *meta.Meta Meta() meta.ReadOnly
} }
type Marshaller interface { type Marshaller interface {

View File

@@ -71,8 +71,8 @@ func (t *Token) Nonce() []byte {
} }
// Meta returns the Token's metadata. // Meta returns the Token's metadata.
func (t *Token) Meta() *meta.Meta { func (t *Token) Meta() meta.ReadOnly {
return t.meta return t.meta.ReadOnly()
} }
// Expiration returns the time at which the Token expires. // Expiration returns the time at which the Token expires.