Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Update AssertionMethod Validator #796

Merged
merged 13 commits into from
Oct 17, 2024
131 changes: 131 additions & 0 deletions tests/integration/cli_diddoc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ package integration

import (
"crypto/ed25519"
"encoding/json"
"fmt"
"strconv"

"github.com/cheqd/cheqd-node/tests/integration/cli"
"github.com/cheqd/cheqd-node/tests/integration/helpers"
Expand Down Expand Up @@ -408,4 +410,133 @@ var _ = Describe("cheqd cli - positive did", func() {
// Check that the DID Doc is deactivated
Expect(resp2.Value.Metadata.Deactivated).To(BeTrue())
})

It("can create diddoc with augmented assertionMethod, update it and query the result (Ed25519VerificationKey2020)", func() {
AddReportEntry("Integration", fmt.Sprintf("%sPositive: %s", cli.Green, "can create diddoc with augmented assertionMethod (Ed25519VerificationKey2020)"))
// Create a new DID Doc
did := "did:cheqd:" + network.DidNamespace + ":" + uuid.NewString()
keyID := did + "#key1"

publicKey, privateKey, err := ed25519.GenerateKey(nil)
Expect(err).To(BeNil())

publicKeyMultibase := testsetup.GenerateEd25519VerificationKey2020VerificationMaterial(publicKey)
publicKeyBase58 := testsetup.GenerateEd25519VerificationKey2018VerificationMaterial(publicKey)

assertionMethodJSONEscaped := func() string {
b, _ := json.Marshal(types.AssertionMethodJSONUnescaped{
Id: keyID,
Type: "Ed25519VerificationKey2018",
Controller: did,
PublicKeyBase58: &publicKeyBase58, // arbitrarily chosen, loosely validated
})
return strconv.Quote(string(b))
}()

payload := didcli.DIDDocument{
ID: did,
VerificationMethod: []didcli.VerificationMethod{
map[string]any{
"id": keyID,
"type": "Ed25519VerificationKey2020",
"controller": did,
"publicKeyMultibase": publicKeyMultibase,
},
},
Authentication: []string{keyID},
AssertionMethod: []string{keyID, assertionMethodJSONEscaped},
}

signInputs := []didcli.SignInput{
{
VerificationMethodID: keyID,
PrivKey: privateKey,
},
}

versionID := uuid.NewString()

res, err := cli.CreateDidDoc(tmpDir, payload, signInputs, versionID, testdata.BASE_ACCOUNT_1, helpers.GenerateFees(feeParams.CreateDid.String()))
Expect(err).To(BeNil())
Expect(res.Code).To(BeEquivalentTo(0))

AddReportEntry("Integration", fmt.Sprintf("%sPositive: %s", cli.Green, "can update diddoc with augmented assertionMethod (Ed25519VerificationKey2020)"))
// Update the DID Doc

assertionMethodJSONEscaped2 := func() string {
b, _ := json.Marshal(types.AssertionMethodJSONUnescaped{
Id: keyID,
Type: "Ed25519VerificationKey2020",
Controller: did,
PublicKeyMultibase: &publicKeyMultibase, // arbitrarily chosen, loosely validated
})
return strconv.Quote(string(b))
}()

payload2 := didcli.DIDDocument{
ID: did,
VerificationMethod: []didcli.VerificationMethod{
map[string]any{
"id": keyID,
"type": "Ed25519VerificationKey2020",
"controller": did,
"publicKeyMultibase": publicKeyMultibase,
},
},
Authentication: []string{keyID},
AssertionMethod: []string{keyID, assertionMethodJSONEscaped, assertionMethodJSONEscaped2},
}

versionID = uuid.NewString()

res2, err := cli.UpdateDidDoc(tmpDir, payload2, signInputs, versionID, testdata.BASE_ACCOUNT_1, helpers.GenerateFees(feeParams.UpdateDid.String()))
Expect(err).To(BeNil())
Expect(res2.Code).To(BeEquivalentTo(0))

AddReportEntry("Integration", fmt.Sprintf("%sPositive: %s", cli.Green, "can query diddoc with augmented assertionMethod (Ed25519VerificationKey2020)"))
// Query the DID Doc
resp, err := cli.QueryDidDoc(did)
Expect(err).To(BeNil())

didDoc := resp.Value.DidDoc
Expect(didDoc.Id).To(BeEquivalentTo(did))
Expect(didDoc.Authentication).To(HaveLen(1))
Expect(didDoc.Authentication[0]).To(BeEquivalentTo(keyID))
Expect(didDoc.VerificationMethod).To(HaveLen(1))
Expect(didDoc.VerificationMethod[0].Id).To(BeEquivalentTo(keyID))
Expect(didDoc.VerificationMethod[0].VerificationMethodType).To(BeEquivalentTo("Ed25519VerificationKey2020"))
Expect(didDoc.VerificationMethod[0].Controller).To(BeEquivalentTo(did))
Expect(didDoc.VerificationMethod[0].VerificationMaterial).To(BeEquivalentTo(publicKeyMultibase))
Expect(didDoc.AssertionMethod).To(HaveLen(3))
Expect(didDoc.AssertionMethod[0]).To(BeEquivalentTo(keyID))
Expect(didDoc.AssertionMethod[1]).To(BeEquivalentTo(assertionMethodJSONEscaped))
Expect(didDoc.AssertionMethod[2]).To(BeEquivalentTo(assertionMethodJSONEscaped2))

// Check that DIDDoc is not deactivated
Expect(resp.Value.Metadata.Deactivated).To(BeFalse())

AddReportEntry("Integration", fmt.Sprintf("%sPositive: %s", cli.Green, "can deactivate diddoc with augmented assertionMethod (Ed25519VerificationKey2020)"))
// Deactivate the DID Doc
payload3 := types.MsgDeactivateDidDocPayload{
Id: did,
}

versionID = uuid.NewString()

res3, err := cli.DeactivateDidDoc(tmpDir, payload3, signInputs, versionID, testdata.BASE_ACCOUNT_1, helpers.GenerateFees(feeParams.DeactivateDid.String()))
Expect(err).To(BeNil())
Expect(res3.Code).To(BeEquivalentTo(0))

AddReportEntry("Integration", fmt.Sprintf("%sPositive: %s", cli.Green, "can query deactivated diddoc with augmented assertionMethod (Ed25519VerificationKey2020)"))
// Query the DID Doc

resp2, err := cli.QueryDidDoc(did)
Expect(err).To(BeNil())

didDoc2 := resp2.Value.DidDoc
Expect(didDoc2).To(BeEquivalentTo(didDoc))

// Check that the DID Doc is deactivated
Expect(resp2.Value.Metadata.Deactivated).To(BeTrue())
})
})
10 changes: 10 additions & 0 deletions x/did/types/diddoc_assertion_method.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package types

