diff --git a/commands/customer/add.go b/commands/customer/add.go new file mode 100644 index 0000000..716144a --- /dev/null +++ b/commands/customer/add.go @@ -0,0 +1,13 @@ +//go:build !codegen + +package customer + +import ( + "github.com/fil-forge/libforge/commands" + "github.com/fil-forge/ucantone/binding" + "github.com/fil-forge/ucantone/ucan/command" +) + +type AddOK = commands.Unit + +var Add = binding.Bind[*AddArguments, *AddOK](command.MustParse("/customer/add")) diff --git a/commands/customer/cbor_gen.go b/commands/customer/cbor_gen.go new file mode 100644 index 0000000..e45ceca --- /dev/null +++ b/commands/customer/cbor_gen.go @@ -0,0 +1,295 @@ +//go:build !codegen + +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package customer + +import ( + "fmt" + "io" + "math" + "sort" + + cid "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf +var _ = cid.Undef +var _ = math.E +var _ = sort.Sort + +func (t *AddArguments) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + fieldCount := 4 + + if t.ExternalAccount == nil { + fieldCount-- + } + + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { + return err + } + + // t.Details (map[string]string) (map) + if len("details") > 8192 { + return xerrors.Errorf("Value in field \"details\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("details"))); err != nil { + return err + } + if _, err := cw.WriteString(string("details")); err != nil { + return err + } + + { + if len(t.Details) > 4096 { + return xerrors.Errorf("cannot marshal t.Details map too large") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajMap, uint64(len(t.Details))); err != nil { + return err + } + + keys := make([]string, 0, len(t.Details)) + for k := range t.Details { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + v := t.Details[k] + + if len(k) > 8192 { + return xerrors.Errorf("Value in field k was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(k))); err != nil { + return err + } + if _, err := cw.WriteString(string(k)); err != nil { + return err + } + + if len(v) > 8192 { + return xerrors.Errorf("Value in field v was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(v))); err != nil { + return err + } + if _, err := cw.WriteString(string(v)); err != nil { + return err + } + + } + } + + // t.Product (did.DID) (struct) + if len("product") > 8192 { + return xerrors.Errorf("Value in field \"product\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("product"))); err != nil { + return err + } + if _, err := cw.WriteString(string("product")); err != nil { + return err + } + + if err := t.Product.MarshalCBOR(cw); err != nil { + return err + } + + // t.Customer (did.DID) (struct) + if len("customer") > 8192 { + return xerrors.Errorf("Value in field \"customer\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("customer"))); err != nil { + return err + } + if _, err := cw.WriteString(string("customer")); err != nil { + return err + } + + if err := t.Customer.MarshalCBOR(cw); err != nil { + return err + } + + // t.ExternalAccount (string) (string) + if t.ExternalAccount != nil { + + if len("externalAccount") > 8192 { + return xerrors.Errorf("Value in field \"externalAccount\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("externalAccount"))); err != nil { + return err + } + if _, err := cw.WriteString(string("externalAccount")); err != nil { + return err + } + + if t.ExternalAccount == nil { + if _, err := cw.Write(cbg.CborNull); err != nil { + return err + } + } else { + if len(*t.ExternalAccount) > 8192 { + return xerrors.Errorf("Value in field t.ExternalAccount was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.ExternalAccount))); err != nil { + return err + } + if _, err := cw.WriteString(string(*t.ExternalAccount)); err != nil { + return err + } + } + } + return nil +} + +func (t *AddArguments) UnmarshalCBOR(r io.Reader) (err error) { + *t = AddArguments{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("AddArguments: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 15) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.Details (map[string]string) (map) + case "details": + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajMap { + return fmt.Errorf("expected a map (major type 5)") + } + if extra > 4096 { + return fmt.Errorf("t.Details: map too large") + } + + t.Details = make(map[string]string, extra) + + for i, l := 0, int(extra); i < l; i++ { + + var k string + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + k = string(sval) + } + + var v string + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + v = string(sval) + } + + t.Details[k] = v + + } + // t.Product (did.DID) (struct) + case "product": + + { + + if err := t.Product.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Product: %w", err) + } + + } + // t.Customer (did.DID) (struct) + case "customer": + + { + + if err := t.Customer.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Customer: %w", err) + } + + } + // t.ExternalAccount (string) (string) + case "externalAccount": + + { + b, err := cr.ReadByte() + if err != nil { + return err + } + if b != cbg.CborNull[0] { + if err := cr.UnreadByte(); err != nil { + return err + } + + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.ExternalAccount = (*string)(&sval) + } + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} diff --git a/commands/customer/gen/main.go b/commands/customer/gen/main.go new file mode 100644 index 0000000..e4a20fb --- /dev/null +++ b/commands/customer/gen/main.go @@ -0,0 +1,41 @@ +//go:generate go run -tags codegen . + +package main + +import ( + "os" + + jsg "github.com/alanshaw/dag-json-gen" + "github.com/fil-forge/libforge/commands/customer" + cbg "github.com/whyrusleeping/cbor-gen" +) + +const buildTag = "//go:build !codegen\n\n" + +func tag(path string) { + data, err := os.ReadFile(path) + if err != nil { + panic(err) + } + if err := os.WriteFile(path, append([]byte(buildTag), data...), 0644); err != nil { + panic(err) + } +} + +func main() { + models := []any{ + customer.AddArguments{}, + } + const ( + cborFile = "../cbor_gen.go" + jsonFile = "../json_gen.go" + ) + if err := cbg.WriteMapEncodersToFile(cborFile, "customer", models...); err != nil { + panic(err) + } + if err := jsg.WriteMapEncodersToFile(jsonFile, "customer", models...); err != nil { + panic(err) + } + tag(cborFile) + tag(jsonFile) +} diff --git a/commands/customer/json_gen.go b/commands/customer/json_gen.go new file mode 100644 index 0000000..1b3f74a --- /dev/null +++ b/commands/customer/json_gen.go @@ -0,0 +1,304 @@ +//go:build !codegen + +// Code generated by github.com/alanshaw/dag-json-gen. DO NOT EDIT. + +package customer + +import ( + "errors" + "fmt" + "io" + "math" + "sort" + + jsg "github.com/alanshaw/dag-json-gen" + cid "github.com/ipfs/go-cid" +) + +var _ = cid.Undef +var _ = math.E +var _ = sort.Sort +var _ = errors.Is + +func (t *AddArguments) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + written := 0 + + // t.Customer (did.DID) (struct) + if len("customer") > 8192 { + return fmt.Errorf("string in field \"customer\" was too long") + } + if err := jw.WriteString(string("customer")); err != nil { + return fmt.Errorf("writing string for field \"customer\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Customer.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Customer: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Details (map[string]string) (map) + if len("details") > 8192 { + return fmt.Errorf("string in field \"details\" was too long") + } + if err := jw.WriteString(string("details")); err != nil { + return fmt.Errorf("writing string for field \"details\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + { + if len(t.Details) > 4096 { + return fmt.Errorf("cannot marshal t.Details map too large") + } + + if err := jw.WriteObjectOpen(); err != nil { + return fmt.Errorf("writing object open for field t.Details: %w", err) + } + + keys := make([]string, 0, len(t.Details)) + for k := range t.Details { + keys = append(keys, k) + } + sort.Strings(keys) + for i, k := range keys { + if i > 0 { + if err := jw.WriteComma(); err != nil { + return fmt.Errorf("writing comma for field t.Details: %w", err) + } + } + v := t.Details[k] + if len(k) > 8192 { + return fmt.Errorf("string in field k was too long") + } + if err := jw.WriteString(string(k)); err != nil { + return fmt.Errorf("writing string for field k: %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return fmt.Errorf("writing colon for field t.Details: %w", err) + } + + if len(v) > 8192 { + return fmt.Errorf("string in field v was too long") + } + if err := jw.WriteString(string(v)); err != nil { + return fmt.Errorf("writing string for field v: %w", err) + } + } + if err := jw.WriteObjectClose(); err != nil { + return fmt.Errorf("writing object close for field t.Details: %w", err) + } + } + + written++ + if t.ExternalAccount != nil { + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + } + + // t.ExternalAccount (string) (string) + if t.ExternalAccount != nil { + if len("externalAccount") > 8192 { + return fmt.Errorf("string in field \"externalAccount\" was too long") + } + if err := jw.WriteString(string("externalAccount")); err != nil { + return fmt.Errorf("writing string for field \"externalAccount\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if t.ExternalAccount == nil { + if err := jw.WriteNull(); err != nil { + return fmt.Errorf("writing null for field t.ExternalAccount: %w", err) + } + } else { + if len(*t.ExternalAccount) > 8192 { + return fmt.Errorf("string in field t.ExternalAccount was too long") + } + if err := jw.WriteString(string(*t.ExternalAccount)); err != nil { + return fmt.Errorf("writing string for field t.ExternalAccount: %w", err) + } + } + written++ + } + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Product (did.DID) (struct) + if len("product") > 8192 { + return fmt.Errorf("string in field \"product\" was too long") + } + if err := jw.WriteString(string("product")); err != nil { + return fmt.Errorf("writing string for field \"product\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Product.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Product: %w", err) + } + written++ + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *AddArguments) UnmarshalDagJSON(r io.Reader) (err error) { + *t = AddArguments{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for AddArguments: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for AddArguments: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for AddArguments: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field AddArguments: string too large") + } + return fmt.Errorf("reading string for field AddArguments: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field AddArguments: %w", err) + } + switch name { + + // t.Customer (did.DID) (struct) + case "customer": + + if err := t.Customer.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Customer: %w", err) + } + + // t.Details (map[string]string) (map) + case "details": + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for field t.Details: %w", err) + } + + t.Details = map[string]string{} + + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for field t.Details: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for field t.Details: %w", err) + } + } else { + for i, l := 0, 8192; i < l; i++ { + var k string + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field k: string too long") + } + return fmt.Errorf("reading string for field k: %w", err) + } + k = string(sval) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field t.Details: %w", err) + } + var v string + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field v: string too long") + } + return fmt.Errorf("reading string for field v: %w", err) + } + v = string(sval) + } + t.Details[k] = v + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field t.Details: %w", err) + } + if close { + break + } + } + } + + // t.ExternalAccount (string) (string) + case "externalAccount": + { + sval, err := jr.ReadStringOrNull(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string or null for field t.ExternalAccount: string too long") + } + return fmt.Errorf("reading string or null for field t.ExternalAccount: %w", err) + } + if sval != nil { + t.ExternalAccount = (*string)(sval) + } + } + + // t.Product (did.DID) (struct) + case "product": + + if err := t.Product.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Product: %w", err) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for AddArguments: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field AddArguments: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for AddArguments") + } + } + } + + return nil +} diff --git a/commands/customer/types.go b/commands/customer/types.go new file mode 100644 index 0000000..5c29857 --- /dev/null +++ b/commands/customer/types.go @@ -0,0 +1,17 @@ +package customer + +import ( + "github.com/fil-forge/ucantone/did" +) + +type AddArguments struct { + // DID of the customer account e.g. `did:mailto:agent` + Customer did.DID `cborgen:"customer" dagjsongen:"customer"` + // Opaque identifier representing an account in the payment system + // e.g. Stripe customer ID (stripe:cus_9s6XKzkNRiz8i3) + ExternalAccount *string `cborgen:"externalAccount,omitempty" dagjsongen:"externalAccount,omitempty"` + // Unique identifier of the product a.k.a plan. + Product did.DID `cborgen:"product" dagjsongen:"product"` + // Misc customer details + Details map[string]string `cborgen:"details" dagjsongen:"details"` +} diff --git a/commands/s3/bucket/cbor_gen.go b/commands/s3/bucket/cbor_gen.go new file mode 100644 index 0000000..cb7caff --- /dev/null +++ b/commands/s3/bucket/cbor_gen.go @@ -0,0 +1,1129 @@ +//go:build !codegen + +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package bucket + +import ( + "fmt" + "io" + "math" + "sort" + + cid "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf +var _ = cid.Undef +var _ = math.E +var _ = sort.Sort + +func (t *CreateArguments) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{161}); err != nil { + return err + } + + // t.Request (s3.Request) (struct) + if len("request") > 8192 { + return xerrors.Errorf("Value in field \"request\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("request"))); err != nil { + return err + } + if _, err := cw.WriteString(string("request")); err != nil { + return err + } + + if err := t.Request.MarshalCBOR(cw); err != nil { + return err + } + return nil +} + +func (t *CreateArguments) UnmarshalCBOR(r io.Reader) (err error) { + *t = CreateArguments{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("CreateArguments: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 7) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.Request (s3.Request) (struct) + case "request": + + { + + if err := t.Request.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Request: %w", err) + } + + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} +func (t *DeleteArguments) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{161}); err != nil { + return err + } + + // t.Request (s3.Request) (struct) + if len("request") > 8192 { + return xerrors.Errorf("Value in field \"request\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("request"))); err != nil { + return err + } + if _, err := cw.WriteString(string("request")); err != nil { + return err + } + + if err := t.Request.MarshalCBOR(cw); err != nil { + return err + } + return nil +} + +func (t *DeleteArguments) UnmarshalCBOR(r io.Reader) (err error) { + *t = DeleteArguments{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("DeleteArguments: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 7) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.Request (s3.Request) (struct) + case "request": + + { + + if err := t.Request.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Request: %w", err) + } + + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} +func (t *ListArguments) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{161}); err != nil { + return err + } + + // t.Request (s3.Request) (struct) + if len("request") > 8192 { + return xerrors.Errorf("Value in field \"request\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("request"))); err != nil { + return err + } + if _, err := cw.WriteString(string("request")); err != nil { + return err + } + + if err := t.Request.MarshalCBOR(cw); err != nil { + return err + } + return nil +} + +func (t *ListArguments) UnmarshalCBOR(r io.Reader) (err error) { + *t = ListArguments{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("ListArguments: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 7) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.Request (s3.Request) (struct) + case "request": + + { + + if err := t.Request.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Request: %w", err) + } + + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} +func (t *InfoArguments) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{162}); err != nil { + return err + } + + // t.Name (string) (string) + if len("name") > 8192 { + return xerrors.Errorf("Value in field \"name\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("name"))); err != nil { + return err + } + if _, err := cw.WriteString(string("name")); err != nil { + return err + } + + if len(t.Name) > 8192 { + return xerrors.Errorf("Value in field t.Name was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Name))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.Name)); err != nil { + return err + } + + // t.AccessKey (did.DID) (struct) + if len("accessKey") > 8192 { + return xerrors.Errorf("Value in field \"accessKey\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("accessKey"))); err != nil { + return err + } + if _, err := cw.WriteString(string("accessKey")); err != nil { + return err + } + + if err := t.AccessKey.MarshalCBOR(cw); err != nil { + return err + } + return nil +} + +func (t *InfoArguments) UnmarshalCBOR(r io.Reader) (err error) { + *t = InfoArguments{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("InfoArguments: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 9) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.Name (string) (string) + case "name": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.Name = string(sval) + } + // t.AccessKey (did.DID) (struct) + case "accessKey": + + { + + if err := t.AccessKey.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.AccessKey: %w", err) + } + + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} +func (t *InfoOK) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{163}); err != nil { + return err + } + + // t.ID (did.DID) (struct) + if len("id") > 8192 { + return xerrors.Errorf("Value in field \"id\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("id"))); err != nil { + return err + } + if _, err := cw.WriteString(string("id")); err != nil { + return err + } + + if err := t.ID.MarshalCBOR(cw); err != nil { + return err + } + + // t.Delegations (s3.ProofSet) (struct) + if len("delegations") > 8192 { + return xerrors.Errorf("Value in field \"delegations\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("delegations"))); err != nil { + return err + } + if _, err := cw.WriteString(string("delegations")); err != nil { + return err + } + + if err := t.Delegations.MarshalCBOR(cw); err != nil { + return err + } + + // t.Permissions (s3.PermissionSet) (struct) + if len("permissions") > 8192 { + return xerrors.Errorf("Value in field \"permissions\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("permissions"))); err != nil { + return err + } + if _, err := cw.WriteString(string("permissions")); err != nil { + return err + } + + if err := t.Permissions.MarshalCBOR(cw); err != nil { + return err + } + return nil +} + +func (t *InfoOK) UnmarshalCBOR(r io.Reader) (err error) { + *t = InfoOK{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("InfoOK: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 11) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.ID (did.DID) (struct) + case "id": + + { + + if err := t.ID.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.ID: %w", err) + } + + } + // t.Delegations (s3.ProofSet) (struct) + case "delegations": + + { + + if err := t.Delegations.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Delegations: %w", err) + } + + } + // t.Permissions (s3.PermissionSet) (struct) + case "permissions": + + { + + if err := t.Permissions.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Permissions: %w", err) + } + + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} +func (t *ListOK) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{164}); err != nil { + return err + } + + // t.Owner (bucket.Owner) (struct) + if len("owner") > 8192 { + return xerrors.Errorf("Value in field \"owner\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("owner"))); err != nil { + return err + } + if _, err := cw.WriteString(string("owner")); err != nil { + return err + } + + if err := t.Owner.MarshalCBOR(cw); err != nil { + return err + } + + // t.Prefix (string) (string) + if len("prefix") > 8192 { + return xerrors.Errorf("Value in field \"prefix\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("prefix"))); err != nil { + return err + } + if _, err := cw.WriteString(string("prefix")); err != nil { + return err + } + + if len(t.Prefix) > 8192 { + return xerrors.Errorf("Value in field t.Prefix was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Prefix))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.Prefix)); err != nil { + return err + } + + // t.Buckets ([]bucket.Bucket) (slice) + if len("buckets") > 8192 { + return xerrors.Errorf("Value in field \"buckets\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("buckets"))); err != nil { + return err + } + if _, err := cw.WriteString(string("buckets")); err != nil { + return err + } + + if len(t.Buckets) > 8192 { + return xerrors.Errorf("Slice value in field t.Buckets was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Buckets))); err != nil { + return err + } + for _, v := range t.Buckets { + if err := v.MarshalCBOR(cw); err != nil { + return err + } + + } + + // t.ContinuationToken (string) (string) + if len("continuationToken") > 8192 { + return xerrors.Errorf("Value in field \"continuationToken\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("continuationToken"))); err != nil { + return err + } + if _, err := cw.WriteString(string("continuationToken")); err != nil { + return err + } + + if len(t.ContinuationToken) > 8192 { + return xerrors.Errorf("Value in field t.ContinuationToken was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.ContinuationToken))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.ContinuationToken)); err != nil { + return err + } + return nil +} + +func (t *ListOK) UnmarshalCBOR(r io.Reader) (err error) { + *t = ListOK{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("ListOK: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 17) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.Owner (bucket.Owner) (struct) + case "owner": + + { + + if err := t.Owner.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Owner: %w", err) + } + + } + // t.Prefix (string) (string) + case "prefix": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.Prefix = string(sval) + } + // t.Buckets ([]bucket.Bucket) (slice) + case "buckets": + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + + if extra > 8192 { + return fmt.Errorf("t.Buckets: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Buckets = make([]Bucket, extra) + } + + for i := 0; i < int(extra); i++ { + { + var maj byte + var extra uint64 + var err error + _ = maj + _ = extra + _ = err + + { + + if err := t.Buckets[i].UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Buckets[i]: %w", err) + } + + } + + } + } + // t.ContinuationToken (string) (string) + case "continuationToken": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.ContinuationToken = string(sval) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} +func (t *Bucket) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{164}); err != nil { + return err + } + + // t.ARN (string) (string) + if len("arn") > 8192 { + return xerrors.Errorf("Value in field \"arn\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("arn"))); err != nil { + return err + } + if _, err := cw.WriteString(string("arn")); err != nil { + return err + } + + if len(t.ARN) > 8192 { + return xerrors.Errorf("Value in field t.ARN was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.ARN))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.ARN)); err != nil { + return err + } + + // t.Name (string) (string) + if len("name") > 8192 { + return xerrors.Errorf("Value in field \"name\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("name"))); err != nil { + return err + } + if _, err := cw.WriteString(string("name")); err != nil { + return err + } + + if len(t.Name) > 8192 { + return xerrors.Errorf("Value in field t.Name was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Name))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.Name)); err != nil { + return err + } + + // t.Region (string) (string) + if len("region") > 8192 { + return xerrors.Errorf("Value in field \"region\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("region"))); err != nil { + return err + } + if _, err := cw.WriteString(string("region")); err != nil { + return err + } + + if len(t.Region) > 8192 { + return xerrors.Errorf("Value in field t.Region was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Region))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.Region)); err != nil { + return err + } + + // t.CreationDate (string) (string) + if len("creationDate") > 8192 { + return xerrors.Errorf("Value in field \"creationDate\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("creationDate"))); err != nil { + return err + } + if _, err := cw.WriteString(string("creationDate")); err != nil { + return err + } + + if len(t.CreationDate) > 8192 { + return xerrors.Errorf("Value in field t.CreationDate was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.CreationDate))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.CreationDate)); err != nil { + return err + } + return nil +} + +func (t *Bucket) UnmarshalCBOR(r io.Reader) (err error) { + *t = Bucket{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("Bucket: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 12) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.ARN (string) (string) + case "arn": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.ARN = string(sval) + } + // t.Name (string) (string) + case "name": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.Name = string(sval) + } + // t.Region (string) (string) + case "region": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.Region = string(sval) + } + // t.CreationDate (string) (string) + case "creationDate": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.CreationDate = string(sval) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} +func (t *Owner) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{162}); err != nil { + return err + } + + // t.ID (string) (string) + if len("id") > 8192 { + return xerrors.Errorf("Value in field \"id\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("id"))); err != nil { + return err + } + if _, err := cw.WriteString(string("id")); err != nil { + return err + } + + if len(t.ID) > 8192 { + return xerrors.Errorf("Value in field t.ID was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.ID))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.ID)); err != nil { + return err + } + + // t.DisplayName (string) (string) + if len("displayName") > 8192 { + return xerrors.Errorf("Value in field \"displayName\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("displayName"))); err != nil { + return err + } + if _, err := cw.WriteString(string("displayName")); err != nil { + return err + } + + if len(t.DisplayName) > 8192 { + return xerrors.Errorf("Value in field t.DisplayName was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.DisplayName))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.DisplayName)); err != nil { + return err + } + return nil +} + +func (t *Owner) UnmarshalCBOR(r io.Reader) (err error) { + *t = Owner{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("Owner: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 11) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.ID (string) (string) + case "id": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.ID = string(sval) + } + // t.DisplayName (string) (string) + case "displayName": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.DisplayName = string(sval) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} diff --git a/commands/s3/bucket/create.go b/commands/s3/bucket/create.go new file mode 100644 index 0000000..98e4581 --- /dev/null +++ b/commands/s3/bucket/create.go @@ -0,0 +1,15 @@ +//go:build !codegen + +package bucket + +import ( + "github.com/fil-forge/libforge/commands/s3/request" + "github.com/fil-forge/ucantone/binding" + "github.com/fil-forge/ucantone/ucan/command" +) + +// Create is the `/s3/bucket/create` command. Ingot invokes it on Hilt to +// create a bucket and provision it with Sprue. It returns the same structure +// as `/s3/request/authorize` ([request.AuthorizeOK]): the new bucket DID and +// any delegations that now have access to it. +var Create = binding.Bind[*CreateArguments, *request.AuthorizeOK](command.MustParse("/s3/bucket/create")) diff --git a/commands/s3/bucket/delete.go b/commands/s3/bucket/delete.go new file mode 100644 index 0000000..7cadff6 --- /dev/null +++ b/commands/s3/bucket/delete.go @@ -0,0 +1,17 @@ +//go:build !codegen + +package bucket + +import ( + "github.com/fil-forge/libforge/commands" + "github.com/fil-forge/ucantone/binding" + "github.com/fil-forge/ucantone/ucan/command" +) + +// DeleteOK is the (empty) result of a successful `/s3/bucket/delete`. +type DeleteOK = commands.Unit + +// Delete is the `/s3/bucket/delete` command. Ingot invokes it on Hilt to +// delete an empty bucket, removing it from Hilt's stores and revoking any +// delegations that grant access to it. +var Delete = binding.Bind[*DeleteArguments, *DeleteOK](command.MustParse("/s3/bucket/delete")) diff --git a/commands/s3/bucket/gen/main.go b/commands/s3/bucket/gen/main.go new file mode 100644 index 0000000..2f464bc --- /dev/null +++ b/commands/s3/bucket/gen/main.go @@ -0,0 +1,48 @@ +//go:generate go run -tags codegen . + +package main + +import ( + "os" + + jsg "github.com/alanshaw/dag-json-gen" + "github.com/fil-forge/libforge/commands/s3/bucket" + cbg "github.com/whyrusleeping/cbor-gen" +) + +const buildTag = "//go:build !codegen\n\n" + +func tag(path string) { + data, err := os.ReadFile(path) + if err != nil { + panic(err) + } + if err := os.WriteFile(path, append([]byte(buildTag), data...), 0644); err != nil { + panic(err) + } +} + +func main() { + models := []any{ + bucket.CreateArguments{}, + bucket.DeleteArguments{}, + bucket.ListArguments{}, + bucket.InfoArguments{}, + bucket.InfoOK{}, + bucket.ListOK{}, + bucket.Bucket{}, + bucket.Owner{}, + } + const ( + cborFile = "../cbor_gen.go" + jsonFile = "../json_gen.go" + ) + if err := cbg.WriteMapEncodersToFile(cborFile, "bucket", models...); err != nil { + panic(err) + } + if err := jsg.WriteMapEncodersToFile(jsonFile, "bucket", models...); err != nil { + panic(err) + } + tag(cborFile) + tag(jsonFile) +} diff --git a/commands/s3/bucket/info.go b/commands/s3/bucket/info.go new file mode 100644 index 0000000..dabaa5d --- /dev/null +++ b/commands/s3/bucket/info.go @@ -0,0 +1,13 @@ +//go:build !codegen + +package bucket + +import ( + "github.com/fil-forge/ucantone/binding" + "github.com/fil-forge/ucantone/ucan/command" +) + +// Info is the `/s3/bucket/info` command. Ingot invokes it on Hilt to look up a +// bucket by global name, returning the bucket DID and the delegation chain +// from the bucket to the given access key. +var Info = binding.Bind[*InfoArguments, *InfoOK](command.MustParse("/s3/bucket/info")) diff --git a/commands/s3/bucket/json_gen.go b/commands/s3/bucket/json_gen.go new file mode 100644 index 0000000..25ddbcf --- /dev/null +++ b/commands/s3/bucket/json_gen.go @@ -0,0 +1,1160 @@ +//go:build !codegen + +// Code generated by github.com/alanshaw/dag-json-gen. DO NOT EDIT. + +package bucket + +import ( + "errors" + "fmt" + "io" + "math" + "sort" + + jsg "github.com/alanshaw/dag-json-gen" + cid "github.com/ipfs/go-cid" +) + +var _ = cid.Undef +var _ = math.E +var _ = sort.Sort +var _ = errors.Is + +func (t *CreateArguments) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + + // t.Request (s3.Request) (struct) + if len("request") > 8192 { + return fmt.Errorf("string in field \"request\" was too long") + } + if err := jw.WriteString(string("request")); err != nil { + return fmt.Errorf("writing string for field \"request\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Request.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Request: %w", err) + } + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *CreateArguments) UnmarshalDagJSON(r io.Reader) (err error) { + *t = CreateArguments{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for CreateArguments: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for CreateArguments: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for CreateArguments: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field CreateArguments: string too large") + } + return fmt.Errorf("reading string for field CreateArguments: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field CreateArguments: %w", err) + } + switch name { + + // t.Request (s3.Request) (struct) + case "request": + + if err := t.Request.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Request: %w", err) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for CreateArguments: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field CreateArguments: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for CreateArguments") + } + } + } + + return nil +} +func (t *DeleteArguments) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + + // t.Request (s3.Request) (struct) + if len("request") > 8192 { + return fmt.Errorf("string in field \"request\" was too long") + } + if err := jw.WriteString(string("request")); err != nil { + return fmt.Errorf("writing string for field \"request\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Request.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Request: %w", err) + } + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *DeleteArguments) UnmarshalDagJSON(r io.Reader) (err error) { + *t = DeleteArguments{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for DeleteArguments: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for DeleteArguments: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for DeleteArguments: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field DeleteArguments: string too large") + } + return fmt.Errorf("reading string for field DeleteArguments: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field DeleteArguments: %w", err) + } + switch name { + + // t.Request (s3.Request) (struct) + case "request": + + if err := t.Request.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Request: %w", err) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for DeleteArguments: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field DeleteArguments: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for DeleteArguments") + } + } + } + + return nil +} +func (t *ListArguments) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + + // t.Request (s3.Request) (struct) + if len("request") > 8192 { + return fmt.Errorf("string in field \"request\" was too long") + } + if err := jw.WriteString(string("request")); err != nil { + return fmt.Errorf("writing string for field \"request\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Request.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Request: %w", err) + } + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *ListArguments) UnmarshalDagJSON(r io.Reader) (err error) { + *t = ListArguments{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for ListArguments: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for ListArguments: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for ListArguments: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field ListArguments: string too large") + } + return fmt.Errorf("reading string for field ListArguments: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field ListArguments: %w", err) + } + switch name { + + // t.Request (s3.Request) (struct) + case "request": + + if err := t.Request.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Request: %w", err) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for ListArguments: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field ListArguments: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for ListArguments") + } + } + } + + return nil +} +func (t *InfoArguments) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + written := 0 + + // t.AccessKey (did.DID) (struct) + if len("accessKey") > 8192 { + return fmt.Errorf("string in field \"accessKey\" was too long") + } + if err := jw.WriteString(string("accessKey")); err != nil { + return fmt.Errorf("writing string for field \"accessKey\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.AccessKey.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.AccessKey: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Name (string) (string) + if len("name") > 8192 { + return fmt.Errorf("string in field \"name\" was too long") + } + if err := jw.WriteString(string("name")); err != nil { + return fmt.Errorf("writing string for field \"name\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.Name) > 8192 { + return fmt.Errorf("string in field t.Name was too long") + } + if err := jw.WriteString(string(t.Name)); err != nil { + return fmt.Errorf("writing string for field t.Name: %w", err) + } + written++ + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *InfoArguments) UnmarshalDagJSON(r io.Reader) (err error) { + *t = InfoArguments{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for InfoArguments: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for InfoArguments: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for InfoArguments: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field InfoArguments: string too large") + } + return fmt.Errorf("reading string for field InfoArguments: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field InfoArguments: %w", err) + } + switch name { + + // t.AccessKey (did.DID) (struct) + case "accessKey": + + if err := t.AccessKey.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.AccessKey: %w", err) + } + + // t.Name (string) (string) + case "name": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.Name: string too long") + } + return fmt.Errorf("reading string for field t.Name: %w", err) + } + t.Name = string(sval) + } + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for InfoArguments: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field InfoArguments: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for InfoArguments") + } + } + } + + return nil +} +func (t *InfoOK) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + written := 0 + + // t.Delegations (s3.ProofSet) (struct) + if len("delegations") > 8192 { + return fmt.Errorf("string in field \"delegations\" was too long") + } + if err := jw.WriteString(string("delegations")); err != nil { + return fmt.Errorf("writing string for field \"delegations\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Delegations.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Delegations: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.ID (did.DID) (struct) + if len("id") > 8192 { + return fmt.Errorf("string in field \"id\" was too long") + } + if err := jw.WriteString(string("id")); err != nil { + return fmt.Errorf("writing string for field \"id\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.ID.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.ID: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Permissions (s3.PermissionSet) (struct) + if len("permissions") > 8192 { + return fmt.Errorf("string in field \"permissions\" was too long") + } + if err := jw.WriteString(string("permissions")); err != nil { + return fmt.Errorf("writing string for field \"permissions\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Permissions.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Permissions: %w", err) + } + written++ + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *InfoOK) UnmarshalDagJSON(r io.Reader) (err error) { + *t = InfoOK{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for InfoOK: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for InfoOK: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for InfoOK: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field InfoOK: string too large") + } + return fmt.Errorf("reading string for field InfoOK: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field InfoOK: %w", err) + } + switch name { + + // t.Delegations (s3.ProofSet) (struct) + case "delegations": + + if err := t.Delegations.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Delegations: %w", err) + } + + // t.ID (did.DID) (struct) + case "id": + + if err := t.ID.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.ID: %w", err) + } + + // t.Permissions (s3.PermissionSet) (struct) + case "permissions": + + if err := t.Permissions.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Permissions: %w", err) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for InfoOK: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field InfoOK: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for InfoOK") + } + } + } + + return nil +} +func (t *ListOK) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + written := 0 + + // t.Buckets ([]bucket.Bucket) (slice) + if len("buckets") > 8192 { + return fmt.Errorf("string in field \"buckets\" was too long") + } + if err := jw.WriteString(string("buckets")); err != nil { + return fmt.Errorf("writing string for field \"buckets\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.Buckets) > 8192 { + return fmt.Errorf("slice value in field t.Buckets was too long") + } + + if err := jw.WriteArrayOpen(); err != nil { + return fmt.Errorf("writing array open for field t.Buckets: %w", err) + } + for i, v := range t.Buckets { + if i > 0 { + if err := jw.WriteComma(); err != nil { + return fmt.Errorf("writing comma for field t.Buckets: %w", err) + } + } + if err := v.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field v: %w", err) + } + } + if err := jw.WriteArrayClose(); err != nil { + return fmt.Errorf("writing array close for field t.Buckets: %w", err) + } + + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.ContinuationToken (string) (string) + if len("continuationToken") > 8192 { + return fmt.Errorf("string in field \"continuationToken\" was too long") + } + if err := jw.WriteString(string("continuationToken")); err != nil { + return fmt.Errorf("writing string for field \"continuationToken\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.ContinuationToken) > 8192 { + return fmt.Errorf("string in field t.ContinuationToken was too long") + } + if err := jw.WriteString(string(t.ContinuationToken)); err != nil { + return fmt.Errorf("writing string for field t.ContinuationToken: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Owner (bucket.Owner) (struct) + if len("owner") > 8192 { + return fmt.Errorf("string in field \"owner\" was too long") + } + if err := jw.WriteString(string("owner")); err != nil { + return fmt.Errorf("writing string for field \"owner\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Owner.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Owner: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Prefix (string) (string) + if len("prefix") > 8192 { + return fmt.Errorf("string in field \"prefix\" was too long") + } + if err := jw.WriteString(string("prefix")); err != nil { + return fmt.Errorf("writing string for field \"prefix\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.Prefix) > 8192 { + return fmt.Errorf("string in field t.Prefix was too long") + } + if err := jw.WriteString(string(t.Prefix)); err != nil { + return fmt.Errorf("writing string for field t.Prefix: %w", err) + } + written++ + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *ListOK) UnmarshalDagJSON(r io.Reader) (err error) { + *t = ListOK{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for ListOK: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for ListOK: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for ListOK: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field ListOK: string too large") + } + return fmt.Errorf("reading string for field ListOK: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field ListOK: %w", err) + } + switch name { + + // t.Buckets ([]bucket.Bucket) (slice) + case "buckets": + { + + if err := jr.ReadArrayOpen(); err != nil { + return fmt.Errorf("reading array open for field t.Buckets: %w", err) + } + + close, err := jr.PeekArrayClose() + if err != nil { + return fmt.Errorf("peeking array close for field t.Buckets: %w", err) + } + if close { + if err := jr.ReadArrayClose(); err != nil { + return fmt.Errorf("reading array close for field t.Buckets: %w", err) + } + + } else { + for i := 0; i < 8192; i++ { + item := make([]Bucket, 1) + + if err := item[0].UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling item[0]: %w", err) + } + + t.Buckets = append(t.Buckets, item[0]) + + close, err := jr.ReadArrayCloseOrComma() + if err != nil { + return fmt.Errorf("reading array close or comma for field t.Buckets: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("reading array for field t.Buckets: slice too large") + } + } + } + + } + + // t.ContinuationToken (string) (string) + case "continuationToken": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.ContinuationToken: string too long") + } + return fmt.Errorf("reading string for field t.ContinuationToken: %w", err) + } + t.ContinuationToken = string(sval) + } + + // t.Owner (bucket.Owner) (struct) + case "owner": + + if err := t.Owner.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Owner: %w", err) + } + + // t.Prefix (string) (string) + case "prefix": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.Prefix: string too long") + } + return fmt.Errorf("reading string for field t.Prefix: %w", err) + } + t.Prefix = string(sval) + } + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for ListOK: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field ListOK: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for ListOK") + } + } + } + + return nil +} +func (t *Bucket) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + written := 0 + + // t.ARN (string) (string) + if len("arn") > 8192 { + return fmt.Errorf("string in field \"arn\" was too long") + } + if err := jw.WriteString(string("arn")); err != nil { + return fmt.Errorf("writing string for field \"arn\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.ARN) > 8192 { + return fmt.Errorf("string in field t.ARN was too long") + } + if err := jw.WriteString(string(t.ARN)); err != nil { + return fmt.Errorf("writing string for field t.ARN: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.CreationDate (string) (string) + if len("creationDate") > 8192 { + return fmt.Errorf("string in field \"creationDate\" was too long") + } + if err := jw.WriteString(string("creationDate")); err != nil { + return fmt.Errorf("writing string for field \"creationDate\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.CreationDate) > 8192 { + return fmt.Errorf("string in field t.CreationDate was too long") + } + if err := jw.WriteString(string(t.CreationDate)); err != nil { + return fmt.Errorf("writing string for field t.CreationDate: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Name (string) (string) + if len("name") > 8192 { + return fmt.Errorf("string in field \"name\" was too long") + } + if err := jw.WriteString(string("name")); err != nil { + return fmt.Errorf("writing string for field \"name\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.Name) > 8192 { + return fmt.Errorf("string in field t.Name was too long") + } + if err := jw.WriteString(string(t.Name)); err != nil { + return fmt.Errorf("writing string for field t.Name: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Region (string) (string) + if len("region") > 8192 { + return fmt.Errorf("string in field \"region\" was too long") + } + if err := jw.WriteString(string("region")); err != nil { + return fmt.Errorf("writing string for field \"region\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.Region) > 8192 { + return fmt.Errorf("string in field t.Region was too long") + } + if err := jw.WriteString(string(t.Region)); err != nil { + return fmt.Errorf("writing string for field t.Region: %w", err) + } + written++ + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *Bucket) UnmarshalDagJSON(r io.Reader) (err error) { + *t = Bucket{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for Bucket: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for Bucket: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for Bucket: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field Bucket: string too large") + } + return fmt.Errorf("reading string for field Bucket: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field Bucket: %w", err) + } + switch name { + + // t.ARN (string) (string) + case "arn": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.ARN: string too long") + } + return fmt.Errorf("reading string for field t.ARN: %w", err) + } + t.ARN = string(sval) + } + + // t.CreationDate (string) (string) + case "creationDate": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.CreationDate: string too long") + } + return fmt.Errorf("reading string for field t.CreationDate: %w", err) + } + t.CreationDate = string(sval) + } + + // t.Name (string) (string) + case "name": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.Name: string too long") + } + return fmt.Errorf("reading string for field t.Name: %w", err) + } + t.Name = string(sval) + } + + // t.Region (string) (string) + case "region": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.Region: string too long") + } + return fmt.Errorf("reading string for field t.Region: %w", err) + } + t.Region = string(sval) + } + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for Bucket: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field Bucket: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for Bucket") + } + } + } + + return nil +} +func (t *Owner) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + written := 0 + + // t.DisplayName (string) (string) + if len("displayName") > 8192 { + return fmt.Errorf("string in field \"displayName\" was too long") + } + if err := jw.WriteString(string("displayName")); err != nil { + return fmt.Errorf("writing string for field \"displayName\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.DisplayName) > 8192 { + return fmt.Errorf("string in field t.DisplayName was too long") + } + if err := jw.WriteString(string(t.DisplayName)); err != nil { + return fmt.Errorf("writing string for field t.DisplayName: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.ID (string) (string) + if len("id") > 8192 { + return fmt.Errorf("string in field \"id\" was too long") + } + if err := jw.WriteString(string("id")); err != nil { + return fmt.Errorf("writing string for field \"id\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.ID) > 8192 { + return fmt.Errorf("string in field t.ID was too long") + } + if err := jw.WriteString(string(t.ID)); err != nil { + return fmt.Errorf("writing string for field t.ID: %w", err) + } + written++ + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *Owner) UnmarshalDagJSON(r io.Reader) (err error) { + *t = Owner{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for Owner: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for Owner: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for Owner: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field Owner: string too large") + } + return fmt.Errorf("reading string for field Owner: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field Owner: %w", err) + } + switch name { + + // t.DisplayName (string) (string) + case "displayName": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.DisplayName: string too long") + } + return fmt.Errorf("reading string for field t.DisplayName: %w", err) + } + t.DisplayName = string(sval) + } + + // t.ID (string) (string) + case "id": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.ID: string too long") + } + return fmt.Errorf("reading string for field t.ID: %w", err) + } + t.ID = string(sval) + } + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for Owner: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field Owner: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for Owner") + } + } + } + + return nil +} diff --git a/commands/s3/bucket/list.go b/commands/s3/bucket/list.go new file mode 100644 index 0000000..8bfc668 --- /dev/null +++ b/commands/s3/bucket/list.go @@ -0,0 +1,12 @@ +//go:build !codegen + +package bucket + +import ( + "github.com/fil-forge/ucantone/binding" + "github.com/fil-forge/ucantone/ucan/command" +) + +// List is the `/s3/bucket/list` command. Ingot invokes it on Hilt to list the +// buckets belonging to the tenant. +var List = binding.Bind[*ListArguments, *ListOK](command.MustParse("/s3/bucket/list")) diff --git a/commands/s3/bucket/types.go b/commands/s3/bucket/types.go new file mode 100644 index 0000000..4faf6b6 --- /dev/null +++ b/commands/s3/bucket/types.go @@ -0,0 +1,69 @@ +package bucket + +import ( + "github.com/fil-forge/libforge/commands/s3" + "github.com/fil-forge/ucantone/did" +) + +// CreateArguments are the arguments to `/s3/bucket/create`. +type CreateArguments struct { + // Request is the AWS S3 CreateBucket request. + Request s3.Request `cborgen:"request" dagjsongen:"request"` +} + +// DeleteArguments are the arguments to `/s3/bucket/delete`. +type DeleteArguments struct { + // Request is the AWS S3 DeleteBucket request. + Request s3.Request `cborgen:"request" dagjsongen:"request"` +} + +// ListArguments are the arguments to `/s3/bucket/list`. +type ListArguments struct { + // Request is the AWS S3 ListBuckets request. + Request s3.Request `cborgen:"request" dagjsongen:"request"` +} + +// InfoArguments are the arguments to `/s3/bucket/info`. +type InfoArguments struct { + // Name is the global bucket name to look up. + Name string `cborgen:"name" dagjsongen:"name"` + // AccessKey is the access key DID the returned delegation chain should + // terminate at. + AccessKey did.DID `cborgen:"accessKey" dagjsongen:"accessKey"` +} + +// InfoOK is the successful result of `/s3/bucket/info`. Its Permissions and +// Delegations fields are slice-valued maps wrapped in struct types +// ([s3.PermissionSet] etc.) with their own codecs, so this struct is generated +// normally (the generators delegate to a struct field's codec). +type InfoOK struct { + // ID is the DID of the bucket. + ID did.DID `cborgen:"id" dagjsongen:"id"` + // Permissions maps the access key DID to its assigned S3 permissions. + Permissions s3.PermissionSet `cborgen:"permissions" dagjsongen:"permissions"` + // Delegations maps the CID of a delegation whose audience is the access key + // to its proof chain from the bucket. + Delegations s3.ProofSet `cborgen:"delegations" dagjsongen:"delegations"` +} + +// ListOK is the successful result of `/s3/bucket/list`. +type ListOK struct { + Buckets []Bucket `cborgen:"buckets" dagjsongen:"buckets"` + ContinuationToken string `cborgen:"continuationToken" dagjsongen:"continuationToken"` + Owner Owner `cborgen:"owner" dagjsongen:"owner"` + Prefix string `cborgen:"prefix" dagjsongen:"prefix"` +} + +// Bucket describes a single bucket in a `/s3/bucket/list` result. +type Bucket struct { + ARN string `cborgen:"arn" dagjsongen:"arn"` + Region string `cborgen:"region" dagjsongen:"region"` + CreationDate string `cborgen:"creationDate" dagjsongen:"creationDate"` + Name string `cborgen:"name" dagjsongen:"name"` +} + +// Owner is the owner of a set of buckets. +type Owner struct { + DisplayName string `cborgen:"displayName" dagjsongen:"displayName"` + ID string `cborgen:"id" dagjsongen:"id"` +} diff --git a/commands/s3/cbor_gen.go b/commands/s3/cbor_gen.go new file mode 100644 index 0000000..926e231 --- /dev/null +++ b/commands/s3/cbor_gen.go @@ -0,0 +1,400 @@ +//go:build !codegen + +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package s3 + +import ( + "fmt" + "io" + "math" + "sort" + + cid "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf +var _ = cid.Undef +var _ = math.E +var _ = sort.Sort + +func (t *Request) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{163}); err != nil { + return err + } + + // t.URL (string) (string) + if len("url") > 8192 { + return xerrors.Errorf("Value in field \"url\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("url"))); err != nil { + return err + } + if _, err := cw.WriteString(string("url")); err != nil { + return err + } + + if len(t.URL) > 8192 { + return xerrors.Errorf("Value in field t.URL was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.URL))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.URL)); err != nil { + return err + } + + // t.Method (string) (string) + if len("method") > 8192 { + return xerrors.Errorf("Value in field \"method\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("method"))); err != nil { + return err + } + if _, err := cw.WriteString(string("method")); err != nil { + return err + } + + if len(t.Method) > 8192 { + return xerrors.Errorf("Value in field t.Method was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Method))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.Method)); err != nil { + return err + } + + // t.Headers (map[string]string) (map) + if len("headers") > 8192 { + return xerrors.Errorf("Value in field \"headers\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("headers"))); err != nil { + return err + } + if _, err := cw.WriteString(string("headers")); err != nil { + return err + } + + { + if len(t.Headers) > 4096 { + return xerrors.Errorf("cannot marshal t.Headers map too large") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajMap, uint64(len(t.Headers))); err != nil { + return err + } + + keys := make([]string, 0, len(t.Headers)) + for k := range t.Headers { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + v := t.Headers[k] + + if len(k) > 8192 { + return xerrors.Errorf("Value in field k was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(k))); err != nil { + return err + } + if _, err := cw.WriteString(string(k)); err != nil { + return err + } + + if len(v) > 8192 { + return xerrors.Errorf("Value in field v was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(v))); err != nil { + return err + } + if _, err := cw.WriteString(string(v)); err != nil { + return err + } + + } + } + return nil +} + +func (t *Request) UnmarshalCBOR(r io.Reader) (err error) { + *t = Request{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("Request: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 7) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.URL (string) (string) + case "url": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.URL = string(sval) + } + // t.Method (string) (string) + case "method": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.Method = string(sval) + } + // t.Headers (map[string]string) (map) + case "headers": + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + if maj != cbg.MajMap { + return fmt.Errorf("expected a map (major type 5)") + } + if extra > 4096 { + return fmt.Errorf("t.Headers: map too large") + } + + t.Headers = make(map[string]string, extra) + + for i, l := 0, int(extra); i < l; i++ { + + var k string + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + k = string(sval) + } + + var v string + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + v = string(sval) + } + + t.Headers[k] = v + + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} +func (t *VerificationKey) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{162}); err != nil { + return err + } + + // t.Data ([]uint8) (slice) + if len("data") > 8192 { + return xerrors.Errorf("Value in field \"data\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("data"))); err != nil { + return err + } + if _, err := cw.WriteString(string("data")); err != nil { + return err + } + + if len(t.Data) > 2097152 { + return xerrors.Errorf("Byte array in field t.Data was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Data))); err != nil { + return err + } + + if _, err := cw.Write(t.Data); err != nil { + return err + } + + // t.Kind (string) (string) + if len("kind") > 8192 { + return xerrors.Errorf("Value in field \"kind\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("kind"))); err != nil { + return err + } + if _, err := cw.WriteString(string("kind")); err != nil { + return err + } + + if len(t.Kind) > 8192 { + return xerrors.Errorf("Value in field t.Kind was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Kind))); err != nil { + return err + } + if _, err := cw.WriteString(string(t.Kind)); err != nil { + return err + } + return nil +} + +func (t *VerificationKey) UnmarshalCBOR(r io.Reader) (err error) { + *t = VerificationKey{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("VerificationKey: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 4) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.Data ([]uint8) (slice) + case "data": + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + + if extra > 2097152 { + return fmt.Errorf("t.Data: byte array too large (%d)", extra) + } + if maj != cbg.MajByteString { + return fmt.Errorf("expected byte array") + } + + if extra > 0 { + t.Data = make([]uint8, extra) + } + + if _, err := io.ReadFull(cr, t.Data); err != nil { + return err + } + + // t.Kind (string) (string) + case "kind": + + { + sval, err := cbg.ReadStringWithMax(cr, 8192) + if err != nil { + return err + } + + t.Kind = string(sval) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} diff --git a/commands/s3/codec.go b/commands/s3/codec.go new file mode 100644 index 0000000..5e32c17 --- /dev/null +++ b/commands/s3/codec.go @@ -0,0 +1,518 @@ +//go:build !codegen + +package s3 + +import ( + "fmt" + "io" + "sort" + + jsg "github.com/alanshaw/dag-json-gen" + "github.com/fil-forge/ucantone/did" + cid "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +// These codecs are hand-written because cbor-gen / dag-json-gen do not support +// slice-valued maps. + +const ( + maxString = 8192 + maxLen = 4096 +) + +// --- shared CBOR helpers --- + +func writeCborStringField(cw *cbg.CborWriter, s string) error { + if len(s) > maxString { + return xerrors.Errorf("string value was too long (%d)", len(s)) + } + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(s))); err != nil { + return err + } + _, err := cw.WriteString(s) + return err +} + +func readCborStringField(cr *cbg.CborReader) (string, error) { + return cbg.ReadStringWithMax(cr, maxString) +} + +func writeCborArrayHeader(cw *cbg.CborWriter, n int) error { + if n > maxString { + return xerrors.Errorf("slice value was too long (%d)", n) + } + return cw.WriteMajorTypeHeader(cbg.MajArray, uint64(n)) +} + +func readCborArrayHeader(cr *cbg.CborReader) (uint64, error) { + maj, extra, err := cr.ReadHeader() + if err != nil { + return 0, err + } + if maj != cbg.MajArray { + return 0, fmt.Errorf("expected cbor array") + } + if extra > maxString { + return 0, fmt.Errorf("array too large (%d)", extra) + } + return extra, nil +} + +func writeCborMapHeader(cw *cbg.CborWriter, n int) error { + if n > maxLen { + return xerrors.Errorf("map too large (%d)", n) + } + return cw.WriteMajorTypeHeader(cbg.MajMap, uint64(n)) +} + +func readCborMapHeader(cr *cbg.CborReader) (uint64, error) { + maj, extra, err := cr.ReadHeader() + if err != nil { + return 0, err + } + if maj != cbg.MajMap { + return 0, fmt.Errorf("expected a map (major type 5)") + } + if extra > maxLen { + return 0, fmt.Errorf("map too large (%d)", extra) + } + return extra, nil +} + +// sortedDIDs returns the DID keys of m sorted by their string encoding, so the +// encoded map keys come out in the same (lexicographic) order the generators +// use for string-keyed maps. +func sortedDIDs[V any](m map[did.DID]V) []did.DID { + keys := make([]did.DID, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() }) + return keys +} + +// sortedCIDs returns the CID keys of m sorted by their string encoding. +func sortedCIDs[V any](m map[cid.Cid]V) []cid.Cid { + keys := make([]cid.Cid, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() }) + return keys +} + +// --- PermissionSet: map[did.DID][]string --- + +func (t PermissionSet) MarshalCBOR(w io.Writer) error { + cw := cbg.NewCborWriter(w) + if err := writeCborMapHeader(cw, len(t.Entries)); err != nil { + return err + } + for _, k := range sortedDIDs(t.Entries) { + if err := writeCborStringField(cw, k.String()); err != nil { + return err + } + perms := t.Entries[k] + if err := writeCborArrayHeader(cw, len(perms)); err != nil { + return err + } + for _, p := range perms { + if err := writeCborStringField(cw, p); err != nil { + return err + } + } + } + return nil +} + +func (t *PermissionSet) UnmarshalCBOR(r io.Reader) error { + cr := cbg.NewCborReader(r) + n, err := readCborMapHeader(cr) + if err != nil { + return err + } + m := make(map[did.DID][]string, n) + for i := uint64(0); i < n; i++ { + ks, err := readCborStringField(cr) + if err != nil { + return err + } + k, err := did.Parse(ks) + if err != nil { + return xerrors.Errorf("parsing access key did %q: %w", ks, err) + } + alen, err := readCborArrayHeader(cr) + if err != nil { + return err + } + perms := make([]string, 0, alen) + for j := uint64(0); j < alen; j++ { + p, err := readCborStringField(cr) + if err != nil { + return err + } + perms = append(perms, p) + } + m[k] = perms + } + *t = PermissionSet{Entries: m} + return nil +} + +func (t PermissionSet) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if err := jw.WriteObjectOpen(); err != nil { + return err + } + for i, k := range sortedDIDs(t.Entries) { + if err := writeJSONKey(jw, k.String(), i > 0); err != nil { + return err + } + if err := jw.WriteArrayOpen(); err != nil { + return err + } + for j, p := range t.Entries[k] { + if j > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + if err := jw.WriteString(p); err != nil { + return err + } + } + if err := jw.WriteArrayClose(); err != nil { + return err + } + } + return jw.WriteObjectClose() +} + +func (t *PermissionSet) UnmarshalDagJSON(r io.Reader) error { + jr := jsg.NewDagJsonReader(r) + m := map[did.DID][]string{} + err := readJSONObject(jr, func(ks string) error { + k, err := did.Parse(ks) + if err != nil { + return xerrors.Errorf("parsing access key did %q: %w", ks, err) + } + perms, err := readJSONArray(jr, func() (string, error) { return jr.ReadString(maxString) }) + if err != nil { + return err + } + m[k] = perms + return nil + }) + if err != nil { + return err + } + *t = PermissionSet{Entries: m} + return nil +} + +// --- ProofSet: map[cid.Cid][]cid.Cid --- + +func (t ProofSet) MarshalCBOR(w io.Writer) error { + cw := cbg.NewCborWriter(w) + if err := writeCborMapHeader(cw, len(t.Entries)); err != nil { + return err + } + for _, k := range sortedCIDs(t.Entries) { + if err := writeCborStringField(cw, k.String()); err != nil { + return err + } + links := t.Entries[k] + if err := writeCborArrayHeader(cw, len(links)); err != nil { + return err + } + for _, c := range links { + if err := cbg.WriteCid(cw, c); err != nil { + return xerrors.Errorf("failed to write cid: %w", err) + } + } + } + return nil +} + +func (t *ProofSet) UnmarshalCBOR(r io.Reader) error { + cr := cbg.NewCborReader(r) + n, err := readCborMapHeader(cr) + if err != nil { + return err + } + m := make(map[cid.Cid][]cid.Cid, n) + for i := uint64(0); i < n; i++ { + ks, err := readCborStringField(cr) + if err != nil { + return err + } + k, err := cid.Decode(ks) + if err != nil { + return xerrors.Errorf("parsing delegation cid %q: %w", ks, err) + } + alen, err := readCborArrayHeader(cr) + if err != nil { + return err + } + links := make([]cid.Cid, 0, alen) + for j := uint64(0); j < alen; j++ { + c, err := cbg.ReadCid(cr) + if err != nil { + return xerrors.Errorf("failed to read cid: %w", err) + } + links = append(links, c) + } + m[k] = links + } + *t = ProofSet{Entries: m} + return nil +} + +func (t ProofSet) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if err := jw.WriteObjectOpen(); err != nil { + return err + } + for i, k := range sortedCIDs(t.Entries) { + if err := writeJSONKey(jw, k.String(), i > 0); err != nil { + return err + } + if err := jw.WriteArrayOpen(); err != nil { + return err + } + for j, c := range t.Entries[k] { + if j > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + if err := jw.WriteCid(c); err != nil { + return err + } + } + if err := jw.WriteArrayClose(); err != nil { + return err + } + } + return jw.WriteObjectClose() +} + +func (t *ProofSet) UnmarshalDagJSON(r io.Reader) error { + jr := jsg.NewDagJsonReader(r) + m := map[cid.Cid][]cid.Cid{} + err := readJSONObject(jr, func(ks string) error { + k, err := cid.Decode(ks) + if err != nil { + return xerrors.Errorf("parsing delegation cid %q: %w", ks, err) + } + links, err := readJSONArray(jr, func() (cid.Cid, error) { return jr.ReadCid() }) + if err != nil { + return err + } + m[k] = links + return nil + }) + if err != nil { + return err + } + *t = ProofSet{Entries: m} + return nil +} + +// --- KeySet: map[did.DID][]VerificationKey --- + +func (t KeySet) MarshalCBOR(w io.Writer) error { + cw := cbg.NewCborWriter(w) + if err := writeCborMapHeader(cw, len(t.Entries)); err != nil { + return err + } + for _, k := range sortedDIDs(t.Entries) { + if err := writeCborStringField(cw, k.String()); err != nil { + return err + } + keys := t.Entries[k] + if err := writeCborArrayHeader(cw, len(keys)); err != nil { + return err + } + for i := range keys { + if err := keys[i].MarshalCBOR(cw); err != nil { + return err + } + } + } + return nil +} + +func (t *KeySet) UnmarshalCBOR(r io.Reader) error { + cr := cbg.NewCborReader(r) + n, err := readCborMapHeader(cr) + if err != nil { + return err + } + m := make(map[did.DID][]VerificationKey, n) + for i := uint64(0); i < n; i++ { + ks, err := readCborStringField(cr) + if err != nil { + return err + } + k, err := did.Parse(ks) + if err != nil { + return xerrors.Errorf("parsing access key did %q: %w", ks, err) + } + alen, err := readCborArrayHeader(cr) + if err != nil { + return err + } + keys := make([]VerificationKey, alen) + for j := uint64(0); j < alen; j++ { + if err := keys[j].UnmarshalCBOR(cr); err != nil { + return err + } + } + m[k] = keys + } + *t = KeySet{Entries: m} + return nil +} + +func (t KeySet) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if err := jw.WriteObjectOpen(); err != nil { + return err + } + for i, k := range sortedDIDs(t.Entries) { + if err := writeJSONKey(jw, k.String(), i > 0); err != nil { + return err + } + if err := jw.WriteArrayOpen(); err != nil { + return err + } + keys := t.Entries[k] + for j := range keys { + if j > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + if err := keys[j].MarshalDagJSON(jw); err != nil { + return err + } + } + if err := jw.WriteArrayClose(); err != nil { + return err + } + } + return jw.WriteObjectClose() +} + +func (t *KeySet) UnmarshalDagJSON(r io.Reader) error { + jr := jsg.NewDagJsonReader(r) + m := map[did.DID][]VerificationKey{} + err := readJSONObject(jr, func(ks string) error { + k, err := did.Parse(ks) + if err != nil { + return xerrors.Errorf("parsing access key did %q: %w", ks, err) + } + keys, err := readJSONArray(jr, func() (VerificationKey, error) { + var vk VerificationKey + err := vk.UnmarshalDagJSON(jr) + return vk, err + }) + if err != nil { + return err + } + m[k] = keys + return nil + }) + if err != nil { + return err + } + *t = KeySet{Entries: m} + return nil +} + +// --- shared DAG-JSON helpers --- + +// writeJSONKey writes an object key, preceded by a comma when comma is true +// (i.e. when it is not the first entry of the object). +func writeJSONKey(jw *jsg.DagJsonWriter, name string, comma bool) error { + if comma { + if err := jw.WriteComma(); err != nil { + return err + } + } + if err := jw.WriteString(name); err != nil { + return err + } + return jw.WriteObjectColon() +} + +// readJSONObject reads a DAG-JSON object, invoking fn for each entry after +// consuming its key and colon. fn is responsible for reading the value. +func readJSONObject(jr *jsg.DagJsonReader, fn func(name string) error) (err error) { + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return err + } + close, err := jr.PeekObjectClose() + if err != nil { + return err + } + if close { + return jr.ReadObjectClose() + } + for { + name, err := jr.ReadString(maxString) + if err != nil { + return err + } + if err := jr.ReadObjectColon(); err != nil { + return err + } + if err := fn(name); err != nil { + return err + } + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return err + } + if close { + return nil + } + } +} + +// readJSONArray reads a DAG-JSON array, invoking read for each element. +func readJSONArray[T any](jr *jsg.DagJsonReader, read func() (T, error)) ([]T, error) { + if err := jr.ReadArrayOpen(); err != nil { + return nil, err + } + close, err := jr.PeekArrayClose() + if err != nil { + return nil, err + } + var out []T + if close { + return out, jr.ReadArrayClose() + } + for { + v, err := read() + if err != nil { + return nil, err + } + out = append(out, v) + close, err := jr.ReadArrayCloseOrComma() + if err != nil { + return nil, err + } + if close { + return out, nil + } + } +} diff --git a/commands/s3/codec_test.go b/commands/s3/codec_test.go new file mode 100644 index 0000000..71886c5 --- /dev/null +++ b/commands/s3/codec_test.go @@ -0,0 +1,167 @@ +package s3_test + +import ( + "bytes" + "reflect" + "strings" + "testing" + + "github.com/fil-forge/libforge/commands/s3" + "github.com/fil-forge/libforge/commands/s3/bucket" + "github.com/fil-forge/libforge/commands/s3/request" + "github.com/fil-forge/ucantone/did" + "github.com/ipfs/go-cid" +) + +func mustCid(t *testing.T, s string) cid.Cid { + t.Helper() + c, err := cid.Parse(s) + if err != nil { + t.Fatalf("parsing cid %q: %v", s, err) + } + return c +} + +func TestRequestRoundTrip(t *testing.T) { + in := &s3.Request{ + Method: "GET", + Headers: map[string]string{ + "host": "region.s3.fil.one", + "x-amz-header": "a", + }, + URL: "https://region.s3.fil.one/bucket/path?x-id=GetObject", + } + + // CBOR + var cb bytes.Buffer + if err := in.MarshalCBOR(&cb); err != nil { + t.Fatalf("MarshalCBOR: %v", err) + } + var outCBOR s3.Request + if err := outCBOR.UnmarshalCBOR(bytes.NewReader(cb.Bytes())); err != nil { + t.Fatalf("UnmarshalCBOR: %v", err) + } + if !reflect.DeepEqual(*in, outCBOR) { + t.Fatalf("CBOR round-trip mismatch:\n got %#v\nwant %#v", outCBOR, *in) + } + + // DAG-JSON + var jb bytes.Buffer + if err := in.MarshalDagJSON(&jb); err != nil { + t.Fatalf("MarshalDagJSON: %v", err) + } + var outJSON s3.Request + if err := outJSON.UnmarshalDagJSON(bytes.NewReader(jb.Bytes())); err != nil { + t.Fatalf("UnmarshalDagJSON: %v\njson: %s", err, jb.String()) + } + if !reflect.DeepEqual(*in, outJSON) { + t.Fatalf("DAG-JSON round-trip mismatch:\n got %#v\nwant %#v", outJSON, *in) + } + // DAG-JSON keys are emitted in lexicographic order. + if got := jb.String(); !strings.HasPrefix(got, `{"headers":`) { + t.Fatalf("expected headers first in DAG-JSON, got: %s", got) + } +} + +func TestAuthorizeOKRoundTrip(t *testing.T) { + access := did.MustParse("did:key:z6MkjFRxLLGdBqQSLkZbVnuwUFiomK8eGBkPtim9ETvP7vec") + delCid := mustCid(t, "bafyreienos3cw7hcga5vwani3pberioe2qscnz5jk2um5jajo4v7bwmvvm") + + in := &request.AuthorizeOK{ + Bucket: did.MustParse("did:key:z6MkmNBgCewjYfEDTdKLpHkbMWUogJk29CxmiVdLeW4Kz3UG"), + Permissions: s3.PermissionSet{Entries: map[did.DID][]string{ + access: {"s3:GetObject", "s3:PutObject"}, + }}, + Keys: s3.KeySet{Entries: map[did.DID][]s3.VerificationKey{ + access: {{Kind: s3.KeyKindSigV4a, Data: []byte{1, 2, 3, 4}}}, + }}, + Delegations: s3.ProofSet{Entries: map[cid.Cid][]cid.Cid{ + delCid: {delCid}, + }}, + } + + var cb bytes.Buffer + if err := in.MarshalCBOR(&cb); err != nil { + t.Fatalf("MarshalCBOR: %v", err) + } + var outCBOR request.AuthorizeOK + if err := outCBOR.UnmarshalCBOR(bytes.NewReader(cb.Bytes())); err != nil { + t.Fatalf("UnmarshalCBOR: %v", err) + } + if !reflect.DeepEqual(*in, outCBOR) { + t.Fatalf("CBOR round-trip mismatch:\n got %#v\nwant %#v", outCBOR, *in) + } + + var jb bytes.Buffer + if err := in.MarshalDagJSON(&jb); err != nil { + t.Fatalf("MarshalDagJSON: %v", err) + } + var outJSON request.AuthorizeOK + if err := outJSON.UnmarshalDagJSON(bytes.NewReader(jb.Bytes())); err != nil { + t.Fatalf("UnmarshalDagJSON: %v\njson: %s", err, jb.String()) + } + if !reflect.DeepEqual(*in, outJSON) { + t.Fatalf("DAG-JSON round-trip mismatch:\n got %#v\nwant %#v", outJSON, *in) + } +} + +func TestInfoOKRoundTrip(t *testing.T) { + access := did.MustParse("did:key:z6MkjFRxLLGdBqQSLkZbVnuwUFiomK8eGBkPtim9ETvP7vec") + root := mustCid(t, "bafyreiabuvg5hkupzjfn2kqywbdp5xhsb25pmhviyfz77yxhspssvxsv5y") + inter := mustCid(t, "bafyreigngbemvzgbmelwddwoms2ak2g32vmhcpxg6dqlwvb6spiezoc4py") + + in := &bucket.InfoOK{ + ID: did.MustParse("did:key:z6MkmNBgCewjYfEDTdKLpHkbMWUogJk29CxmiVdLeW4Kz3UG"), + Permissions: s3.PermissionSet{Entries: map[did.DID][]string{ + access: {"s3:GetObject", "s3:PutObject"}, + }}, + Delegations: s3.ProofSet{Entries: map[cid.Cid][]cid.Cid{ + inter: {root, inter}, + }}, + } + + var cb bytes.Buffer + if err := in.MarshalCBOR(&cb); err != nil { + t.Fatalf("MarshalCBOR: %v", err) + } + var outCBOR bucket.InfoOK + if err := outCBOR.UnmarshalCBOR(bytes.NewReader(cb.Bytes())); err != nil { + t.Fatalf("UnmarshalCBOR: %v", err) + } + if !reflect.DeepEqual(*in, outCBOR) { + t.Fatalf("CBOR round-trip mismatch:\n got %#v\nwant %#v", outCBOR, *in) + } + + var jb bytes.Buffer + if err := in.MarshalDagJSON(&jb); err != nil { + t.Fatalf("MarshalDagJSON: %v", err) + } + var outJSON bucket.InfoOK + if err := outJSON.UnmarshalDagJSON(bytes.NewReader(jb.Bytes())); err != nil { + t.Fatalf("UnmarshalDagJSON: %v\njson: %s", err, jb.String()) + } + if !reflect.DeepEqual(*in, outJSON) { + t.Fatalf("DAG-JSON round-trip mismatch:\n got %#v\nwant %#v", outJSON, *in) + } +} + +func TestEmptyMapsRoundTrip(t *testing.T) { + // Nil/empty slice-valued maps must encode as empty objects and decode back. + in := &request.AuthorizeOK{ + Bucket: did.MustParse("did:key:z6MkmNBgCewjYfEDTdKLpHkbMWUogJk29CxmiVdLeW4Kz3UG"), + Permissions: s3.PermissionSet{}, + Keys: s3.KeySet{}, + Delegations: s3.ProofSet{}, + } + var jb bytes.Buffer + if err := in.MarshalDagJSON(&jb); err != nil { + t.Fatalf("MarshalDagJSON: %v", err) + } + var out request.AuthorizeOK + if err := out.UnmarshalDagJSON(bytes.NewReader(jb.Bytes())); err != nil { + t.Fatalf("UnmarshalDagJSON: %v\njson: %s", err, jb.String()) + } + if len(out.Permissions.Entries) != 0 || len(out.Keys.Entries) != 0 || len(out.Delegations.Entries) != 0 { + t.Fatalf("expected empty maps, got %#v", out) + } +} diff --git a/commands/s3/gen/main.go b/commands/s3/gen/main.go new file mode 100644 index 0000000..6f7cd68 --- /dev/null +++ b/commands/s3/gen/main.go @@ -0,0 +1,45 @@ +//go:generate go run -tags codegen . + +package main + +import ( + "os" + + jsg "github.com/alanshaw/dag-json-gen" + "github.com/fil-forge/libforge/commands/s3" + cbg "github.com/whyrusleeping/cbor-gen" +) + +const buildTag = "//go:build !codegen\n\n" + +func tag(path string) { + data, err := os.ReadFile(path) + if err != nil { + panic(err) + } + if err := os.WriteFile(path, append([]byte(buildTag), data...), 0644); err != nil { + panic(err) + } +} + +func main() { + // PermissionSet, KeySet and ProofSet have hand-written codecs (see + // codec.go) because cbor-gen / dag-json-gen do not support slice-valued + // maps. + models := []any{ + s3.Request{}, + s3.VerificationKey{}, + } + const ( + cborFile = "../cbor_gen.go" + jsonFile = "../json_gen.go" + ) + if err := cbg.WriteMapEncodersToFile(cborFile, "s3", models...); err != nil { + panic(err) + } + if err := jsg.WriteMapEncodersToFile(jsonFile, "s3", models...); err != nil { + panic(err) + } + tag(cborFile) + tag(jsonFile) +} diff --git a/commands/s3/json_gen.go b/commands/s3/json_gen.go new file mode 100644 index 0000000..3291b5f --- /dev/null +++ b/commands/s3/json_gen.go @@ -0,0 +1,415 @@ +//go:build !codegen + +// Code generated by github.com/alanshaw/dag-json-gen. DO NOT EDIT. + +package s3 + +import ( + "errors" + "fmt" + "io" + "math" + "sort" + + jsg "github.com/alanshaw/dag-json-gen" + cid "github.com/ipfs/go-cid" +) + +var _ = cid.Undef +var _ = math.E +var _ = sort.Sort +var _ = errors.Is + +func (t *Request) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + written := 0 + + // t.Headers (map[string]string) (map) + if len("headers") > 8192 { + return fmt.Errorf("string in field \"headers\" was too long") + } + if err := jw.WriteString(string("headers")); err != nil { + return fmt.Errorf("writing string for field \"headers\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + { + if len(t.Headers) > 4096 { + return fmt.Errorf("cannot marshal t.Headers map too large") + } + + if err := jw.WriteObjectOpen(); err != nil { + return fmt.Errorf("writing object open for field t.Headers: %w", err) + } + + keys := make([]string, 0, len(t.Headers)) + for k := range t.Headers { + keys = append(keys, k) + } + sort.Strings(keys) + for i, k := range keys { + if i > 0 { + if err := jw.WriteComma(); err != nil { + return fmt.Errorf("writing comma for field t.Headers: %w", err) + } + } + v := t.Headers[k] + if len(k) > 8192 { + return fmt.Errorf("string in field k was too long") + } + if err := jw.WriteString(string(k)); err != nil { + return fmt.Errorf("writing string for field k: %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return fmt.Errorf("writing colon for field t.Headers: %w", err) + } + + if len(v) > 8192 { + return fmt.Errorf("string in field v was too long") + } + if err := jw.WriteString(string(v)); err != nil { + return fmt.Errorf("writing string for field v: %w", err) + } + } + if err := jw.WriteObjectClose(); err != nil { + return fmt.Errorf("writing object close for field t.Headers: %w", err) + } + } + + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Method (string) (string) + if len("method") > 8192 { + return fmt.Errorf("string in field \"method\" was too long") + } + if err := jw.WriteString(string("method")); err != nil { + return fmt.Errorf("writing string for field \"method\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.Method) > 8192 { + return fmt.Errorf("string in field t.Method was too long") + } + if err := jw.WriteString(string(t.Method)); err != nil { + return fmt.Errorf("writing string for field t.Method: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.URL (string) (string) + if len("url") > 8192 { + return fmt.Errorf("string in field \"url\" was too long") + } + if err := jw.WriteString(string("url")); err != nil { + return fmt.Errorf("writing string for field \"url\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.URL) > 8192 { + return fmt.Errorf("string in field t.URL was too long") + } + if err := jw.WriteString(string(t.URL)); err != nil { + return fmt.Errorf("writing string for field t.URL: %w", err) + } + written++ + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *Request) UnmarshalDagJSON(r io.Reader) (err error) { + *t = Request{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for Request: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for Request: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for Request: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field Request: string too large") + } + return fmt.Errorf("reading string for field Request: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field Request: %w", err) + } + switch name { + + // t.Headers (map[string]string) (map) + case "headers": + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for field t.Headers: %w", err) + } + + t.Headers = map[string]string{} + + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for field t.Headers: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for field t.Headers: %w", err) + } + } else { + for i, l := 0, 8192; i < l; i++ { + var k string + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field k: string too long") + } + return fmt.Errorf("reading string for field k: %w", err) + } + k = string(sval) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field t.Headers: %w", err) + } + var v string + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field v: string too long") + } + return fmt.Errorf("reading string for field v: %w", err) + } + v = string(sval) + } + t.Headers[k] = v + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field t.Headers: %w", err) + } + if close { + break + } + } + } + + // t.Method (string) (string) + case "method": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.Method: string too long") + } + return fmt.Errorf("reading string for field t.Method: %w", err) + } + t.Method = string(sval) + } + + // t.URL (string) (string) + case "url": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.URL: string too long") + } + return fmt.Errorf("reading string for field t.URL: %w", err) + } + t.URL = string(sval) + } + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for Request: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field Request: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for Request") + } + } + } + + return nil +} +func (t *VerificationKey) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + written := 0 + + // t.Data ([]uint8) (slice) + if len("data") > 8192 { + return fmt.Errorf("string in field \"data\" was too long") + } + if err := jw.WriteString(string("data")); err != nil { + return fmt.Errorf("writing string for field \"data\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.Data) > 2097152 { + return fmt.Errorf("byte array in field t.Data was too long") + } + + if err := jw.WriteBytes(t.Data); err != nil { + return fmt.Errorf("writing bytes for field t.Data: %w", err) + } + + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Kind (string) (string) + if len("kind") > 8192 { + return fmt.Errorf("string in field \"kind\" was too long") + } + if err := jw.WriteString(string("kind")); err != nil { + return fmt.Errorf("writing string for field \"kind\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.Kind) > 8192 { + return fmt.Errorf("string in field t.Kind was too long") + } + if err := jw.WriteString(string(t.Kind)); err != nil { + return fmt.Errorf("writing string for field t.Kind: %w", err) + } + written++ + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *VerificationKey) UnmarshalDagJSON(r io.Reader) (err error) { + *t = VerificationKey{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for VerificationKey: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for VerificationKey: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for VerificationKey: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field VerificationKey: string too large") + } + return fmt.Errorf("reading string for field VerificationKey: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field VerificationKey: %w", err) + } + switch name { + + // t.Data ([]uint8) (slice) + case "data": + + { + bval, err := jr.ReadBytes(2097152) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading bytes for field t.Data: byte array too large") + } + return fmt.Errorf("reading bytes for field t.Data: %w", err) + } + if len(bval) > 0 { + t.Data = []uint8(bval) + } + } + + // t.Kind (string) (string) + case "kind": + { + sval, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field t.Kind: string too long") + } + return fmt.Errorf("reading string for field t.Kind: %w", err) + } + t.Kind = string(sval) + } + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for VerificationKey: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field VerificationKey: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for VerificationKey") + } + } + } + + return nil +} diff --git a/commands/s3/request/authorize.go b/commands/s3/request/authorize.go new file mode 100644 index 0000000..f0ce059 --- /dev/null +++ b/commands/s3/request/authorize.go @@ -0,0 +1,15 @@ +//go:build !codegen + +package request + +import ( + "github.com/fil-forge/ucantone/binding" + "github.com/fil-forge/ucantone/ucan/command" +) + +// Authorize is the `/s3/request/authorize` command. Ingot invokes it on Hilt +// (issuer = Ingot, audience = subject = Hilt) to authorize an AWS S3 API +// request: Hilt verifies the SigV4 signature, looks up the access key's +// delegations, derives a signing key and re-delegates capabilities to the +// invocation issuer. +var Authorize = binding.Bind[*AuthorizeArguments, *AuthorizeOK](command.MustParse("/s3/request/authorize")) diff --git a/commands/s3/request/cbor_gen.go b/commands/s3/request/cbor_gen.go new file mode 100644 index 0000000..35f9a5c --- /dev/null +++ b/commands/s3/request/cbor_gen.go @@ -0,0 +1,284 @@ +//go:build !codegen + +// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. + +package request + +import ( + "fmt" + "io" + "math" + "sort" + + cid "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + xerrors "golang.org/x/xerrors" +) + +var _ = xerrors.Errorf +var _ = cid.Undef +var _ = math.E +var _ = sort.Sort + +func (t *AuthorizeArguments) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{161}); err != nil { + return err + } + + // t.Request (s3.Request) (struct) + if len("request") > 8192 { + return xerrors.Errorf("Value in field \"request\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("request"))); err != nil { + return err + } + if _, err := cw.WriteString(string("request")); err != nil { + return err + } + + if err := t.Request.MarshalCBOR(cw); err != nil { + return err + } + return nil +} + +func (t *AuthorizeArguments) UnmarshalCBOR(r io.Reader) (err error) { + *t = AuthorizeArguments{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("AuthorizeArguments: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 7) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.Request (s3.Request) (struct) + case "request": + + { + + if err := t.Request.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Request: %w", err) + } + + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} +func (t *AuthorizeOK) MarshalCBOR(w io.Writer) error { + if t == nil { + _, err := w.Write(cbg.CborNull) + return err + } + + cw := cbg.NewCborWriter(w) + + if _, err := cw.Write([]byte{164}); err != nil { + return err + } + + // t.Keys (s3.KeySet) (struct) + if len("keys") > 8192 { + return xerrors.Errorf("Value in field \"keys\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("keys"))); err != nil { + return err + } + if _, err := cw.WriteString(string("keys")); err != nil { + return err + } + + if err := t.Keys.MarshalCBOR(cw); err != nil { + return err + } + + // t.Bucket (did.DID) (struct) + if len("bucket") > 8192 { + return xerrors.Errorf("Value in field \"bucket\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("bucket"))); err != nil { + return err + } + if _, err := cw.WriteString(string("bucket")); err != nil { + return err + } + + if err := t.Bucket.MarshalCBOR(cw); err != nil { + return err + } + + // t.Delegations (s3.ProofSet) (struct) + if len("delegations") > 8192 { + return xerrors.Errorf("Value in field \"delegations\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("delegations"))); err != nil { + return err + } + if _, err := cw.WriteString(string("delegations")); err != nil { + return err + } + + if err := t.Delegations.MarshalCBOR(cw); err != nil { + return err + } + + // t.Permissions (s3.PermissionSet) (struct) + if len("permissions") > 8192 { + return xerrors.Errorf("Value in field \"permissions\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("permissions"))); err != nil { + return err + } + if _, err := cw.WriteString(string("permissions")); err != nil { + return err + } + + if err := t.Permissions.MarshalCBOR(cw); err != nil { + return err + } + return nil +} + +func (t *AuthorizeOK) UnmarshalCBOR(r io.Reader) (err error) { + *t = AuthorizeOK{} + + cr := cbg.NewCborReader(r) + + maj, extra, err := cr.ReadHeader() + if err != nil { + return err + } + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + + if maj != cbg.MajMap { + return fmt.Errorf("cbor input should be of type map") + } + + if extra > cbg.MaxLength { + return fmt.Errorf("AuthorizeOK: map struct too large (%d)", extra) + } + + n := extra + + nameBuf := make([]byte, 11) + for i := uint64(0); i < n; i++ { + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) + if err != nil { + return err + } + + if !ok { + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { + return err + } + continue + } + + switch string(nameBuf[:nameLen]) { + // t.Keys (s3.KeySet) (struct) + case "keys": + + { + + if err := t.Keys.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Keys: %w", err) + } + + } + // t.Bucket (did.DID) (struct) + case "bucket": + + { + + if err := t.Bucket.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Bucket: %w", err) + } + + } + // t.Delegations (s3.ProofSet) (struct) + case "delegations": + + { + + if err := t.Delegations.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Delegations: %w", err) + } + + } + // t.Permissions (s3.PermissionSet) (struct) + case "permissions": + + { + + if err := t.Permissions.UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Permissions: %w", err) + } + + } + + default: + // Field doesn't exist on this type, so ignore it + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { + return err + } + } + } + + return nil +} diff --git a/commands/s3/request/gen/main.go b/commands/s3/request/gen/main.go new file mode 100644 index 0000000..587bf51 --- /dev/null +++ b/commands/s3/request/gen/main.go @@ -0,0 +1,42 @@ +//go:generate go run -tags codegen . + +package main + +import ( + "os" + + jsg "github.com/alanshaw/dag-json-gen" + "github.com/fil-forge/libforge/commands/s3/request" + cbg "github.com/whyrusleeping/cbor-gen" +) + +const buildTag = "//go:build !codegen\n\n" + +func tag(path string) { + data, err := os.ReadFile(path) + if err != nil { + panic(err) + } + if err := os.WriteFile(path, append([]byte(buildTag), data...), 0644); err != nil { + panic(err) + } +} + +func main() { + models := []any{ + request.AuthorizeArguments{}, + request.AuthorizeOK{}, + } + const ( + cborFile = "../cbor_gen.go" + jsonFile = "../json_gen.go" + ) + if err := cbg.WriteMapEncodersToFile(cborFile, "request", models...); err != nil { + panic(err) + } + if err := jsg.WriteMapEncodersToFile(jsonFile, "request", models...); err != nil { + panic(err) + } + tag(cborFile) + tag(jsonFile) +} diff --git a/commands/s3/request/json_gen.go b/commands/s3/request/json_gen.go new file mode 100644 index 0000000..14319a0 --- /dev/null +++ b/commands/s3/request/json_gen.go @@ -0,0 +1,287 @@ +//go:build !codegen + +// Code generated by github.com/alanshaw/dag-json-gen. DO NOT EDIT. + +package request + +import ( + "errors" + "fmt" + "io" + "math" + "sort" + + jsg "github.com/alanshaw/dag-json-gen" + cid "github.com/ipfs/go-cid" +) + +var _ = cid.Undef +var _ = math.E +var _ = sort.Sort +var _ = errors.Is + +func (t *AuthorizeArguments) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + + // t.Request (s3.Request) (struct) + if len("request") > 8192 { + return fmt.Errorf("string in field \"request\" was too long") + } + if err := jw.WriteString(string("request")); err != nil { + return fmt.Errorf("writing string for field \"request\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Request.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Request: %w", err) + } + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *AuthorizeArguments) UnmarshalDagJSON(r io.Reader) (err error) { + *t = AuthorizeArguments{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for AuthorizeArguments: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for AuthorizeArguments: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for AuthorizeArguments: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field AuthorizeArguments: string too large") + } + return fmt.Errorf("reading string for field AuthorizeArguments: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field AuthorizeArguments: %w", err) + } + switch name { + + // t.Request (s3.Request) (struct) + case "request": + + if err := t.Request.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Request: %w", err) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for AuthorizeArguments: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field AuthorizeArguments: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for AuthorizeArguments") + } + } + } + + return nil +} +func (t *AuthorizeOK) MarshalDagJSON(w io.Writer) error { + jw := jsg.NewDagJsonWriter(w) + if t == nil { + err := jw.WriteNull() + return err + } + if err := jw.WriteObjectOpen(); err != nil { + return err + } + written := 0 + + // t.Bucket (did.DID) (struct) + if len("bucket") > 8192 { + return fmt.Errorf("string in field \"bucket\" was too long") + } + if err := jw.WriteString(string("bucket")); err != nil { + return fmt.Errorf("writing string for field \"bucket\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Bucket.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Bucket: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Delegations (s3.ProofSet) (struct) + if len("delegations") > 8192 { + return fmt.Errorf("string in field \"delegations\" was too long") + } + if err := jw.WriteString(string("delegations")); err != nil { + return fmt.Errorf("writing string for field \"delegations\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Delegations.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Delegations: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Keys (s3.KeySet) (struct) + if len("keys") > 8192 { + return fmt.Errorf("string in field \"keys\" was too long") + } + if err := jw.WriteString(string("keys")); err != nil { + return fmt.Errorf("writing string for field \"keys\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Keys.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Keys: %w", err) + } + written++ + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } + + // t.Permissions (s3.PermissionSet) (struct) + if len("permissions") > 8192 { + return fmt.Errorf("string in field \"permissions\" was too long") + } + if err := jw.WriteString(string("permissions")); err != nil { + return fmt.Errorf("writing string for field \"permissions\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if err := t.Permissions.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field t.Permissions: %w", err) + } + written++ + if err := jw.WriteObjectClose(); err != nil { + return err + } + return nil +} +func (t *AuthorizeOK) UnmarshalDagJSON(r io.Reader) (err error) { + *t = AuthorizeOK{} + + jr := jsg.NewDagJsonReader(r) + defer func() { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + }() + if err := jr.ReadObjectOpen(); err != nil { + return fmt.Errorf("reading object open for AuthorizeOK: %w", err) + } + close, err := jr.PeekObjectClose() + if err != nil { + return fmt.Errorf("peeking object close for AuthorizeOK: %w", err) + } + if close { + if err := jr.ReadObjectClose(); err != nil { + return fmt.Errorf("reading object close for AuthorizeOK: %w", err) + } + } else { + for i := uint64(0); i < 8192; i++ { + name, err := jr.ReadString(8192) + if err != nil { + if errors.Is(err, jsg.ErrLimitExceeded) { + return fmt.Errorf("reading string for field AuthorizeOK: string too large") + } + return fmt.Errorf("reading string for field AuthorizeOK: %w", err) + } + if err := jr.ReadObjectColon(); err != nil { + return fmt.Errorf("reading object colon for field AuthorizeOK: %w", err) + } + switch name { + + // t.Bucket (did.DID) (struct) + case "bucket": + + if err := t.Bucket.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Bucket: %w", err) + } + + // t.Delegations (s3.ProofSet) (struct) + case "delegations": + + if err := t.Delegations.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Delegations: %w", err) + } + + // t.Keys (s3.KeySet) (struct) + case "keys": + + if err := t.Keys.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Keys: %w", err) + } + + // t.Permissions (s3.PermissionSet) (struct) + case "permissions": + + if err := t.Permissions.UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling t.Permissions: %w", err) + } + + default: + // Field doesn't exist on this type, so ignore it + if err := jr.DiscardType(); err != nil { + return fmt.Errorf("ignoring field %s for AuthorizeOK: %w", name, err) + } + } + + close, err := jr.ReadObjectCloseOrComma() + if err != nil { + return fmt.Errorf("reading object close or comma for field AuthorizeOK: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("map too large for AuthorizeOK") + } + } + } + + return nil +} diff --git a/commands/s3/request/types.go b/commands/s3/request/types.go new file mode 100644 index 0000000..71f2258 --- /dev/null +++ b/commands/s3/request/types.go @@ -0,0 +1,33 @@ +package request + +import ( + "github.com/fil-forge/libforge/commands/s3" + "github.com/fil-forge/ucantone/did" +) + +// AuthorizeArguments are the arguments to the `/s3/request/authorize` command. +type AuthorizeArguments struct { + // Request is the AWS S3 API request to authorize. + Request s3.Request `cborgen:"request" dagjsongen:"request"` +} + +// AuthorizeOK is the successful result of `/s3/request/authorize`. It carries +// the resolved bucket DID, the S3 permission set for the access key, the +// derived signing key(s) and the (24-hour TTL) delegations re-delegated to the +// invocation issuer. +// +// Its Permissions, Keys and Delegations fields are slice-valued maps that +// cbor-gen / dag-json-gen cannot generate inline, but they are wrapped in +// struct types ([s3.PermissionSet] etc.) with their own codecs, so this struct +// is generated normally (the generators delegate to a struct field's codec). +type AuthorizeOK struct { + // Bucket is the DID of the bucket addressed by the request. + Bucket did.DID `cborgen:"bucket" dagjsongen:"bucket"` + // Permissions maps the access key DID to its assigned S3 permissions. + Permissions s3.PermissionSet `cborgen:"permissions" dagjsongen:"permissions"` + // Keys maps the access key DID to its derived signing key(s). + Keys s3.KeySet `cborgen:"keys" dagjsongen:"keys"` + // Delegations maps the CID of a delegation whose audience is the invocation + // issuer to its proof chain. + Delegations s3.ProofSet `cborgen:"delegations" dagjsongen:"delegations"` +} diff --git a/commands/s3/types.go b/commands/s3/types.go new file mode 100644 index 0000000..36f17bd --- /dev/null +++ b/commands/s3/types.go @@ -0,0 +1,69 @@ +// Package s3 defines the shared wire types for the Hilt S3 tenant-management +// UCAN API (the `/s3/...` commands). The individual commands live in the +// request and bucket subpackages; this package holds the types shared across +// them. +// +// PermissionSet, KeySet and ProofSet carry maps whose values are lists +// (e.g. map[did.DID][]string). The cbor-gen / dag-json-gen code generators do +// not support slice-valued maps, so these three types have hand-written codecs +// (see codec.go). They are defined as structs wrapping a map so that structs +// embedding them (AuthorizeOK, InfoOK) can still be generated as usual. +package s3 + +import ( + "github.com/fil-forge/ucantone/did" + "github.com/ipfs/go-cid" +) + +// KeyKind identifies the signing scheme of a derived [VerificationKey]. +const ( + KeyKindSigV4 = "sigv4" + KeyKindSigV4a = "sigv4a" +) + +// Request is an AWS S3 API request as forwarded by Ingot to Hilt. It carries +// enough of the original HTTP request (method, headers and URL) for Hilt to +// verify the SigV4/SigV4a signature and determine the requested S3 action. +type Request struct { + Method string `cborgen:"method" dagjsongen:"method"` + Headers map[string]string `cborgen:"headers" dagjsongen:"headers"` + URL string `cborgen:"url" dagjsongen:"url"` +} + +// VerificationKey is a SigV4/SigV4a derived signing key returned by Hilt so +// that Ingot can verify request signatures locally. Kind is one of +// [KeyKindSigV4] or [KeyKindSigV4a]. +type VerificationKey struct { + Kind string `cborgen:"kind" dagjsongen:"kind"` + Data []byte `cborgen:"data" dagjsongen:"data"` +} + +// PermissionSet maps an access key DID to the list of S3 permission strings +// (e.g. "s3:GetObject") granted to it. The DID is encoded as the (string) map +// key on the wire. +// +// It is a struct wrapping the map (rather than a named map type) so that +// structs embedding it can be generated by cbor-gen / dag-json-gen, which +// delegate to a struct field's MarshalCBOR but cannot generate a (slice-valued) +// map field inline. On the wire it encodes as the bare map, not as an object +// with an "entries" key. +type PermissionSet struct { + Entries map[did.DID][]string +} + +// KeySet maps an access key DID to its derived signing keys. Hilt returns the +// key kind matching the request signature and MAY include the other kind. The +// DID is encoded as the (string) map key on the wire. See [PermissionSet] for +// why this is a struct wrapping a map. +type KeySet struct { + Entries map[did.DID][]VerificationKey +} + +// ProofSet maps a delegation CID to a proof chain: the list of delegation CIDs +// that make up the chain. In the initial implementation a chain holds a single +// delegation, but it is modeled as a list to allow more in the future. The CID +// is encoded as the (string) map key on the wire; the chain entries are encoded +// as CID links. See [PermissionSet] for why this is a struct wrapping a map. +type ProofSet struct { + Entries map[cid.Cid][]cid.Cid +}