token/read: add the usual collections of readers

This commit is contained in:
Michael Muré
2024-10-01 14:17:02 +02:00
parent f3a5209cec
commit 1b7059c029
2 changed files with 73 additions and 46 deletions

View File

@@ -94,19 +94,7 @@ func DecodeReader[T Tokener](r io.Reader, decFn codec.Decoder) (T, error) {
// An error is returned if the conversion fails, or if the resulting
// Tokener is invalid.
func FromDagCbor[T Tokener](b []byte) (T, error) {
undef := *new(T)
node, err := ipld.Decode(b, dagcbor.Decode)
if err != nil {
return undef, err
}
tkn, err := fromIPLD[T](node)
if err != nil {
return undef, err
}
return tkn, nil
return Decode[T](b, dagcbor.Decode)
}
// FromDagCborReader is the same as FromDagCbor, but accept an io.Reader.
@@ -132,20 +120,9 @@ func FromDagJsonReader[T Tokener](r io.Reader) (T, error) {
// An error is returned if the conversion fails, or if the resulting
// Tokener is invalid.
func FromIPLD[T Tokener](node datamodel.Node) (T, error) {
undef := *new(T)
tkn, err := fromIPLD[T](node)
if err != nil {
return undef, err
}
return tkn, nil
}
func fromIPLD[T Tokener](node datamodel.Node) (T, error) {
zero := *new(T)
info, err := inspect(node)
info, err := Inspect(node)
if err != nil {
return zero, err
}
@@ -154,7 +131,7 @@ func fromIPLD[T Tokener](node datamodel.Node) (T, error) {
return zero, errors.New("data doesn't match the expected type")
}
tokenPayloadNode, err := info.SigPayloadNode.LookupByString(info.Tag)
tokenPayloadNode, err := info.sigPayloadNode.LookupByString(info.Tag)
if err != nil {
return zero, err
}
@@ -215,7 +192,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")
}
data, err := ipld.Encode(info.SigPayloadNode, dagcbor.Encode)
data, err := ipld.Encode(info.sigPayloadNode, dagcbor.Encode)
if err != nil {
return zero, err
}
@@ -335,50 +312,50 @@ func FindTag(node datamodel.Node) (string, error) {
return "", fmt.Errorf("no token tag found")
}
type info struct {
type Info struct {
Tag string
Signature []byte
SigPayloadNode datamodel.Node
sigPayloadNode datamodel.Node // private, we don't want to expose that
VarsigHeader []byte
}
func inspect(node datamodel.Node) (info, error) {
var res info
func Inspect(node datamodel.Node) (Info, error) {
var res Info
signatureNode, err := node.LookupByIndex(0)
if err != nil {
return info{}, err
return Info{}, err
}
res.Signature, err = signatureNode.AsBytes()
if err != nil {
return info{}, err
return Info{}, err
}
res.SigPayloadNode, err = node.LookupByIndex(1)
res.sigPayloadNode, err = node.LookupByIndex(1)
if err != nil {
return info{}, err
return Info{}, err
}
it := res.SigPayloadNode.MapIterator()
it := res.sigPayloadNode.MapIterator()
foundVarsigHeader := false
foundTokenPayload := false
i := 0
for !it.Done() {
if i >= 2 {
return info{}, fmt.Errorf("expected two and only two fields in SigPayload")
return Info{}, fmt.Errorf("expected two and only two fields in SigPayload")
}
i++
k, v, err := it.Next()
if err != nil {
return info{}, err
return Info{}, err
}
key, err := k.AsString()
if err != nil {
return info{}, err
return Info{}, err
}
switch {
@@ -386,24 +363,24 @@ func inspect(node datamodel.Node) (info, error) {
foundVarsigHeader = true
res.VarsigHeader, err = v.AsBytes()
if err != nil {
return info{}, err
return Info{}, err
}
case strings.HasPrefix(key, UCANTagPrefix):
foundTokenPayload = true
res.Tag = key
default:
return info{}, fmt.Errorf("unexpected key type %q", key)
return Info{}, fmt.Errorf("unexpected key type %q", key)
}
}
if i != 2 {
return info{}, fmt.Errorf("expected two and only two fields in SigPayload: %d", i)
return Info{}, fmt.Errorf("expected two and only two fields in SigPayload: %d", i)
}
if !foundVarsigHeader {
return info{}, errors.New("failed to find VarsigHeader field")
return Info{}, errors.New("failed to find VarsigHeader field")
}
if !foundTokenPayload {
return info{}, errors.New("failed to find TokenPayload field")
return Info{}, errors.New("failed to find TokenPayload field")
}
return res, nil

View File

@@ -2,20 +2,70 @@ package tokens
import (
"fmt"
"io"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/codec"
"github.com/ipld/go-ipld-prime/codec/dagcbor"
"github.com/ipld/go-ipld-prime/codec/dagjson"
"github.com/ipld/go-ipld-prime/datamodel"
"github.com/ucan-wg/go-ucan/tokens/delegation"
"github.com/ucan-wg/go-ucan/tokens/internal/envelope"
)
func FromDagCbor(b []byte) (any, error) {
node, err := ipld.Decode(b, dagcbor.Decode)
// Decode unmarshals the input data using the format specified by the
// provided codec.Decoder into an arbitrary UCAN token.
// An error is returned if the conversion fails, or if the resulting
// Token is invalid.
// Supported and returned types are:
// - delegation.Token
func Decode(b []byte, decFn codec.Decoder) (any, error) {
node, err := ipld.Decode(b, decFn)
if err != nil {
return nil, err
}
return fromIPLD(node)
}
// DecodeReader is the same as Decode, but accept an io.Reader.
func DecodeReader(r io.Reader, decFn codec.Decoder) (any, error) {
node, err := ipld.DecodeStreaming(r, decFn)
if err != nil {
return nil, err
}
return fromIPLD(node)
}
// FromDagCbor unmarshals an arbitrary DagCbor encoded UCAN token.
// An error is returned if the conversion fails, or if the resulting
// Token is invalid.
// Supported and returned types are:
// - delegation.Token
func FromDagCbor(b []byte) (any, error) {
return Decode(b, dagcbor.Decode)
}
// FromDagCborReader is the same as FromDagCbor, but accept an io.Reader.
func FromDagCborReader(r io.Reader) (any, error) {
return DecodeReader(r, dagcbor.Decode)
}
// FromDagCbor unmarshals an arbitrary DagJson encoded UCAN token.
// An error is returned if the conversion fails, or if the resulting
// Token is invalid.
// Supported and returned types are:
// - delegation.Token
func FromDagJson(b []byte) (any, error) {
return Decode(b, dagjson.Decode)
}
// FromDagJsonReader is the same as FromDagJson, but accept an io.Reader.
func FromDagJsonReader(r io.Reader) (any, error) {
return DecodeReader(r, dagjson.Decode)
}
func fromIPLD(node datamodel.Node) (any, error) {
tag, err := envelope.FindTag(node)
if err != nil {
return nil, err