type AssertionMethodJSONUnescaped struct {
Id string `json:"id"`
Type string `json:"type"`
Controller string `json:"controller"`
PublicKeyBase58 *string `json:"publicKeyBase58,omitempty"`
PublicKeyMultibase *string `json:"publicKeyMultibase,omitempty"`
PublicKeyJwk *string `json:"publicKeyJwk,omitempty"`
}
3 changes: 1 addition & 2 deletions x/did/types/diddoc_diddoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ func (didDoc DidDoc) Validate(allowedNamespaces []string) error {
IsUniqueStrList(), validation.Each(IsDIDUrl(allowedNamespaces, Empty, Empty, Required), HasPrefix(didDoc.Id)),
),
validation.Field(&didDoc.AssertionMethod,
IsUniqueStrList(), validation.Each(IsDIDUrl(allowedNamespaces, Empty, Empty, Required), HasPrefix(didDoc.Id)),
),
IsUniqueStrList(), validation.Each(IsAssertionMethod(allowedNamespaces, didDoc))),
validation.Field(&didDoc.CapabilityInvocation,
IsUniqueStrList(), validation.Each(IsDIDUrl(allowedNamespaces, Empty, Empty, Required), HasPrefix(didDoc.Id)),
),
Expand Down
144 changes: 144 additions & 0 deletions x/did/types/diddoc_diddoc_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package types_test

