2024-11-20 15:35:33 +01:00
|
|
|
package main
|
2024-11-20 14:55:48 +01:00
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"slices"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/dave/jennifer/jen"
|
|
|
|
|
"github.com/ipfs/go-cid"
|
|
|
|
|
"github.com/libp2p/go-libp2p/core/crypto"
|
|
|
|
|
|
|
|
|
|
"github.com/ucan-wg/go-ucan/did"
|
|
|
|
|
"github.com/ucan-wg/go-ucan/did/didtest"
|
|
|
|
|
"github.com/ucan-wg/go-ucan/pkg/command"
|
|
|
|
|
"github.com/ucan-wg/go-ucan/pkg/policy"
|
2024-11-27 10:20:40 -05:00
|
|
|
"github.com/ucan-wg/go-ucan/pkg/policy/policytest"
|
2024-11-20 14:55:48 +01:00
|
|
|
"github.com/ucan-wg/go-ucan/token/delegation"
|
2024-11-20 15:35:33 +01:00
|
|
|
"github.com/ucan-wg/go-ucan/token/delegation/delegationtest"
|
2024-11-20 14:55:48 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
tokenNamePrefix = "Token"
|
|
|
|
|
proorChainNamePrefix = "Proof"
|
2024-11-20 15:35:33 +01:00
|
|
|
tokenExt = ".dagcbor"
|
2024-11-20 14:55:48 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var constantNonce = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b}
|
|
|
|
|
|
|
|
|
|
type newDelegationParams struct {
|
|
|
|
|
privKey crypto.PrivKey
|
|
|
|
|
aud did.DID
|
|
|
|
|
sub did.DID
|
|
|
|
|
cmd command.Command
|
|
|
|
|
pol policy.Policy
|
|
|
|
|
opts []delegation.Option
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type token struct {
|
|
|
|
|
name string
|
|
|
|
|
id cid.Cid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type proof struct {
|
|
|
|
|
name string
|
|
|
|
|
prf []cid.Cid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type acc struct {
|
|
|
|
|
name string
|
|
|
|
|
chain []cid.Cid
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type variant struct {
|
|
|
|
|
name string
|
|
|
|
|
variant func(*newDelegationParams)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func noopVariant() variant {
|
|
|
|
|
return variant{
|
|
|
|
|
name: "",
|
|
|
|
|
variant: func(_ *newDelegationParams) {},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type generator struct {
|
|
|
|
|
dlgs []token
|
|
|
|
|
chains []proof
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *generator) chainPersonas(personas []didtest.Persona, acc acc, vari variant) error {
|
|
|
|
|
acc.name += personas[0].Name()
|
|
|
|
|
|
|
|
|
|
proofName := acc.name
|
|
|
|
|
if len(vari.name) > 0 {
|
|
|
|
|
proofName += "_" + vari.name
|
|
|
|
|
}
|
|
|
|
|
g.createProofChain(proofName, acc.chain)
|
|
|
|
|
|
|
|
|
|
if len(personas) < 2 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name := personas[0].Name() + personas[1].Name()
|
|
|
|
|
|
|
|
|
|
params := newDelegationParams{
|
|
|
|
|
privKey: personas[0].PrivKey(),
|
|
|
|
|
aud: personas[1].DID(),
|
2024-11-20 15:35:33 +01:00
|
|
|
cmd: delegationtest.NominalCommand,
|
2024-11-27 10:20:40 -05:00
|
|
|
pol: policytest.EmptyPolicy,
|
2024-11-20 14:55:48 +01:00
|
|
|
opts: []delegation.Option{
|
|
|
|
|
delegation.WithSubject(didtest.PersonaAlice.DID()),
|
|
|
|
|
delegation.WithNonce(constantNonce),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create each nominal token and continue the chain
|
|
|
|
|
id, err := g.createDelegation(params, name, vari)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
acc.chain = append(acc.chain, id)
|
|
|
|
|
err = g.chainPersonas(personas[1:], acc, vari)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the user is Carol, create variants for each invalid and/or optional
|
|
|
|
|
// parameter and also continue the chain
|
|
|
|
|
if personas[0] == didtest.PersonaCarol {
|
|
|
|
|
variants := []variant{
|
|
|
|
|
{name: "InvalidExpandedCommand", variant: func(p *newDelegationParams) {
|
2024-11-20 15:35:33 +01:00
|
|
|
p.cmd = delegationtest.ExpandedCommand
|
2024-11-20 14:55:48 +01:00
|
|
|
}},
|
|
|
|
|
{name: "ValidAttenuatedCommand", variant: func(p *newDelegationParams) {
|
2024-11-20 15:35:33 +01:00
|
|
|
p.cmd = delegationtest.AttenuatedCommand
|
2024-11-20 14:55:48 +01:00
|
|
|
}},
|
|
|
|
|
{name: "InvalidSubject", variant: func(p *newDelegationParams) {
|
|
|
|
|
p.opts = append(p.opts, delegation.WithSubject(didtest.PersonaBob.DID()))
|
|
|
|
|
}},
|
|
|
|
|
{name: "InvalidExpired", variant: func(p *newDelegationParams) {
|
|
|
|
|
// Note: this makes the generator not deterministic
|
|
|
|
|
p.opts = append(p.opts, delegation.WithExpiration(time.Now().Add(time.Second)))
|
|
|
|
|
}},
|
|
|
|
|
{name: "InvalidInactive", variant: func(p *newDelegationParams) {
|
|
|
|
|
nbf, err := time.Parse(time.RFC3339, "2070-01-01T00:00:00Z")
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
p.opts = append(p.opts, delegation.WithNotBefore(nbf))
|
|
|
|
|
}},
|
2024-11-27 10:20:40 -05:00
|
|
|
{name: "ValidExamplePolicy", variant: func(p *newDelegationParams) {
|
|
|
|
|
p.pol = policytest.ExamplePolicy
|
|
|
|
|
}},
|
2024-11-20 14:55:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start a branch in the recursion for each of the variants
|
|
|
|
|
for _, v := range variants {
|
|
|
|
|
id, err := g.createDelegation(params, name, v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// replace the previous Carol token id with the one from the variant
|
|
|
|
|
acc.chain[len(acc.chain)-1] = id
|
|
|
|
|
err = g.chainPersonas(personas[1:], acc, v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *generator) createDelegation(params newDelegationParams, name string, vari variant) (cid.Cid, error) {
|
|
|
|
|
vari.variant(¶ms)
|
|
|
|
|
|
2024-11-25 15:12:29 -05:00
|
|
|
issDID, err := did.FromPrivKey(params.privKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return cid.Undef, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tkn, err := delegation.New(issDID, params.aud, params.cmd, params.pol, params.opts...)
|
2024-11-20 14:55:48 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return cid.Undef, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data, id, err := tkn.ToSealed(params.privKey)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return cid.Undef, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dlgName := tokenNamePrefix + name
|
|
|
|
|
if len(vari.name) > 0 {
|
|
|
|
|
dlgName += "_" + vari.name
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-20 15:35:33 +01:00
|
|
|
err = os.WriteFile(filepath.Join("..", delegationtest.TokenDir, dlgName+tokenExt), data, 0o644)
|
2024-11-20 14:55:48 +01:00
|
|
|
if err != nil {
|
|
|
|
|
return cid.Undef, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g.dlgs = append(g.dlgs, token{
|
|
|
|
|
name: dlgName,
|
|
|
|
|
id: id,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return id, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *generator) createProofChain(name string, prf []cid.Cid) {
|
|
|
|
|
if len(prf) < 1 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clone := make([]cid.Cid, len(prf))
|
|
|
|
|
copy(clone, prf)
|
|
|
|
|
|
|
|
|
|
g.chains = append(g.chains, proof{
|
|
|
|
|
name: proorChainNamePrefix + name,
|
|
|
|
|
prf: clone,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *generator) writeGoFile() error {
|
|
|
|
|
file := jen.NewFile("delegationtest")
|
|
|
|
|
file.HeaderComment("Code generated by delegationtest - DO NOT EDIT.")
|
|
|
|
|
|
|
|
|
|
refs := map[cid.Cid]string{}
|
|
|
|
|
|
|
|
|
|
for _, d := range g.dlgs {
|
|
|
|
|
refs[d.id] = d.name + "CID"
|
|
|
|
|
|
|
|
|
|
file.Var().Defs(
|
|
|
|
|
jen.Id(d.name+"CID").Op("=").Qual("github.com/ipfs/go-cid", "MustParse").Call(jen.Lit(d.id.String())),
|
|
|
|
|
jen.Id(d.name).Op("=").Id("mustGetDelegation").Call(jen.Id(d.name+"CID")),
|
|
|
|
|
)
|
|
|
|
|
file.Line()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, c := range g.chains {
|
|
|
|
|
g := jen.CustomFunc(jen.Options{
|
|
|
|
|
Multi: true,
|
|
|
|
|
Separator: ",",
|
|
|
|
|
Close: "\n",
|
|
|
|
|
}, func(g *jen.Group) {
|
|
|
|
|
slices.Reverse(c.prf)
|
|
|
|
|
for _, p := range c.prf {
|
|
|
|
|
g.Id(refs[p])
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
file.Var().Id(c.name).Op("=").Index().Qual("github.com/ipfs/go-cid", "Cid").Values(g)
|
|
|
|
|
file.Line()
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-20 15:35:33 +01:00
|
|
|
return file.Save("../token_gen.go")
|
2024-11-20 14:55:48 +01:00
|
|
|
}
|