Skip to content

Commit

Permalink
fix: Change DID Doc Metadata for following the ADR + fix resource che…
Browse files Browse the repository at this point in the history
…cksum [DEV-1640] (#37)

* fix: Change metadata format

* fix: checksum calculation

* fix: linter

* feat: change to pretty JSONs

* fix tests

* fix tests

* fix linter

* fix tests

* linter

* change data model approach

* Update resource output + tests

* Update integration tests

* Fixed typo

* Update go.mod

* Pickup go.mod from files

Co-authored-by: Ankur Banerjee <[email protected]>
  • Loading branch information
Toktar and ankurdotb authored Aug 18, 2022
1 parent 28337ab commit e643552
Show file tree
Hide file tree
Showing 21 changed files with 596 additions and 666 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

- uses: actions/setup-go@v3
with:
go-version: 1.17
go-version-file: ./go.mod

- name: Run Golang unit tests
run: go test -v ./...
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:

- uses: actions/setup-go@v3
with:
go-version: '1.17'
go-version-file: ./go.mod

# Node.js setup is needed to run Semantic Release
- uses: actions/setup-node@v3
Expand Down
13 changes: 9 additions & 4 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,17 @@ func serve() {
if utils.IsCollectionResourcesPathRedirect(path) {
return c.Redirect(http.StatusMovedPermanently, "all")
}
responseBody, status, contentType := requestService.ProcessDIDRequest(didUrl, types.ResolutionOption{Accept: requestedContentType})
resolutionResponse := requestService.ProcessDIDRequest(didUrl, types.ResolutionOption{Accept: requestedContentType})

log.Debug().Msgf("Response body: %s", responseBody)
c.Response().Header().Set(echo.HeaderContentType, resolutionResponse.GetContentType())

c.Response().Header().Set(echo.HeaderContentType, string(contentType))
return c.Blob(status, string(contentType), responseBody)
// if contentType != dereferencingOptions.Accept {
// return didDereferencing.ContentStream, statusCode, contentType
// }
if utils.IsResourceDataPath(path) && resolutionResponse.GetStatus() == http.StatusOK {
return c.Blob(resolutionResponse.GetStatus(), resolutionResponse.GetContentType(), resolutionResponse.GetBytes())
}
return c.JSONPretty(resolutionResponse.GetStatus(), resolutionResponse, " ")
})

log.Info().Msg("Starting listener")
Expand Down
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ go 1.17

require (
github.com/cheqd/cheqd-node v0.6.0
github.com/iancoleman/orderedmap v0.2.0
github.com/labstack/echo/v4 v4.7.2
github.com/rs/zerolog v1.27.0
github.com/spf13/cobra v1.5.0
github.com/spf13/viper v1.12.0
github.com/stretchr/testify v1.8.0
google.golang.org/grpc v1.48.0
google.golang.org/protobuf v1.28.1
gopkg.in/yaml.v3 v3.0.1
)