import (
"encoding/json"
"fmt"
"strconv"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -229,4 +231,146 @@ var _ = DescribeTable("DIDDoc Validation tests", func(testCase DIDDocTestCase) {
isValid: false,
errorMsg: "verification_method: there are verification method duplicates.",
}),
Entry(
"Assertion method is valid",
DIDDocTestCase{
didDoc: &DidDoc{
Id: ValidTestDID,
Controller: []string{ValidTestDID},
VerificationMethod: []*VerificationMethod{
{
Id: fmt.Sprintf("%s#fragment", ValidTestDID),
VerificationMethodType: "Ed25519VerificationKey2020",
Controller: ValidTestDID,
VerificationMaterial: ValidEd25519VerificationKey2020VerificationMaterial,
},
},
AssertionMethod: []string{fmt.Sprintf("%s#fragment", ValidTestDID), func() string {
b, _ := json.Marshal(AssertionMethodJSONUnescaped{
Id: fmt.Sprintf("%s#fragment", ValidTestDID),
Type: "Ed25519VerificationKey2018",
Controller: ValidTestDID,
PublicKeyBase58: &ValidEd25519VerificationKey2018VerificationMaterial, // arbitrarily chosen, loosely validated
})
return strconv.Quote(string(b))
}()},
},
isValid: true,
errorMsg: "",
}),
Entry(
"Assertion method has wrong fragment",
DIDDocTestCase{
didDoc: &DidDoc{
Id: ValidTestDID,
Controller: []string{ValidTestDID},
VerificationMethod: []*VerificationMethod{
{
Id: fmt.Sprintf("%s#fragment", ValidTestDID),
VerificationMethodType: "Ed25519VerificationKey2020",
Controller: ValidTestDID,
VerificationMaterial: ValidEd25519VerificationKey2020VerificationMaterial,
},
},
AssertionMethod: []string{fmt.Sprintf("%s#fragment", ValidTestDID), func() string {
b, _ := json.Marshal(AssertionMethodJSONUnescaped{
Id: fmt.Sprintf("%s#fragment-1", ValidTestDID),
Type: "Ed25519VerificationKey2018",
Controller: ValidTestDID,
PublicKeyBase58: &ValidEd25519VerificationKey2018VerificationMaterial, // arbitrarily chosen, loosely validated
})
return strconv.Quote(string(b))
}()},
},
isValid: false,
errorMsg: "assertionMethod should be a valid key reference within the DID document's verification method",
}),
Entry(
"Assertion method has invalid protobuf value",
DIDDocTestCase{
didDoc: &DidDoc{
Id: ValidTestDID,
Controller: []string{ValidTestDID},
VerificationMethod: []*VerificationMethod{
{
Id: fmt.Sprintf("%s#fragment", ValidTestDID),
VerificationMethodType: "Ed25519VerificationKey2020",
Controller: ValidTestDID,
VerificationMaterial: ValidEd25519VerificationKey2020VerificationMaterial,
},
},
AssertionMethod: []string{func() string {
b, _ := json.Marshal(struct {
Id string `json:"id"`
Type string `json:"type"`
Controller string `json:"controller"`
InvalidField map[string]interface{} `json:"invalidField"`
}{
Id: fmt.Sprintf("%s#fragment", ValidTestDID),
Type: "Ed25519VerificationKey2018",
Controller: ValidTestDID,
InvalidField: map[string]interface{}{"unsupported": []int{1, 2, 3}},
})
return strconv.Quote(string(b))
}()},
},
isValid: false,
errorMsg: "field invalidField is not protobuf-supported",
}),
Entry(
"Assertion method is missing controller value in JSON",
DIDDocTestCase{
didDoc: &DidDoc{
Id: ValidTestDID,
Controller: []string{ValidTestDID},
VerificationMethod: []*VerificationMethod{
{
Id: fmt.Sprintf("%s#fragment", ValidTestDID),
VerificationMethodType: "Ed25519VerificationKey2020",
Controller: ValidTestDID,
VerificationMaterial: ValidEd25519VerificationKey2020VerificationMaterial,
},
},
AssertionMethod: []string{func() string {
b, _ := json.Marshal(struct {
Id string `json:"id"`
Type string `json:"type"`
}{
Id: fmt.Sprintf("%s#fragment", ValidTestDID),
Type: "Ed25519VerificationKey2018",
})
return strconv.Quote(string(b))
}()},
},
isValid: false,
errorMsg: "assertion_method: (0: (controller: cannot be blank.).).",
}),
Entry(
"Assertion method contains unescaped JSON string",
DIDDocTestCase{
didDoc: &DidDoc{
Id: ValidTestDID,
Controller: []string{ValidTestDID},
VerificationMethod: []*VerificationMethod{
{
Id: fmt.Sprintf("%s#fragment", ValidTestDID),
VerificationMethodType: "Ed25519VerificationKey2020",
Controller: ValidTestDID,
VerificationMaterial: ValidEd25519VerificationKey2020VerificationMaterial,
},
},
AssertionMethod: []string{func() string {
b, _ := json.Marshal(struct {
Id string `json:"id"`
Type string `json:"type"` // controller is intentionally missing, no additional fields are necessary as the focal point is the unescaped JSON string, i.e. deserialisation should fail first, before any other validation
}{
Id: fmt.Sprintf("%s#fragment", ValidTestDID),
Type: "Ed25519VerificationKey2018",
})
return string(b)
}()},
},
isValid: false,
errorMsg: "assertionMethod should be a DIDUrl or an Escaped JSON string",
}),
)
10 changes: 5 additions & 5 deletions x/did/types/tx_msg_create_diddoc_payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ func (msg *MsgCreateDidDocPayload) Normalize() {
s.Id = utils.NormalizeDIDUrl(s.Id)
}
msg.Controller = utils.NormalizeDIDList(msg.Controller)
msg.Authentication = utils.NormalizeDIDUrlList(msg.Authentication)
msg.AssertionMethod = utils.NormalizeDIDUrlList(msg.AssertionMethod)
msg.CapabilityInvocation = utils.NormalizeDIDUrlList(msg.CapabilityInvocation)
msg.CapabilityDelegation = utils.NormalizeDIDUrlList(msg.CapabilityDelegation)
msg.KeyAgreement = utils.NormalizeDIDUrlList(msg.KeyAgreement)
msg.Authentication = utils.NormalizeDIDUrlList(msg.Authentication, false)
msg.AssertionMethod = utils.NormalizeDIDUrlList(msg.AssertionMethod, true)
msg.CapabilityInvocation = utils.NormalizeDIDUrlList(msg.CapabilityInvocation, false)
msg.CapabilityDelegation = utils.NormalizeDIDUrlList(msg.CapabilityDelegation, false)
msg.KeyAgreement = utils.NormalizeDIDUrlList(msg.KeyAgreement, false)

