Skip to content

Commit

Permalink
Merge pull request #14 from cheqd/resource-dereferencing
Browse files Browse the repository at this point in the history
feat: Add Resource dereferencing
  • Loading branch information
Toktar authored Jul 14, 2022
2 parents 0d98362 + bffbbc3 commit e3a35d7
Show file tree
Hide file tree
Showing 15 changed files with 598 additions and 121 deletions.
20 changes: 11 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ module github.com/cheqd/did-resolver
go 1.17

require (
github.com/cheqd/cheqd-node v0.5.0
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.23.0
github.com/spf13/cobra v1.2.1
github.com/spf13/cobra v1.5.0
github.com/spf13/viper v1.11.0
github.com/stretchr/testify v1.7.1
google.golang.org/grpc v1.45.0
google.golang.org/grpc v1.46.2
google.golang.org/protobuf v1.28.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
gopkg.in/yaml.v3 v3.0.1
)

require (
Expand All @@ -25,7 +26,7 @@ require (
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/confio/ics23/go v0.7.0 // indirect
github.com/cosmos/btcutil v1.0.4 // indirect
github.com/cosmos/cosmos-sdk v0.45.1 // indirect
github.com/cosmos/cosmos-sdk v0.45.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d // indirect
github.com/dgraph-io/badger/v2 v2.2007.2 // indirect
Expand All @@ -40,6 +41,7 @@ require (
github.com/goccy/go-json v0.9.4 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/google/btree v1.0.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
Expand Down Expand Up @@ -67,9 +69,9 @@ require (
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.11.0 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.30.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect
github.com/spf13/afero v1.8.2 // indirect
Expand All @@ -80,10 +82,10 @@ require (
github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tendermint/tendermint v0.34.15 // indirect
github.com/tendermint/tendermint v0.34.19 // indirect
github.com/tendermint/tm-db v0.6.6 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac // indirect
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
Expand Down
75 changes: 73 additions & 2 deletions go.sum

Large diffs are not rendered by default.

89 changes: 66 additions & 23 deletions services/diddoc_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import (
"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"
)

Expand Down Expand Up @@ -41,12 +43,15 @@ func (ds DIDDocService) MarshallDID(didDoc cheqd.Did) (string, error) {
if err != nil {
return "", err
}
mapDID[verificationMethod] = formatedVerificationMethod
mapDID.Set(verificationMethod, json.RawMessage(formatedVerificationMethod))

// Context changes
if val, ok := mapDID[didContext]; ok {
mapDID["@"+didContext] = val
delete(mapDID, didContext)
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)
Expand All @@ -57,22 +62,56 @@ func (ds DIDDocService) MarshallDID(didDoc cheqd.Did) (string, error) {
}

func (ds DIDDocService) MarshallContentStream(contentStream protoiface.MessageV1, contentType types.ContentType) (string, error) {
var mapContent map[string]interface{}
var mapContent orderedmap.OrderedMap
var err error
var context types.ContentType
if contentType == types.DIDJSONLD || contentType == types.JSONLD {
context = types.DIDSchemaJSONLD
}

// VerKey changes, marshal
if verificationMethod, ok := contentStream.(*cheqd.VerificationMethod); ok {
mapContent, err = ds.prepareJWKPubkey(verificationMethod)
} else {
switch contentStream := contentStream.(type) {
case *cheqd.VerificationMethod:
mapContent, err = ds.prepareJWKPubkey(contentStream)
case *cheqd.Did:
contentStream.Context = []string{string(context)}
jsonDid, err := ds.MarshallDID(*contentStream)
if err != nil {
return "", err
}
return string(jsonDid), nil
case *resource.Resource:
dResource := types.DereferencedResource{
Context: []string{string(context)},
CollectionId: contentStream.Header.CollectionId,
Id: contentStream.Header.Id,
Name: contentStream.Header.Name,
ResourceType: contentStream.Header.ResourceType,
MediaType: contentStream.Header.MediaType,
Created: contentStream.Header.Created,
Checksum: contentStream.Header.Checksum,
PreviousVersionId: contentStream.Header.PreviousVersionId,
NextVersionId: contentStream.Header.NextVersionId,
Data: contentStream.Data,
}
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 contentType == types.DIDJSONLD || contentType == types.JSONLD {
mapContent["@"+didContext] = types.DIDSchemaJSONLD
if context != "" {
mapContent.Set("@"+didContext, context)
mapContent.Sort(func(a *orderedmap.Pair, b *orderedmap.Pair) bool {
return a.Key() == "@"+didContext
})
}

result, err := json.Marshal(mapContent)
Expand All @@ -97,40 +136,44 @@ func (DIDDocService) GetDIDFragment(fragmentId string, didDoc cheqd.Did) protoif
return nil
}

func (ds DIDDocService) prepareJWKPubkey(verificationMethod *cheqd.VerificationMethod) (map[string]interface{}, error) {
func (ds DIDDocService) prepareJWKPubkey(verificationMethod *cheqd.VerificationMethod) (orderedmap.OrderedMap, error) {
methodJson, err := ds.protoToMap(verificationMethod)
if err != nil {
return nil, err
return *orderedmap.New(), err
}
if len(verificationMethod.PublicKeyJwk) > 0 {
methodJson[publicKeyJwk] = cheqd.PubKeyJWKToMap(verificationMethod.PublicKeyJwk)
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) ([]map[string]interface{}, error) {
var verMethodList []map[string]interface{}
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 nil, err
return []byte{}, err
}
verMethodList = append(verMethodList, methodJson)
}
return verMethodList, nil
return json.Marshal(verMethodList)
}

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

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

return mapObj, err
return *mapObj, err
}
5 changes: 2 additions & 3 deletions services/diddoc_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,10 @@ func TestMarshallDID(t *testing.T) {
VerificationMethod: []*cheqd.VerificationMethod{&verificationMethod1, &verificationMethod2},
}

expectedDID := "{\"@context\":[\"test\"],\"id\":\"did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue\",\"verificationMethod\":[{\"controller\":\"did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue\",\"id\":\"did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue#verkey\",\"publicKeyMultibase\":\"zAKJP3f7BD6W4iWEQ9jwndVTCBq8ua2Utt8EEjJ6Vxsf\",\"type\":\"Ed25519VerificationKey2020\"},{\"controller\":\"did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue\",\"id\":\"did:cheqd:mainnet:N22KY2Dyvmuu2PyyqSFKue#verkey\",\"publicKeyJwk\":{\"crv\":\"Ed25519\",\"kty\":\"OKP\",\"x\":\"VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ\"},\"type\":\"JsonWebKey2020\"}]}"

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)

fmt.Println(jsonDID)
require.EqualValues(t, jsonDID, expectedDID)
require.EqualValues(t, expectedDID, jsonDID)
require.Empty(t, err)
}
48 changes: 40 additions & 8 deletions services/ledger_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import (

cheqd "github.com/cheqd/cheqd-node/x/cheqd/types"
cheqdUtils "github.com/cheqd/cheqd-node/x/cheqd/utils"
resource "github.com/cheqd/cheqd-node/x/resource/types"
"github.com/rs/zerolog/log"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

type LedgerServiceI interface {
QueryDIDDoc(did string) (cheqd.Did, cheqd.Metadata, bool, error)
QueryResource(collectionDid string, resourceId string) (resource.Resource, bool, error)
GetNamespaces() []string
}

Expand All @@ -43,20 +45,13 @@ func (ls LedgerService) QueryDIDDoc(did string) (cheqd.Did, cheqd.Metadata, bool
return cheqd.Did{}, cheqd.Metadata{}, false, fmt.Errorf("namespace not supported: %s", namespace)
}

log.Info().Msgf("Connecting to the ledger: %s", serverAddr)
conn, err := ls.openGRPCConnection(serverAddr)
if err != nil {
log.Error().Err(err).Msg("QueryDIDDoc: failed connection")
return cheqd.Did{}, cheqd.Metadata{}, false, err
}

defer func(conn *grpc.ClientConn) {
err := conn.Close()
if err != nil {
log.Panic().Err(err).Msg("QueryDIDDoc: failed to close connection")
panic(err)
}
}(conn)
defer mustCloseGRPCConnection(conn)

log.Info().Msgf("Querying did doc: %s", did)
client := cheqd.NewQueryClient(conn)
Expand All @@ -68,6 +63,32 @@ func (ls LedgerService) QueryDIDDoc(did string) (cheqd.Did, cheqd.Metadata, bool
return *didDocResponse.Did, *didDocResponse.Metadata, true, err
}

func (ls LedgerService) QueryResource(did string, resourceId string) (resource.Resource, bool, error) {
collectionId, namespace, _, _ := cheqdUtils.TrySplitDID(did)
serverAddr, namespaceFound := ls.ledgers[namespace]
if !namespaceFound {
return resource.Resource{}, false, fmt.Errorf("namespace not supported: %s", namespace)
}

conn, err := ls.openGRPCConnection(serverAddr)
if err != nil {
log.Error().Err(err).Msg("QueryResource: failed connection")
return resource.Resource{}, false, err
}

defer mustCloseGRPCConnection(conn)

log.Info().Msgf("Querying did resource: %s, %s", did, resourceId)

client := resource.NewQueryClient(conn)
resourceResponse, err := client.Resource(context.Background(), &resource.QueryGetResourceRequest{CollectionId: collectionId, Id: resourceId})
if err != nil {
return resource.Resource{}, false, nil
}

return *resourceResponse.Resource, true, err
}

func (ls *LedgerService) RegisterLedger(namespace string, url string) error {
if namespace == "" {
err := errors.New("namespace cannot be empty")
Expand Down Expand Up @@ -109,6 +130,17 @@ func (ls LedgerService) openGRPCConnection(addr string) (conn *grpc.ClientConn,
return conn, nil
}

func mustCloseGRPCConnection(conn *grpc.ClientConn) {
if conn == nil {
return
}
err := conn.Close()
if err != nil {
log.Panic().Err(err).Msg("QueryDIDDoc: failed to close connection")
panic(err)
}
}

func (ls LedgerService) GetNamespaces() []string {
keys := make([]string, 0, len(ls.ledgers))
for k := range ls.ledgers {
Expand Down
34 changes: 34 additions & 0 deletions services/ledger_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

cheqd "github.com/cheqd/cheqd-node/x/cheqd/types"
resource "github.com/cheqd/cheqd-node/x/resource/types"
"github.com/stretchr/testify/require"
)

Expand Down Expand Up @@ -42,3 +43,36 @@ func TestQueryDIDDoc(t *testing.T) {
})
}
}

func TestQueryResource(t *testing.T) {
subtests := []struct {
name string
collectionDid string
resourceId string
expectedResource resource.Resource
expectedIsFound bool
expectedError error
}{
{
name: "DeadlineExceeded",
collectionDid: "321",
resourceId: "123",
expectedResource: resource.Resource{},
expectedIsFound: false,
expectedError: errors.New("namespace not supported: "),
},
}

for _, subtest := range subtests {
t.Run(subtest.name, func(t *testing.T) {
timeout, err := time.ParseDuration("5s")
require.NoError(t, err)

ledgerService := NewLedgerService(timeout, false)
resource, isFound, err := ledgerService.QueryResource(subtest.collectionDid, subtest.resourceId)
require.EqualValues(t, subtest.expectedResource, resource)
require.EqualValues(t, subtest.expectedIsFound, isFound)
require.EqualValues(t, subtest.expectedError, err)
})
}
}
Loading

0 comments on commit e3a35d7

Please sign in to comment.