diff --git a/token/invocation/invocation_test.go b/token/invocation/invocation_test.go index eb15889..b103869 100644 --- a/token/invocation/invocation_test.go +++ b/token/invocation/invocation_test.go @@ -197,7 +197,7 @@ func TestToken_ExecutionAllowed(t *testing.T) { cmd: delegationtest.NominalCommand, args: emptyArguments, proofs: []cid.Cid{delegationtest.TokenBobBobCID}, - err: invocation.ErrBrokenChain, + err: invocation.ErrWrongSub, }, } { t.Run(tc.name, func(t *testing.T) { @@ -206,6 +206,8 @@ func TestToken_ExecutionAllowed(t *testing.T) { tkn, err := invocation.New(tc.issuer.DID(), tc.cmd, didtest.PersonaAlice.DID(), tc.proofs, tc.opts...) require.NoError(t, err) + t.Log(tkn.String()) + err = tkn.ExecutionAllowed(delegationtest.GetDelegationLoader()) if tc.err != nil { diff --git a/toolkit/client/proof.go b/toolkit/client/proof.go index 14d557d..5bcf562 100644 --- a/toolkit/client/proof.go +++ b/toolkit/client/proof.go @@ -21,8 +21,7 @@ import ( // Note: the returned delegation(s) don't have to match exactly the parameters, as long as they allow them. // Note: the implemented algorithm won't perform well with a large number of delegations. func FindProof(dlgs func() iter.Seq[*delegation.Bundle], issuer did.DID, cmd command.Command, subject did.DID) []cid.Cid { - // TODO: maybe that should be part of delegation.Token directly? - dlgMatch := func(dlg *delegation.Token, issuer did.DID, cmd command.Command, subject did.DID) bool { + continuePath := func(dlg *delegation.Token, issuer did.DID, cmd command.Command, subject did.DID) bool { // The Subject of each delegation must equal the invocation's Subject (or Audience if defined). - 4f if !dlg.Subject().Equal(subject) { return false @@ -47,7 +46,7 @@ func FindProof(dlgs func() iter.Seq[*delegation.Bundle], issuer did.DID, cmd com var candidateLeaf []*delegation.Bundle for bundle := range dlgs() { - if !dlgMatch(bundle.Decoded, issuer, cmd, subject) { + if !continuePath(bundle.Decoded, issuer, cmd, subject) { continue } candidateLeaf = append(candidateLeaf, bundle) @@ -83,7 +82,12 @@ func FindProof(dlgs func() iter.Seq[*delegation.Bundle], issuer did.DID, cmd com // find parent delegation for our current delegation for candidate := range dlgs() { - if !dlgMatch(candidate.Decoded, at.Decoded.Issuer(), at.Decoded.Command(), subject) { + // Prune the delegations that don't match the current proof. + if !continuePath(candidate.Decoded, at.Decoded.Issuer(), at.Decoded.Command(), subject) { + continue + } + // Prune the self-delegations as they can't get us closer to what we are looking for. + if candidate.Decoded.Issuer().Equal(candidate.Decoded.Audience()) { continue } diff --git a/toolkit/client/proof_test.go b/toolkit/client/proof_test.go index c729418..403fae5 100644 --- a/toolkit/client/proof_test.go +++ b/toolkit/client/proof_test.go @@ -4,7 +4,9 @@ import ( "iter" "testing" + "github.com/MetaMask/go-did-it" "github.com/MetaMask/go-did-it/didtest" + "github.com/ipfs/go-cid" "github.com/stretchr/testify/require" "github.com/ucan-wg/go-ucan/pkg/command" @@ -23,17 +25,76 @@ func TestFindProof(t *testing.T) { } } - require.Equal(t, delegationtest.ProofAliceBob, - FindProof(dlgs, didtest.PersonaBob.DID(), delegationtest.NominalCommand, didtest.PersonaAlice.DID())) - require.Equal(t, delegationtest.ProofAliceBobCarol, - FindProof(dlgs, didtest.PersonaCarol.DID(), delegationtest.NominalCommand, didtest.PersonaAlice.DID())) - require.Equal(t, delegationtest.ProofAliceBobCarolDan, - FindProof(dlgs, didtest.PersonaDan.DID(), delegationtest.NominalCommand, didtest.PersonaAlice.DID())) - require.Equal(t, delegationtest.ProofAliceBobCarolDanErin, - FindProof(dlgs, didtest.PersonaErin.DID(), delegationtest.NominalCommand, didtest.PersonaAlice.DID())) - require.Equal(t, delegationtest.ProofAliceBobCarolDanErinFrank, - FindProof(dlgs, didtest.PersonaFrank.DID(), delegationtest.NominalCommand, didtest.PersonaAlice.DID())) + for _, tc := range []struct { + name string + issuer did.DID + command command.Command + subject did.DID + expected []cid.Cid + }{ + // Passes + { + name: "Alice --> Alice (self-delegation)", + issuer: didtest.PersonaAlice.DID(), + command: delegationtest.NominalCommand, + subject: didtest.PersonaAlice.DID(), + expected: []cid.Cid{delegationtest.TokenAliceAliceCID}, + }, + { + name: "Alice --> Bob", + issuer: didtest.PersonaBob.DID(), + command: delegationtest.NominalCommand, + subject: didtest.PersonaAlice.DID(), + expected: delegationtest.ProofAliceBob, + }, + { + name: "Alice --> Bob --> Carol", + issuer: didtest.PersonaCarol.DID(), + command: delegationtest.NominalCommand, + subject: didtest.PersonaAlice.DID(), + expected: delegationtest.ProofAliceBobCarol, + }, + { + name: "Alice --> Bob --> Carol --> Dan", + issuer: didtest.PersonaDan.DID(), + command: delegationtest.NominalCommand, + subject: didtest.PersonaAlice.DID(), + expected: delegationtest.ProofAliceBobCarolDan, + }, + { + name: "Alice --> Bob --> Carol --> Dan --> Erin", + issuer: didtest.PersonaErin.DID(), + command: delegationtest.NominalCommand, + subject: didtest.PersonaAlice.DID(), + expected: delegationtest.ProofAliceBobCarolDanErin, + }, + { + name: "Alice --> Bob --> Carol --> Dan --> Erin --> Frank", + issuer: didtest.PersonaFrank.DID(), + command: delegationtest.NominalCommand, + subject: didtest.PersonaAlice.DID(), + expected: delegationtest.ProofAliceBobCarolDanErinFrank, + }, - // wrong command - require.Empty(t, FindProof(dlgs, didtest.PersonaBob.DID(), command.New("foo"), didtest.PersonaAlice.DID())) + // Fails + { + name: "wrong command", + issuer: didtest.PersonaBob.DID(), + command: command.New("foo"), + subject: didtest.PersonaAlice.DID(), + expected: nil, + }, + { + name: "wrong subject", + issuer: didtest.PersonaBob.DID(), + command: delegationtest.NominalCommand, + subject: didtest.PersonaDan.DID(), + expected: nil, + }, + } { + t.Run(tc.name, func(t *testing.T) { + res := FindProof(dlgs, tc.issuer, tc.command, tc.subject) + require.Equal(t, tc.expected, res) + }) + } }