Expand Down Expand Up @@ -86,14 +84,15 @@ require (
github.com/tendermint/tm-db v0.6.6 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

require (
github.com/gogo/protobuf v1.3.3 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/protobuf v1.5.2
github.com/golang/protobuf v1.5.2 // indirect
github.com/labstack/gommon v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,6 @@ github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT
github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 h1:uUjLpLt6bVvZ72SQc/B4dXcPBw4Vgd7soowdRl52qEM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo=
github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA=
github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
Expand Down
160 changes: 3 additions & 157 deletions services/diddoc_service.go
Original file line number Diff line number Diff line change
@@ -1,178 +1,24 @@
package services

import (

// jsonpb Marshaller is deprecated, but is needed because there's only one way to proto
// marshal in combination with our proto generator version
"encoding/json"
"fmt"
"strings"

cheqd "github.com/cheqd/cheqd-node/x/cheqd/types"
resource "github.com/cheqd/cheqd-node/x/resource/types"
"github.com/cheqd/did-resolver/types"
"github.com/golang/protobuf/jsonpb" //nolint
"github.com/iancoleman/orderedmap"
"google.golang.org/protobuf/runtime/protoiface"
)

type DIDDocService struct{}

const (
verificationMethod = "verificationMethod"
publicKeyJwk = "publicKeyJwk"
didContext = "context"
)

func (DIDDocService) MarshallProto(protoObject protoiface.MessageV1) (string, error) {
var m jsonpb.Marshaler
jsonObject, err := m.MarshalToString(protoObject)
if err != nil {
return "", err
}
return jsonObject, nil
}

func (ds DIDDocService) MarshallDID(didDoc cheqd.Did) (string, error) {
mapDID, err := ds.protoToMap(&didDoc)
if err != nil {
return "", err
}

// VerKey changes
formatedVerificationMethod, err := ds.MarshallVerificationMethod(didDoc.VerificationMethod)
if err != nil {
return "", err
}
mapDID.Set(verificationMethod, json.RawMessage(formatedVerificationMethod))

// Context changes
if val, ok := mapDID.Get(didContext); ok {
mapDID.Set("@"+didContext, val)
mapDID.Delete(didContext)
mapDID.Sort(func(a *orderedmap.Pair, b *orderedmap.Pair) bool {
return a.Key() == "@"+didContext
})
}

result, err := json.Marshal(mapDID)
if err != nil {
return "", err
}
return string(result), nil
}

func (ds DIDDocService) MarshallContentStream(contentStream protoiface.MessageV1, contentType types.ContentType) (string, error) {
var mapContent orderedmap.OrderedMap
var err error
var context []string
if contentType == types.DIDJSONLD || contentType == types.JSONLD {
context = []string{types.DIDSchemaJSONLD}
}
switch contentStream := contentStream.(type) {
case *cheqd.VerificationMethod:
mapContent, err = ds.prepareJWKPubkey(contentStream)
case *cheqd.Did:
contentStream.Context = context
jsonDid, err := ds.MarshallDID(*contentStream)
if err != nil {
return "", err
}
return string(jsonDid), nil
case *resource.ResourceHeader:
dResource := types.DereferencedResource{
Context: context,
CollectionId: contentStream.CollectionId,
Id: contentStream.Id,
Name: contentStream.Name,
ResourceType: contentStream.ResourceType,
MediaType: contentStream.MediaType,
Created: contentStream.Created,
Checksum: fmt.Sprintf("%x", contentStream.Checksum),
PreviousVersionId: contentStream.PreviousVersionId,
NextVersionId: contentStream.NextVersionId,
}
jsonResource, err := json.Marshal(dResource)
if err != nil {
return "", err
}
return string(jsonResource), nil
default:
mapContent, err = ds.protoToMap(contentStream)
}

if err != nil {
return "", err
}

// Context changes
if len(context) != 0 {
mapContent.Set("@"+didContext, context[0])
mapContent.Sort(func(a *orderedmap.Pair, b *orderedmap.Pair) bool {
return a.Key() == "@"+didContext
})
}

result, err := json.Marshal(mapContent)
if err != nil {
return "", err
}
return string(result), nil
}

func (DIDDocService) GetDIDFragment(fragmentId string, didDoc cheqd.Did) protoiface.MessageV1 {
func (DIDDocService) GetDIDFragment(fragmentId string, didDoc types.DidDoc) types.ContentStreamI {
for _, verMethod := range didDoc.VerificationMethod {
if strings.Contains(verMethod.Id, fragmentId) {
return verMethod
return &verMethod
}
}
for _, service := range didDoc.Service {
if strings.Contains(service.Id, fragmentId) {
return service
return &service
}
}

return nil
}

func (ds DIDDocService) prepareJWKPubkey(verificationMethod *cheqd.VerificationMethod) (orderedmap.OrderedMap, error) {
methodJson, err := ds.protoToMap(verificationMethod)
if err != nil {
return *orderedmap.New(), err
}
if len(verificationMethod.PublicKeyJwk) > 0 {
jsonKey, err := cheqd.PubKeyJWKToJson(verificationMethod.PublicKeyJwk)
if err != nil {
return *orderedmap.New(), err
}
methodJson.Set(publicKeyJwk, json.RawMessage(jsonKey))
}
return methodJson, nil
}

func (ds DIDDocService) MarshallVerificationMethod(verificationMethod []*cheqd.VerificationMethod) ([]byte, error) {
var verMethodList []orderedmap.OrderedMap
for _, value := range verificationMethod {
methodJson, err := ds.prepareJWKPubkey(value)
if err != nil {
return []byte{}, err
}
verMethodList = append(verMethodList, methodJson)
}
return json.Marshal(verMethodList)
}

func (ds DIDDocService) protoToMap(protoObject protoiface.MessageV1) (orderedmap.OrderedMap, error) {
mapObj := orderedmap.New()
jsonObj, err := ds.MarshallProto(protoObject)
if err != nil {
return *mapObj, err
}

err = json.Unmarshal([]byte(jsonObj), &mapObj)
if err != nil {
return *mapObj, err
}

return *mapObj, err
}
63 changes: 35 additions & 28 deletions services/diddoc_service_test.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,49 @@
package services

import (
"fmt"
"testing"

cheqd "github.com/cheqd/cheqd-node/x/cheqd/types"
"github.com/cheqd/did-resolver/types"
"github.com/cheqd/did-resolver/utils"
"github.com/stretchr/testify/require"
)

func TestMarshallDID(t *testing.T) {
didDocService := DIDDocService{}
verificationMethod1 := cheqd.VerificationMethod{
Id: "did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue#verkey",
Type: "Ed25519VerificationKey2020",
Controller: "did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue",
PublicKeyMultibase: "zAKJP3f7BD6W4iWEQ9jwndVTCBq8ua2Utt8EEjJ6Vxsf",
}
func TestDIDDocFragment(t *testing.T) {
validDIDDoc := types.NewDidDoc(utils.ValidDIDDoc())

verificationMethod2 := cheqd.VerificationMethod{
Id: "did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue#verkey",
Type: "JsonWebKey2020",
Controller: "did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue",
PublicKeyJwk: []*cheqd.KeyValuePair{
{Key: "kty", Value: "OKP"},
{Key: "crv", Value: "Ed25519"},
{Key: "x", Value: "VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ"},
subtests := []struct {
name string
fragmentId string
didDoc types.DidDoc
expectedFragment types.ContentStreamI
}{
{
name: "successful VerificationMethod finding",
fragmentId: validDIDDoc.VerificationMethod[0].Id,
didDoc: *validDIDDoc,
expectedFragment: &validDIDDoc.VerificationMethod[0],
},
{
name: "successful Service finding",
fragmentId: validDIDDoc.Service[0].Id,
didDoc: *validDIDDoc,
expectedFragment: &validDIDDoc.Service[0],
},
{
name: "Fragment is not found",
fragmentId: "fake_id",
didDoc: *validDIDDoc,
expectedFragment: nil,
},
}
didDoc := cheqd.Did{
Context: []string{"test"},
Id: "did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue",
VerificationMethod: []*cheqd.VerificationMethod{&verificationMethod1, &verificationMethod2},
}

expectedDID := "{\"@context\":[\"test\"],\"id\":\"did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue\",\"verificationMethod\":[{\"id\":\"did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue#verkey\",\"type\":\"Ed25519VerificationKey2020\",\"controller\":\"did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue\",\"publicKeyMultibase\":\"zAKJP3f7BD6W4iWEQ9jwndVTCBq8ua2Utt8EEjJ6Vxsf\"},{\"id\":\"did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue#verkey\",\"type\":\"JsonWebKey2020\",\"controller\":\"did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue\",\"publicKeyJwk\":{\"crv\":\"Ed25519\",\"kty\":\"OKP\",\"x\":\"VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ\"}}]}"
jsonDID, err := didDocService.MarshallDID(didDoc)
for _, subtest := range subtests {
t.Run(subtest.name, func(t *testing.T) {
didDocService := DIDDocService{}

fragment := didDocService.GetDIDFragment(subtest.fragmentId, subtest.didDoc)

fmt.Println(jsonDID)
require.EqualValues(t, expectedDID, jsonDID)
require.Empty(t, err)
require.EqualValues(t, subtest.expectedFragment, fragment)
})
}
}
Loading

0 comments on commit e643552

Please sign in to comment.