Skip to content

Commit

Permalink
feat: Update AssertionMethod Validator (#796)
Browse files Browse the repository at this point in the history
* feat: Update AssertionMethod Validator

* Add relevant tests

* Add fragment validation & tests

* Add protobuf validation in json

* Remove debug statement

* Removed redundant

* Added indicative integration tests + reusable types

* Adjusted literals

* Added explicit message server assertionMethod validation

* Adjusted serialised field

---------

Co-authored-by: Tasos Derisiotis <[email protected]>
  • Loading branch information
DaevMithran and Eengineer1 authored Oct 17, 2024
1 parent db3c40e commit 156d9e1
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 14 deletions.
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

0 comments on commit 156d9e1

Please sign in to comment.