msg.VersionId = utils.NormalizeUUID(msg.VersionId)
}
10 changes: 5 additions & 5 deletions x/did/types/tx_msg_update_did_doc_payload.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ func (msg *MsgUpdateDidDocPayload) Normalize() {
s.Id = utils.NormalizeDIDUrl(s.Id)
}
msg.Controller = utils.NormalizeDIDList(msg.Controller)
msg.Authentication = utils.NormalizeDIDUrlList(msg.Authentication)
msg.AssertionMethod = utils.NormalizeDIDUrlList(msg.AssertionMethod)
msg.CapabilityInvocation = utils.NormalizeDIDUrlList(msg.CapabilityInvocation)
msg.CapabilityDelegation = utils.NormalizeDIDUrlList(msg.CapabilityDelegation)
msg.KeyAgreement = utils.NormalizeDIDUrlList(msg.KeyAgreement)
msg.Authentication = utils.NormalizeDIDUrlList(msg.Authentication, false)
msg.AssertionMethod = utils.NormalizeDIDUrlList(msg.AssertionMethod, true)
msg.CapabilityInvocation = utils.NormalizeDIDUrlList(msg.CapabilityInvocation, false)
msg.CapabilityDelegation = utils.NormalizeDIDUrlList(msg.CapabilityDelegation, false)
msg.KeyAgreement = utils.NormalizeDIDUrlList(msg.KeyAgreement, false)

msg.VersionId = utils.NormalizeUUID(msg.VersionId)
}
Loading
Loading