diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7cb4400d..57c82382 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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 ./... diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8e22e6df..f9fc7b24 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -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 diff --git a/cmd/serve.go b/cmd/serve.go index fe423116..054fe20a 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -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") diff --git a/go.mod b/go.mod index 23a3b163..314f1c0e 100644 --- a/go.mod +++ b/go.mod @@ -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 ) @@ -86,6 +84,7 @@ 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 ) @@ -93,7 +92,7 @@ require ( 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 diff --git a/go.sum b/go.sum index 1015baa3..8299c5c4 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/services/diddoc_service.go b/services/diddoc_service.go index e2881cd8..77651eb1 100644 --- a/services/diddoc_service.go +++ b/services/diddoc_service.go @@ -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 -} diff --git a/services/diddoc_service_test.go b/services/diddoc_service_test.go index 17152176..25ec42ad 100644 --- a/services/diddoc_service_test.go +++ b/services/diddoc_service_test.go @@ -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) + }) + } } diff --git a/services/request_service.go b/services/request_service.go index 57694f15..8b6f5b99 100644 --- a/services/request_service.go +++ b/services/request_service.go @@ -1,10 +1,6 @@ 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" - "github.com/rs/zerolog/log" cheqdTypes "github.com/cheqd/cheqd-node/x/cheqd/types" @@ -12,7 +8,6 @@ import ( resourceTypes "github.com/cheqd/cheqd-node/x/resource/types" "github.com/cheqd/did-resolver/types" "github.com/cheqd/did-resolver/utils" - "google.golang.org/protobuf/runtime/protoiface" ) type RequestService struct { @@ -32,74 +27,18 @@ func NewRequestService(didMethod string, ledgerService LedgerServiceI) RequestSe } } -func (rs RequestService) ProcessDIDRequest(didUrl string, resolutionOptions types.ResolutionOption) ([]byte, int, types.ContentType) { - var result []byte - var statusCode int - contentType := resolutionOptions.Accept +func (rs RequestService) ProcessDIDRequest(didUrl string, resolutionOptions types.ResolutionOption) types.ResolutionResultI { + var result types.ResolutionResultI + did, path, query, fragmentId, _ := cheqdUtils.TrySplitDIDUrl(didUrl) + log.Warn().Msgf("Query %s %s %s %s ", did, path, query, fragmentId) if utils.IsDidUrl(didUrl) { log.Trace().Msgf("Dereferencing %s", didUrl) - result, statusCode, contentType = rs.prepareDereferencingResult(didUrl, types.DereferencingOption(resolutionOptions)) + result = rs.Dereference(didUrl, types.DereferencingOption(resolutionOptions)) } else { log.Trace().Msgf("Resolving %s", didUrl) - result, statusCode = rs.prepareResolutionResult(didUrl, resolutionOptions) - } - return result, statusCode, contentType -} - -func (rs RequestService) prepareResolutionResult(did string, resolutionOptions types.ResolutionOption) ([]byte, int) { - didResolution := rs.Resolve(did, resolutionOptions) - - resolutionMetadata, mErr1 := json.Marshal(didResolution.ResolutionMetadata) - didDoc, mErr2 := rs.didDocService.MarshallDID(didResolution.Did) - metadata, mErr3 := json.Marshal(&didResolution.Metadata) - if mErr1 != nil || mErr2 != nil || mErr3 != nil { - log.Error().Errs("errors", []error{mErr1, mErr2, mErr3}).Msg("Marshalling error") - return createJsonResolutionInternalError(resolutionMetadata) - } - - if didResolution.ResolutionMetadata.ResolutionError != "" { - didDoc, metadata = "", []byte{} - } - - result, err := createJsonResolution(didDoc, string(metadata), string(resolutionMetadata)) - if err != nil { - log.Error().Err(err).Msg("Marshalling error") - return createJsonResolutionInternalError([]byte{}) + result = rs.Resolve(didUrl, resolutionOptions) } - return result, didResolution.ResolutionMetadata.ResolutionError.GetStatusCode() -} - -func (rs RequestService) prepareDereferencingResult(didUrl string, dereferencingOptions types.DereferencingOption) ([]byte, int, types.ContentType) { - log.Info().Msgf("Dereferencing %s", didUrl) - contentType := dereferencingOptions.Accept - - didDereferencing, statusCode := rs.Dereference(didUrl, dereferencingOptions) - - dereferencingMetadata, mErr1 := json.Marshal(didDereferencing.DereferencingMetadata) - metadata, mErr2 := json.Marshal(didDereferencing.Metadata) - if mErr1 != nil || mErr2 != nil { - log.Error().Errs("errors", []error{mErr1, mErr2}).Msg("Marshalling error") - response, errorStatusCode := createJsonDereferencingInternalError([]byte{}) - return response, errorStatusCode, contentType - } - - if didDereferencing.DereferencingMetadata.ResolutionError != "" { - didDereferencing.ContentStream = nil - metadata = []byte{} - } else { - contentType = didDereferencing.DereferencingMetadata.ContentType - if contentType != dereferencingOptions.Accept { - return didDereferencing.ContentStream, statusCode, contentType - } - } - - result, err := createJsonDereferencing(didDereferencing.ContentStream, string(metadata), string(dereferencingMetadata)) - if err != nil { - log.Error().Err(err).Msg("Marshalling error") - response, errorStatusCode := createJsonDereferencingInternalError(dereferencingMetadata) - return response, errorStatusCode, dereferencingOptions.Accept - } - return result, statusCode, contentType + return result } // https://w3c-ccg.github.io/did-resolution/#resolving @@ -119,7 +58,7 @@ func (rs RequestService) Resolve(did string, resolutionOptions types.ResolutionO } - didDoc, metadata, isFound, err := rs.ledgerService.QueryDIDDoc(did) + protoDidDoc, metadata, isFound, err := rs.ledgerService.QueryDIDDoc(did) if err != nil { didResolutionMetadata.ResolutionError = types.InternalError return types.DidResolution{ResolutionMetadata: didResolutionMetadata} @@ -135,34 +74,29 @@ func (rs RequestService) Resolve(did string, resolutionOptions types.ResolutionO didResolutionMetadata.ResolutionError = types.NotFoundError return types.DidResolution{ResolutionMetadata: didResolutionMetadata} } - + didDoc := types.NewDidDoc(protoDidDoc) if didResolutionMetadata.ContentType == types.DIDJSONLD || didResolutionMetadata.ContentType == types.JSONLD { - didDoc.Context = append(didDoc.Context, types.DIDSchemaJSONLD) + didDoc.AddContext(types.DIDSchemaJSONLD) } else { - didDoc.Context = []string{} + didDoc.RemoveContext() } return types.DidResolution{Did: didDoc, Metadata: resolvedMetadata, ResolutionMetadata: didResolutionMetadata} } // https://w3c-ccg.github.io/did-resolution/#dereferencing -func (rs RequestService) Dereference(didUrl string, dereferenceOptions types.DereferencingOption) (types.DidDereferencing, int) { +func (rs RequestService) Dereference(didUrl string, dereferenceOptions types.DereferencingOption) types.DidDereferencing { did, path, query, fragmentId, err := cheqdUtils.TrySplitDIDUrl(didUrl) log.Info().Msgf("did: %s, path: %s, query: %s, fragmentId: %s", did, path, query, fragmentId) - if !dereferenceOptions.Accept.IsSupported() { - dereferencingMetadata := types.NewDereferencingMetadata(did, types.JSON, types.RepresentationNotSupportedError) - return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata}, dereferencingMetadata.ResolutionError.GetStatusCode() - } - if err != nil || !cheqdUtils.IsValidDIDUrl(didUrl, "", []string{}) { dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.InvalidDIDUrlError) - return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata}, dereferencingMetadata.ResolutionError.GetStatusCode() + return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata} } // TODO: implement if query != "" { dereferencingMetadata := types.NewDereferencingMetadata(didUrl, dereferenceOptions.Accept, types.RepresentationNotSupportedError) - return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata}, dereferencingMetadata.ResolutionError.GetStatusCode() + return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata} } var didDereferencing types.DidDereferencing @@ -172,7 +106,19 @@ func (rs RequestService) Dereference(didUrl string, dereferenceOptions types.Der didDereferencing = rs.dereferenceSecondary(did, fragmentId, dereferenceOptions) } - return didDereferencing, didDereferencing.DereferencingMetadata.ResolutionError.GetStatusCode() + if didDereferencing.DereferencingMetadata.ResolutionError != "" { + didDereferencing.ContentStream = nil + didDereferencing.Metadata = types.ResolutionDidDocMetadata{} + return didDereferencing + } + + if dereferenceOptions.Accept == types.DIDJSONLD || dereferenceOptions.Accept == types.JSONLD { + didDereferencing.ContentStream.AddContext(types.DIDSchemaJSONLD) + } else { + didDereferencing.ContentStream.RemoveContext() + } + + return didDereferencing } func (rs RequestService) dereferencePrimary(path string, did string, dereferenceOptions types.DereferencingOption) types.DidDereferencing { @@ -181,6 +127,11 @@ func (rs RequestService) dereferencePrimary(path string, did string, dereference } func (rs RequestService) dereferenceSecondary(did string, fragmentId string, dereferenceOptions types.DereferencingOption) types.DidDereferencing { + if !dereferenceOptions.Accept.IsSupported() { + dereferencingMetadata := types.NewDereferencingMetadata(did, types.JSON, types.RepresentationNotSupportedError) + return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata} + } + didResolution := rs.Resolve(did, types.ResolutionOption(dereferenceOptions)) dereferencingMetadata := types.DereferencingMetadata(didResolution.ResolutionMetadata) @@ -190,26 +141,18 @@ func (rs RequestService) dereferenceSecondary(did string, fragmentId string, der metadata := didResolution.Metadata - var protoContent protoiface.MessageV1 + var contentStream types.ContentStreamI if fragmentId != "" { - protoContent = rs.didDocService.GetDIDFragment(fragmentId, didResolution.Did) + contentStream = rs.didDocService.GetDIDFragment(fragmentId, *didResolution.Did) metadata = types.TransformToFragmentMetadata(metadata) } else { - protoContent = &didResolution.Did + contentStream = didResolution.Did } - if protoContent == nil { + if contentStream == nil { dereferencingMetadata := types.NewDereferencingMetadata(did, dereferenceOptions.Accept, types.NotFoundError) return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata} } - - jsonFragment, err := rs.didDocService.MarshallContentStream(protoContent, dereferenceOptions.Accept) - if err != nil { - dereferencingMetadata := types.NewDereferencingMetadata(did, dereferenceOptions.Accept, types.InternalError) - return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata} - } - contentStream := json.RawMessage(jsonFragment) - return types.DidDereferencing{ContentStream: contentStream, Metadata: metadata, DereferencingMetadata: dereferencingMetadata} } @@ -223,75 +166,3 @@ func (rs RequestService) ResolveMetadata(did string, metadata cheqdTypes.Metadat } return types.NewResolutionDidDocMetadata(did, metadata, resources), "" } - -func createJsonResolution(didDoc string, metadata string, resolutionMetadata string) ([]byte, error) { - if didDoc == "" { - didDoc = "null" - } - - if metadata == "" { - metadata = "[]" - } - - response := struct { - DidResolutionMetadata json.RawMessage `json:"didResolutionMetadata"` - DidDocument json.RawMessage `json:"didDocument"` - DidDocumentMetadata json.RawMessage `json:"didDocumentMetadata"` - }{ - DidResolutionMetadata: json.RawMessage(resolutionMetadata), - DidDocument: json.RawMessage(didDoc), - DidDocumentMetadata: json.RawMessage(metadata), - } - - respJson, err := json.Marshal(&response) - if err != nil { - log.Error().Err(err).Msg("Failed to marshal response") - return []byte{}, err - } - - return respJson, nil -} - -func createJsonDereferencing(contentStream json.RawMessage, metadata string, dereferencingMetadata string) ([]byte, error) { - if contentStream == nil { - contentStream = json.RawMessage("null") - } - - if metadata == "" { - metadata = "[]" - } - - response := struct { - ContentStream json.RawMessage `json:"contentStream"` - ContentMetadata json.RawMessage `json:"contentMetadata"` - DereferencingMetadata json.RawMessage `json:"dereferencingMetadata"` - }{ - ContentStream: contentStream, - ContentMetadata: json.RawMessage(metadata), - DereferencingMetadata: json.RawMessage(dereferencingMetadata), - } - - respJson, err := json.Marshal(&response) - if err != nil { - log.Error().Err(err).Msg("Failed to marshal response") - return []byte{}, err - } - - return respJson, nil -} - -func createJsonDereferencingInternalError(dereferencingMetadata []byte) ([]byte, int) { - result, mErr := createJsonDereferencing(nil, "", string(dereferencingMetadata)) - if mErr != nil { - return []byte{}, types.InternalError.GetStatusCode() - } - return result, types.InternalError.GetStatusCode() -} - -func createJsonResolutionInternalError(resolutionMetadata []byte) ([]byte, int) { - result, mErr := createJsonResolution("", "", string(resolutionMetadata)) - if mErr != nil { - return []byte{}, types.InternalError.GetStatusCode() - } - return result, types.InternalError.GetStatusCode() -} diff --git a/services/request_service_test.go b/services/request_service_test.go index ed573c81..7272e771 100644 --- a/services/request_service_test.go +++ b/services/request_service_test.go @@ -1,77 +1,16 @@ package services import ( - "crypto/sha256" "fmt" "testing" 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/cheqd/did-resolver/utils" "github.com/stretchr/testify/require" ) -const ( - validIdentifier = "N22KY2Dyvmuu2Pyy" - validMethod = "cheqd" - validNamespace = "mainnet" - validDid = "did:" + validMethod + ":" + validNamespace + ":" + validIdentifier - validResourceId = "a09abea0-22e0-4b35-8f70-9cc3a6d0b5fd" - validPubKeyJWK = "{" + - "\"crv\":\"Ed25519\"," + - "\"kid\":\"_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A\"," + - "\"kty\":\"OKP\"," + - "\"x\":\"VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ\"" + - "}" -) - -func validVerificationMethod() cheqd.VerificationMethod { - return cheqd.VerificationMethod{ - Id: validDid + "#key-1", - Type: "JsonWebKey2020", - Controller: validDid, - PublicKeyJwk: cheqd.JSONToPubKeyJWK(validPubKeyJWK), - } -} - -func validService() cheqd.Service { - return cheqd.Service{ - Id: validDid + "#service-1", - Type: "DIDCommMessaging", - ServiceEndpoint: "endpoint", - } -} - -func validDIDDoc() cheqd.Did { - service := validService() - verificationMethod := validVerificationMethod() - - return cheqd.Did{ - Id: validDid, - VerificationMethod: []*cheqd.VerificationMethod{&verificationMethod}, - Service: []*cheqd.Service{&service}, - } -} - -func validResource() resource.Resource { - data := []byte("{\"attr\":[\"name\",\"age\"]}") - return resource.Resource{ - Header: &resource.ResourceHeader{ - CollectionId: validIdentifier, - Id: validResourceId, - Name: "Existing Resource Name", - ResourceType: "CL-Schema", - MediaType: "application/json", - Checksum: sha256.New().Sum(data), - }, - Data: data, - } -} - -func validMetadata() cheqd.Metadata { - return cheqd.Metadata{VersionId: "test_version_id", Deactivated: false, Resources: []string{validResourceId}} -} - type MockLedgerService struct { Did cheqd.Did Metadata cheqd.Metadata @@ -113,9 +52,9 @@ func (ls MockLedgerService) GetNamespaces() []string { } func TestResolve(t *testing.T) { - validDIDDoc := validDIDDoc() - validMetadata := validMetadata() - validResource := validResource() + validDIDDoc := utils.ValidDIDDoc() + validMetadata := utils.ValidMetadata() + validResource := utils.ValidResource() subtests := []struct { name string ledgerService MockLedgerService @@ -123,7 +62,7 @@ func TestResolve(t *testing.T) { identifier string method string namespace string - expectedDID cheqd.Did + expectedDID *types.DidDoc expectedMetadata types.ResolutionDidDocMetadata expectedResolutionType types.ContentType expectedError types.ErrorType @@ -132,21 +71,21 @@ func TestResolve(t *testing.T) { name: "successful resolution", ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), resolutionType: types.DIDJSONLD, - identifier: validIdentifier, - method: validMethod, - namespace: validNamespace, - expectedDID: validDIDDoc, - expectedMetadata: types.NewResolutionDidDocMetadata(validDid, validMetadata, []*resource.ResourceHeader{validResource.Header}), + identifier: utils.ValidIdentifier, + method: utils.ValidMethod, + namespace: utils.ValidNamespace, + expectedDID: types.NewDidDoc(validDIDDoc), + expectedMetadata: types.NewResolutionDidDocMetadata(utils.ValidDid, validMetadata, []*resource.ResourceHeader{validResource.Header}), expectedError: "", }, { name: "DID not found", ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}), resolutionType: types.DIDJSONLD, - identifier: validIdentifier, - method: validMethod, - namespace: validNamespace, - expectedDID: cheqd.Did{}, + identifier: utils.ValidIdentifier, + method: utils.ValidMethod, + namespace: utils.ValidNamespace, + expectedDID: nil, expectedMetadata: types.ResolutionDidDocMetadata{}, expectedError: types.NotFoundError, }, @@ -155,9 +94,9 @@ func TestResolve(t *testing.T) { ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}), resolutionType: types.DIDJSONLD, identifier: "oooooo0000OOOO_invalid_did", - method: validMethod, - namespace: validNamespace, - expectedDID: cheqd.Did{}, + method: utils.ValidMethod, + namespace: utils.ValidNamespace, + expectedDID: nil, expectedMetadata: types.ResolutionDidDocMetadata{}, expectedError: types.InvalidDIDError, }, @@ -165,10 +104,10 @@ func TestResolve(t *testing.T) { name: "invalid method", ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}), resolutionType: types.DIDJSONLD, - identifier: validIdentifier, + identifier: utils.ValidIdentifier, method: "not_supported_method", - namespace: validNamespace, - expectedDID: cheqd.Did{}, + namespace: utils.ValidNamespace, + expectedDID: nil, expectedMetadata: types.ResolutionDidDocMetadata{}, expectedError: types.MethodNotSupportedError, }, @@ -176,10 +115,10 @@ func TestResolve(t *testing.T) { name: "invalid namespace", ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}), resolutionType: types.DIDJSONLD, - identifier: validIdentifier, - method: validMethod, + identifier: utils.ValidIdentifier, + method: utils.ValidMethod, namespace: "invalid_namespace", - expectedDID: cheqd.Did{}, + expectedDID: nil, expectedMetadata: types.ResolutionDidDocMetadata{}, expectedError: types.InvalidDIDError, }, @@ -187,10 +126,10 @@ func TestResolve(t *testing.T) { name: "representation is not supported", ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), resolutionType: "text/html,application/xhtml+xml", - identifier: validIdentifier, - method: validMethod, - namespace: validNamespace, - expectedDID: cheqd.Did{}, + identifier: utils.ValidIdentifier, + method: utils.ValidMethod, + namespace: utils.ValidNamespace, + expectedDID: nil, expectedMetadata: types.ResolutionDidDocMetadata{}, expectedResolutionType: types.JSON, expectedError: types.RepresentationNotSupportedError, @@ -208,7 +147,7 @@ func TestResolve(t *testing.T) { } if (subtest.resolutionType == "" || subtest.resolutionType == types.DIDJSONLD) && subtest.expectedError == "" { subtest.expectedDID.Context = []string{types.DIDSchemaJSONLD} - } else { + } else if subtest.expectedDID != nil { subtest.expectedDID.Context = nil } expectedContentType := subtest.expectedResolutionType @@ -217,9 +156,6 @@ func TestResolve(t *testing.T) { } resolutionResult := requestService.Resolve(id, types.ResolutionOption{Accept: subtest.resolutionType}) - fmt.Println(subtest.name + ": resolutionResult:") - fmt.Println(resolutionResult.Did.VerificationMethod) - fmt.Println(subtest.expectedDID.VerificationMethod) require.EqualValues(t, subtest.expectedDID, resolutionResult.Did) require.EqualValues(t, subtest.expectedMetadata, resolutionResult.Metadata) require.EqualValues(t, expectedContentType, resolutionResult.ResolutionMetadata.ContentType) @@ -230,79 +166,74 @@ func TestResolve(t *testing.T) { } func TestDereferencing(t *testing.T) { - validDIDDoc := validDIDDoc() - validVerificationMethod := validVerificationMethod() - validService := validService() - validResource := validResource() - validChecksum := fmt.Sprintf("%x", validResource.Header.Checksum) - validMetadata := validMetadata() - validFragmentMetadata := types.NewResolutionDidDocMetadata(validDid, validMetadata, []*resource.ResourceHeader{}) + validDIDDoc := utils.ValidDIDDoc() + validVerificationMethod := utils.ValidVerificationMethod() + validService := utils.ValidService() + validResource := utils.ValidResource() + validResourceData := types.DereferencedResourceData(validResource.Data) + validMetadata := utils.ValidMetadata() + validFragmentMetadata := types.NewResolutionDidDocMetadata(utils.ValidDid, validMetadata, []*resource.ResourceHeader{}) subtests := []struct { name string ledgerService MockLedgerService dereferencingType types.ContentType didUrl string - expectedContentStream []byte + expectedContentStream types.ContentStreamI expectedContentType types.ContentType expectedMetadata types.ResolutionDidDocMetadata expectedError types.ErrorType }{ { - name: "successful resolution", - ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), - dereferencingType: types.DIDJSONLD, - didUrl: validDid, - expectedContentStream: []byte(fmt.Sprintf("{\"@context\":[\"%s\"],\"id\":\"%s\",\"verificationMethod\":[{\"id\":\"%s\",\"type\":\"%s\",\"controller\":\"%s\",\"publicKeyJwk\":%s}],\"service\":[{\"id\":\"%s\",\"type\":\"%s\",\"serviceEndpoint\":\"%s\"}]}", - types.DIDSchemaJSONLD, validDid, validVerificationMethod.Id, validVerificationMethod.Type, validVerificationMethod.Controller, validPubKeyJWK, validService.Id, validService.Type, validService.ServiceEndpoint)), - expectedMetadata: types.NewResolutionDidDocMetadata(validDid, validMetadata, []*resource.ResourceHeader{validResource.Header}), - expectedError: "", + name: "successful resolution", + ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), + dereferencingType: types.DIDJSON, + didUrl: utils.ValidDid, + expectedContentStream: types.NewDidDoc(validDIDDoc), + expectedMetadata: types.NewResolutionDidDocMetadata(utils.ValidDid, validMetadata, []*resource.ResourceHeader{validResource.Header}), + expectedError: "", }, { - name: "successful Secondary dereferencing (key)", - ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), - dereferencingType: types.DIDJSONLD, - didUrl: validVerificationMethod.Id, - expectedContentStream: []byte(fmt.Sprintf("{\"@context\":\"%s\",\"id\":\"%s\",\"type\":\"%s\",\"controller\":\"%s\",\"publicKeyJwk\":%s}", - types.DIDSchemaJSONLD, validVerificationMethod.Id, validVerificationMethod.Type, validVerificationMethod.Controller, validPubKeyJWK)), - expectedMetadata: validFragmentMetadata, - expectedError: "", + name: "successful Secondary dereferencing (key)", + ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), + dereferencingType: types.DIDJSON, + didUrl: validVerificationMethod.Id, + expectedContentStream: types.NewVerificationMethod(&validVerificationMethod), + expectedMetadata: validFragmentMetadata, + expectedError: "", }, { - name: "successful Secondary dereferencing (service)", - ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), - dereferencingType: types.DIDJSONLD, - didUrl: validService.Id, - expectedContentStream: []byte(fmt.Sprintf("{\"@context\":\"%s\",\"id\":\"%s\",\"type\":\"%s\",\"serviceEndpoint\":\"%s\"}", - types.DIDSchemaJSONLD, validService.Id, validService.Type, validService.ServiceEndpoint)), - expectedMetadata: validFragmentMetadata, - expectedError: "", + name: "successful Secondary dereferencing (service)", + ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), + dereferencingType: types.DIDJSON, + didUrl: validService.Id, + expectedContentStream: types.NewService(&validService), + expectedMetadata: validFragmentMetadata, + expectedError: "", }, { - name: "successful Primary dereferencing (resource header)", - ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), - dereferencingType: types.DIDJSONLD, - didUrl: validDid + types.RESOURCE_PATH + validResourceId + "/metadata", - expectedContentStream: []byte(fmt.Sprintf("{\"@context\":[\"%s\"],\"collectionId\":\"%s\",\"id\":\"%s\",\"name\":\"%s\",\"resourceType\":\"%s\",\"mediaType\":\"%s\",\"checksum\":\"%s\"}", - types.DIDSchemaJSONLD, validResource.Header.CollectionId, validResource.Header.Id, validResource.Header.Name, validResource.Header.ResourceType, validResource.Header.MediaType, validChecksum)), - expectedMetadata: types.ResolutionDidDocMetadata{}, - expectedError: "", + name: "successful Primary dereferencing (resource header)", + ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), + dereferencingType: types.DIDJSON, + didUrl: utils.ValidDid + types.RESOURCE_PATH + utils.ValidResourceId + "/metadata", + expectedContentStream: types.NewDereferencedResourceList(utils.ValidDid, []*resource.ResourceHeader{validResource.Header}), + expectedMetadata: types.ResolutionDidDocMetadata{}, + expectedError: "", }, { - name: "successful Primary dereferencing (resource list)", - ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), - dereferencingType: types.DIDJSONLD, - didUrl: validDid + types.RESOURCE_PATH + "all", - expectedContentStream: []byte(fmt.Sprintf("[{\"@context\":[\"%s\"],\"collectionId\":\"%s\",\"id\":\"%s\",\"name\":\"%s\",\"resourceType\":\"%s\",\"mediaType\":\"%s\",\"checksum\":\"%s\"}]", - types.DIDSchemaJSONLD, validResource.Header.CollectionId, validResource.Header.Id, validResource.Header.Name, validResource.Header.ResourceType, validResource.Header.MediaType, validChecksum)), - expectedMetadata: types.ResolutionDidDocMetadata{}, - expectedError: "", + name: "successful Primary dereferencing (resource list)", + ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), + dereferencingType: types.DIDJSON, + didUrl: utils.ValidDid + types.RESOURCE_PATH + "all", + expectedContentStream: types.NewDereferencedResourceList(utils.ValidDid, []*resource.ResourceHeader{validResource.Header}), + expectedMetadata: types.ResolutionDidDocMetadata{}, + expectedError: "", }, { name: "successful Primary dereferencing (resource data)", ledgerService: NewMockLedgerService(validDIDDoc, validMetadata, validResource), dereferencingType: types.DIDJSONLD, - didUrl: validDid + types.RESOURCE_PATH + validResourceId, - expectedContentStream: validResource.Data, + didUrl: utils.ValidDid + types.RESOURCE_PATH + utils.ValidResourceId, + expectedContentStream: &validResourceData, expectedContentType: types.ContentType(validResource.Header.MediaType), expectedMetadata: types.ResolutionDidDocMetadata{}, expectedError: "", @@ -310,7 +241,7 @@ func TestDereferencing(t *testing.T) { { name: "invalid URL", ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}), - didUrl: "unvalid_url", + didUrl: "unutils.Valid_url", dereferencingType: types.DIDJSONLD, expectedMetadata: types.ResolutionDidDocMetadata{}, expectedError: types.InvalidDIDUrlError, @@ -319,7 +250,7 @@ func TestDereferencing(t *testing.T) { name: "not supported path", ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}), dereferencingType: types.DIDJSONLD, - didUrl: validDid + "/unknown_path", + didUrl: utils.ValidDid + "/unknown_path", expectedMetadata: types.ResolutionDidDocMetadata{}, expectedError: types.RepresentationNotSupportedError, }, @@ -327,7 +258,7 @@ func TestDereferencing(t *testing.T) { name: "not supported query", ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}), dereferencingType: types.DIDJSONLD, - didUrl: validDid + "?unknown_query", + didUrl: utils.ValidDid + "?unknown_query", expectedMetadata: types.ResolutionDidDocMetadata{}, expectedError: types.RepresentationNotSupportedError, }, @@ -335,7 +266,7 @@ func TestDereferencing(t *testing.T) { name: "key not found", ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}), dereferencingType: types.DIDJSONLD, - didUrl: validDid + "#notFoundKey", + didUrl: utils.ValidDid + "#notFoundKey", expectedMetadata: types.ResolutionDidDocMetadata{}, expectedError: types.NotFoundError, }, @@ -343,7 +274,7 @@ func TestDereferencing(t *testing.T) { name: "resource not found", ledgerService: NewMockLedgerService(cheqd.Did{}, cheqd.Metadata{}, resource.Resource{}), dereferencingType: types.DIDJSONLD, - didUrl: validDid + types.RESOURCE_PATH + "00000000-0000-0000-0000-000000000000", + didUrl: utils.ValidDid + types.RESOURCE_PATH + "00000000-0000-0000-0000-000000000000", expectedMetadata: types.ResolutionDidDocMetadata{}, expectedError: types.NotFoundError, }, @@ -355,9 +286,9 @@ func TestDereferencing(t *testing.T) { var expectedDIDProperties types.DidProperties if subtest.expectedError != types.InvalidDIDUrlError { expectedDIDProperties = types.DidProperties{ - DidString: validDid, - MethodSpecificId: validIdentifier, - Method: validMethod, + DidString: utils.ValidDid, + MethodSpecificId: utils.ValidIdentifier, + Method: utils.ValidMethod, } } expectedContentType := subtest.expectedContentType @@ -367,16 +298,17 @@ func TestDereferencing(t *testing.T) { fmt.Println(" dereferencingResult " + subtest.didUrl) - dereferencingResult, statusCode := requestService.Dereference(subtest.didUrl, types.DereferencingOption{Accept: subtest.dereferencingType}) + dereferencingResult := requestService.Dereference(subtest.didUrl, types.DereferencingOption{Accept: subtest.dereferencingType}) fmt.Println(subtest.name + ": dereferencingResult:") fmt.Println(dereferencingResult) + require.EqualValues(t, subtest.expectedContentStream, dereferencingResult.ContentStream) require.EqualValues(t, subtest.expectedMetadata, dereferencingResult.Metadata) require.EqualValues(t, expectedContentType, dereferencingResult.DereferencingMetadata.ContentType) require.EqualValues(t, subtest.expectedError, dereferencingResult.DereferencingMetadata.ResolutionError) require.EqualValues(t, expectedDIDProperties, dereferencingResult.DereferencingMetadata.DidProperties) - require.EqualValues(t, subtest.expectedError.GetStatusCode(), statusCode) + require.EqualValues(t, subtest.expectedError.GetStatusCode(), dereferencingResult.DereferencingMetadata.ResolutionError.GetStatusCode()) }) } } diff --git a/services/resource_dereference_service.go b/services/resource_dereference_service.go index a594b159..9108bbdc 100644 --- a/services/resource_dereference_service.go +++ b/services/resource_dereference_service.go @@ -3,10 +3,11 @@ 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" + resourceTypes "github.com/cheqd/cheqd-node/x/resource/types" "github.com/cheqd/did-resolver/types" "github.com/cheqd/did-resolver/utils" + "github.com/rs/zerolog/log" ) type ResourceDereferenceService struct { @@ -22,9 +23,14 @@ func NewResourceDereferenceService(ledgerService LedgerServiceI, didDocService D } func (rds ResourceDereferenceService) DereferenceResource(path string, did string, dereferenceOptions types.DereferencingOption) types.DidDereferencing { - var cotentStream []byte + var cotentStream types.ContentStreamI var dereferenceMetadata types.DereferencingMetadata + if !dereferenceOptions.Accept.IsSupported() && !utils.IsResourceDataPath(path) { + dereferencingMetadata := types.NewDereferencingMetadata(did, types.JSON, types.RepresentationNotSupportedError) + return types.DidDereferencing{DereferencingMetadata: dereferencingMetadata} + } + if utils.IsResourceHeaderPath(path) { cotentStream, dereferenceMetadata = rds.dereferenceHeader(path, did, dereferenceOptions) } else if utils.IsCollectionResourcesPath(path) { @@ -38,50 +44,31 @@ func (rds ResourceDereferenceService) DereferenceResource(path string, did strin return types.DidDereferencing{ContentStream: cotentStream, DereferencingMetadata: dereferenceMetadata} } -func (rds ResourceDereferenceService) dereferenceHeader(path string, did string, dereferenceOptions types.DereferencingOption) ([]byte, types.DereferencingMetadata) { +func (rds ResourceDereferenceService) dereferenceHeader(path string, did string, dereferenceOptions types.DereferencingOption) (*types.DereferencedResourceList, types.DereferencingMetadata) { dereferenceMetadata := types.NewDereferencingMetadata(did, dereferenceOptions.Accept, "") resourceId := utils.GetResourceId(path) resource, dereferencingError := rds.ledgerService.QueryResource(did, resourceId) - + log.Warn().Msgf("dereferencingError: %s", dereferencingError) if dereferencingError != "" { dereferenceMetadata.ResolutionError = dereferencingError - return []byte(nil), dereferenceMetadata + return &types.DereferencedResourceList{}, dereferenceMetadata } - var err error - cotentStream, err := rds.didDocService.MarshallContentStream(resource.Header, dereferenceOptions.Accept) - if err != nil { - dereferenceMetadata.ResolutionError = types.InternalError - } - return []byte(cotentStream), dereferenceMetadata + return types.NewDereferencedResourceList(did, []*resourceTypes.ResourceHeader{resource.Header}), dereferenceMetadata } -func (rds ResourceDereferenceService) dereferenceCollectionResources(did string, dereferenceOptions types.DereferencingOption) ([]byte, types.DereferencingMetadata) { +func (rds ResourceDereferenceService) dereferenceCollectionResources(did string, dereferenceOptions types.DereferencingOption) (*types.DereferencedResourceList, types.DereferencingMetadata) { dereferenceMetadata := types.NewDereferencingMetadata(did, dereferenceOptions.Accept, "") resources, dereferencingError := rds.ledgerService.QueryCollectionResources(did) if dereferencingError != "" { dereferenceMetadata.ResolutionError = dereferencingError - return []byte(nil), dereferenceMetadata - } - jsonResources := []json.RawMessage{} - for _, r := range resources { - jsonR, err := rds.didDocService.MarshallContentStream(r, dereferenceOptions.Accept) - if err != nil { - dereferenceMetadata.ResolutionError = types.InternalError - return []byte(nil), dereferenceMetadata - } - jsonResources = append(jsonResources, json.RawMessage(jsonR)) - } - cotentStream, err := json.Marshal(jsonResources) - if err != nil { - dereferenceMetadata.ResolutionError = types.InternalError - return []byte(nil), dereferenceMetadata + return &types.DereferencedResourceList{}, dereferenceMetadata } - return cotentStream, dereferenceMetadata + return types.NewDereferencedResourceList(did, resources), dereferenceMetadata } -func (rds ResourceDereferenceService) dereferenceResourceData(path string, did string, dereferenceOptions types.DereferencingOption) ([]byte, types.DereferencingMetadata) { +func (rds ResourceDereferenceService) dereferenceResourceData(path string, did string, dereferenceOptions types.DereferencingOption) (*types.DereferencedResourceData, types.DereferencingMetadata) { dereferenceMetadata := types.NewDereferencingMetadata(did, dereferenceOptions.Accept, "") resourceId := utils.GetResourceId(path) @@ -89,8 +76,9 @@ func (rds ResourceDereferenceService) dereferenceResourceData(path string, did s if dereferencingError != "" { dereferenceMetadata.ResolutionError = dereferencingError - return []byte(nil), dereferenceMetadata + return &types.DereferencedResourceData{}, dereferenceMetadata } + result := types.DereferencedResourceData(resource.Data) dereferenceMetadata.ContentType = types.ContentType(resource.Header.MediaType) - return resource.Data, dereferenceMetadata + return &result, dereferenceMetadata } diff --git a/tests/pytest/test_resolution.py b/tests/pytest/test_resolution.py index 4cec403a..df9bb01e 100644 --- a/tests/pytest/test_resolution.py +++ b/tests/pytest/test_resolution.py @@ -13,31 +13,31 @@ "did_url, expected_output", [ (TESTNET_DID, - fr"didResolutionMetadata(.*?)didDocument(.*?)\"id\":\"{TESTNET_DID}\"(.*?)didDocumentMetadata(.*?){TESTNET_RESOURCE_NAME}"), - (MAINNET_DID, fr"didResolutionMetadata(.*?)didDocument(.*?)\"id\":\"{MAINNET_DID}\"(.*?)didDocumentMetadata"), - (FAKE_TESTNET_DID, r"\"didResolutionMetadata(.*?)\"error\":\"notFound\"(.*?)" - r"didDocument\":null,\"didDocumentMetadata\":\[\]"), - (FAKE_MAINNET_DID, r"\"didResolutionMetadata(.*?)\"error\":\"notFound\"(.*?)" - r"didDocument\":null,\"didDocumentMetadata\":\[\]"), - ("did:wrong_method:MTMxDQKMTMxDQKMT", r"\"didResolutionMetadata(.*?)\"error\":\"methodNotSupported\"(.*?)" - r"didDocument\":null,\"didDocumentMetadata\":\[\]"), - - (TESTNET_FRAGMENT, fr"\"contentStream\":(.*?)\"id\":\"{TESTNET_FRAGMENT}\"(.*?)contentMetadata" - r"(.*?)dereferencingMetadata\""), - (MAINNET_FRAGMENT, fr"\"contentStream\":(.*?)\"id\":\"{MAINNET_FRAGMENT}\"(.*?)contentMetadata" - r"(.*?)dereferencingMetadata\""), - (FAKE_TESTNET_FRAGMENT, r"\"contentStream\":null,\"contentMetadata\":\[\]," - r"\"dereferencingMetadata(.*?)\"error\":\"notFound\""), - (FAKE_MAINNET_FRAGMENT, r"\"contentStream\":null,\"contentMetadata\":\[\]," - r"\"dereferencingMetadata(.*?)\"error\":\"notFound\""), - - (TESTNET_RESOURCE_METADATA, fr"\"contentStream\":(.*?)collectionId(.*?),\"contentMetadata\":(.*?)," - r"\"dereferencingMetadata(.*?)"), - (TESTNET_RESOURCE_LIST, fr"\"contentStream\":\[(.*?)collectionId(.*?),\"contentMetadata\":(.*?)," - r"\"dereferencingMetadata(.*?)"), + fr"didResolutionMetadata(.*?)didDocument(.*?)\"id\": \"{TESTNET_DID}\"(.*?)didDocumentMetadata(.*?){TESTNET_RESOURCE_NAME}"), + (MAINNET_DID, fr"didResolutionMetadata(.*?)didDocument(.*?)\"id\": \"{MAINNET_DID}\"(.*?)didDocumentMetadata"), + (FAKE_TESTNET_DID, r"\"didResolutionMetadata(.*?)\"error\": \"notFound\"(.*?)" + r"didDocument\": null,(.*?)\"didDocumentMetadata\": \{\}"), + (FAKE_MAINNET_DID, r"\"didResolutionMetadata(.*?)\"error\": \"notFound\"(.*?)" + r"didDocument\": null,(.*?)\"didDocumentMetadata\": \{\}"), + ("did:wrong_method:MTMxDQKMTMxDQKMT", r"\"didResolutionMetadata(.*?)\"error\": \"methodNotSupported\"(.*?)" + r"didDocument\": null,(.*?)\"didDocumentMetadata\": \{\}"), + + (TESTNET_FRAGMENT, r"(.*?)dereferencingMetadata\"(.*?)" + fr"\"contentStream\":(.*?)\"id\": \"{TESTNET_FRAGMENT}\"(.*?)contentMetadata"), + (MAINNET_FRAGMENT, r"(.*?)dereferencingMetadata\"(.*?)" + fr"\"contentStream\":(.*?)\"id\": \"{MAINNET_FRAGMENT}\"(.*?)contentMetadata"), + (FAKE_TESTNET_FRAGMENT, r"\"dereferencingMetadata(.*?)\"error\": \"notFound\"(.*?)" + r"\"contentStream\": null,(.*?)\"contentMetadata\": \{\}"), + (FAKE_MAINNET_FRAGMENT, r"\"dereferencingMetadata(.*?)\"error\": \"notFound\"(.*?)" + r"\"contentStream\": null,(.*?)\"contentMetadata\": \{\}"), + + (TESTNET_RESOURCE_METADATA, r"\"dereferencingMetadata(.*?)\"contentStream\":(.*?)linkedResourceMetadata(.*?)" + "resourceCollectionId(.*?)\"contentMetadata\":(.*?)"), + (TESTNET_RESOURCE_LIST, r"\"dereferencingMetadata(.*?)\"contentStream\":(.*?)linkedResourceMetadata(.*?)" + "resourceCollectionId(.*?)\"contentMetadata\":(.*?)"), (TESTNET_RESOURCE, RESOURCE_DATA), - (FAKE_TESTNET_RESOURCE, r"\"contentStream\":null,\"contentMetadata\":\[\]," - r"\"dereferencingMetadata(.*?)\"error\":\"notFound\""), + (FAKE_TESTNET_RESOURCE, r"\"dereferencingMetadata(.*?)\"error\": \"notFound\"(.*?)" + r"\"contentStream\": null,(.*?)\"contentMetadata\": \{\}"), ] ) def test_resolution(did_url, expected_output): @@ -48,20 +48,19 @@ def test_resolution(did_url, expected_output): "accept, expected_header, has_context, expected_status_code, expected_body", [ (LDJSON, LDJSON, True, 200, - r"(.*?)didResolutionMetadata(.*?)application/ld\+json" - r"(.*?)didDocument(.*?)@context(.*?)didDocumentMetadata"), + r"(.*?)didResolutionMetadata"), (DIDLDJSON, DIDLDJSON, True, 200, "(.*?)didResolutionMetadata(.*?)application/did\+ld\+json" - "(.*?)didDocument(.*?)@context(.*?)didDocumentMetadata"), + "(.*?)didDocument(.*?)@context(.*?)didDocumentMetadata(.*?)"), ("*/*", DIDLDJSON, True, 200, "(.*?)didResolutionMetadata(.*?)application/did\+ld\+json" - "(.*?)didDocument(.*?)@context(.*?)didDocumentMetadata"), + "(.*?)didDocument(.*?)@context(.*?)didDocumentMetadata(.*?)"), (DIDJSON, DIDJSON, False, 200, r"(.*?)didResolutionMetadata(.*?)application/did\+json" - r"(.*?)didDocument(.*?)(?!`@context`)(.*?)didDocumentMetadata"), + r"(.*?)didDocument(.*?)(?!`@context`)(.*?)didDocumentMetadata(.*?)"), (HTML + ",application/xhtml+xml", JSON, False, 406, - "(.*?)didResolutionMetadata(.*?)\"error\":\"representationNotSupported\"" - "(.*?)\"didDocument\":null,\"didDocumentMetadata\":\[\]"), + "(.*?)didResolutionMetadata(.*?)\"error\": \"representationNotSupported\"" + "(.*?)\"didDocument\": null,(.*?)\"didDocumentMetadata\": \{\}"), ] ) def test_resolution_content_type(accept, expected_header, expected_body, has_context, expected_status_code): @@ -69,38 +68,38 @@ def test_resolution_content_type(accept, expected_header, expected_body, has_con header = {"Accept": accept} if accept else {} r = requests.get(url, headers=header) - + print(r.text.replace("\n", "\\n")) assert r.headers["Content-Type"] == expected_header assert r.status_code == expected_status_code - assert re.match(expected_body, r.text) + assert re.match(expected_body, r.text.replace("\n", "\\n").replace("\n", "\\n")) if has_context: - assert re.findall(r"context", r.text) + assert re.findall(r"context", r.text.replace("\n", "\\n").replace("\n", "\\n")) else: - assert not re.findall(r"context", r.text) + assert not re.findall(r"context", r.text.replace("\n", "\\n").replace("\n", "\\n")) -dereferencing_content_type_test_set = [ +secondary_dereferencing_content_type_test_set = [ (LDJSON, LDJSON, True, 200, - r"(.*?)contentStream(.*?)@context(.*?)contentMetadata" - r"(.*?)dereferencingMetadata(.*?)application/ld\+json"), + r"(.*?)dereferencingMetadata(.*?)application/ld\+json" + r"(.*?)contentStream(.*?)@context(.*?)contentMetadata"), (DIDLDJSON, DIDLDJSON, True, 200, - "(.*?)contentStream(.*?)@context(.*?)contentMetadata" - "(.*?)dereferencingMetadata(.*?)application/did\+ld\+json"), + "(.*?)dereferencingMetadata(.*?)application/did\+ld\+json" + "(.*?)contentStream(.*?)@context(.*?)contentMetadata"), ("*/*", DIDLDJSON, True, 200, - "(.*?)contentStream(.*?)@context(.*?)contentMetadata" - "(.*?)dereferencingMetadata(.*?)application/did\+ld\+json"), + "(.*?)dereferencingMetadata(.*?)application/did\+ld\+json" + "(.*?)contentStream(.*?)@context(.*?)contentMetadata"), (DIDJSON, DIDJSON, False, 200, - r"(.*?)contentStream(.*?)contentMetadata" - r"(.*?)dereferencingMetadata(.*?)application/did\+json"), - (HTML + ",application/xhtml+xml", JSON, False, 406, - "(.*?)\"contentStream\":null,\"contentMetadata\":\[\]," - "\"dereferencingMetadata(.*?)\"error\":\"representationNotSupported\""), + r"(.*?)dereferencingMetadata(.*?)application/did\+json" + r"(.*?)contentStream(.*?)contentMetadata"), + (HTML, JSON, False, 406, + "(.*?)dereferencingMetadata(.*?)\"error\": \"representationNotSupported\"" + "(.*?)\"contentStream\": null,(.*?)\"contentMetadata\": \{\}"), ] @pytest.mark.parametrize( "accept, expected_header, has_context, expected_status_code, expected_body", - dereferencing_content_type_test_set + secondary_dereferencing_content_type_test_set ) def test_dereferencing_content_type_fragment(accept, expected_header, expected_body, has_context, expected_status_code): url = RESOLVER_URL + PATH + TESTNET_FRAGMENT.replace("#", "%23") @@ -110,16 +109,35 @@ def test_dereferencing_content_type_fragment(accept, expected_header, expected_b assert r.headers["Content-Type"] == expected_header assert r.status_code == expected_status_code - assert re.match(expected_body, r.text) + assert re.match(expected_body, r.text.replace("\n", "\\n")) if has_context: - assert re.findall(r"context", r.text) + assert re.findall(r"context", r.text.replace("\n", "\\n")) else: - assert not re.findall(r"context", r.text) + assert not re.findall(r"context", r.text.replace("\n", "\\n")) + + +primary_dereferencing_content_type_test_set = [ + (LDJSON, LDJSON, True, 200, + r"(.*?)dereferencingMetadata(.*?)application/ld\+json" + r"(.*?)contentStream(.*?)contentMetadata"), + (DIDLDJSON, DIDLDJSON, True, 200, + "(.*?)dereferencingMetadata(.*?)application/did\+ld\+json" + "(.*?)contentStream(.*?)contentMetadata"), + ("*/*", DIDLDJSON, True, 200, + "(.*?)dereferencingMetadata(.*?)application/did\+ld\+json" + "(.*?)contentStream(.*?)contentMetadata"), + (DIDJSON, DIDJSON, False, 200, + r"(.*?)dereferencingMetadata(.*?)application/did\+json" + r"(.*?)contentStream(.*?)contentMetadata"), + (HTML, JSON, False, 406, + "(.*?)dereferencingMetadata(.*?)\"error\": \"representationNotSupported\"" + "(.*?)\"contentStream\": null,(.*?)\"contentMetadata\": \{\}"), +] @pytest.mark.parametrize( "accept, expected_header, has_context, expected_status_code, expected_body", - dereferencing_content_type_test_set + primary_dereferencing_content_type_test_set ) def test_dereferencing_content_type_resource_metadata(accept, expected_header, expected_body, has_context, expected_status_code): @@ -127,13 +145,10 @@ def test_dereferencing_content_type_resource_metadata(accept, expected_header, e header = {"Accept": accept} if accept else {} r = requests.get(url, headers=header) - + print(r.text) assert r.headers["Content-Type"] == expected_header - assert re.match(expected_body, r.text) - if has_context: - assert re.findall(r"context", r.text) - else: - assert not re.findall(r"context", r.text) + assert re.match(expected_body, r.text.replace("\n", "\\n")) + assert not re.findall(r"context", r.text.replace("\n", "\\n")) @pytest.mark.parametrize( @@ -146,17 +161,19 @@ def test_dereferencing_content_type_resource(accept, expected_header, expected_s r = requests.get(url, headers=header) assert r.headers["Content-Type"] == expected_header + @pytest.mark.parametrize( "accept, expected_header, expected_status_code, expected_body", [(LDJSON, LDJSON, 301, - r"(.*?)\"contentStream\":\[(.*?)collectionId(.*?),\"contentMetadata\":(.*?),\"dereferencingMetadata(.*?)"),] + r"(.*?)\"dereferencingMetadata(.*?)\"contentStream\":(.*?)" + r"resourceCollectionId(.*?)\"contentMetadata\":(.*?)"), ] ) def test_dereferencing_content_type_resource_redirect(accept, expected_header, expected_status_code, expected_body): url = RESOLVER_URL + PATH + TESTNET_RESOURCE_LIST_REDIRECT header = {"Accept": accept} if accept else {} r = requests.get(url, headers=header) assert r.headers["Content-Type"] == expected_header - assert re.match(expected_body, r.text) + assert re.match(expected_body, r.text.replace("\n", "\\n")) @pytest.mark.parametrize( diff --git a/types/config.go b/types/config.go index ee27e90b..7ab9a8c6 100644 --- a/types/config.go +++ b/types/config.go @@ -45,7 +45,7 @@ func (c *Config) MustMarshalYaml() string { } func (c *Config) MarshalJson() (string, error) { - bytes, err := json.Marshal(c) + bytes, err := json.MarshalIndent(c, "", " ") return string(bytes), err } diff --git a/types/dereferecing_metadata.go b/types/dereferecing_metadata.go index bb57d5b8..4ad7f1e6 100644 --- a/types/dereferecing_metadata.go +++ b/types/dereferecing_metadata.go @@ -5,11 +5,26 @@ type DereferencingOption ResolutionOption type DereferencingMetadata ResolutionMetadata type DidDereferencing struct { - ContentStream []byte `json:"contentStream,omitempty"` - Metadata ResolutionDidDocMetadata `json:"contentMetadata,omitempty"` - DereferencingMetadata DereferencingMetadata `json:"dereferencingMetadata,omitempty"` + DereferencingMetadata DereferencingMetadata `json:"dereferencingMetadata"` + ContentStream ContentStreamI `json:"contentStream"` + Metadata ResolutionDidDocMetadata `json:"contentMetadata"` } func NewDereferencingMetadata(did string, contentType ContentType, resolutionError ErrorType) DereferencingMetadata { return DereferencingMetadata(NewResolutionMetadata(did, contentType, resolutionError)) } + +func (d DidDereferencing) GetStatus() int { + return d.DereferencingMetadata.ResolutionError.GetStatusCode() +} + +func (d DidDereferencing) GetContentType() string { + return string(d.DereferencingMetadata.ContentType) +} + +func (d DidDereferencing) GetBytes() []byte { + if d.ContentStream == nil { + return []byte{} + } + return d.ContentStream.GetBytes() +} diff --git a/types/dereferencing_content_stream.go b/types/dereferencing_content_stream.go index 3fcc1b28..38c8dc80 100644 --- a/types/dereferencing_content_stream.go +++ b/types/dereferencing_content_stream.go @@ -1,14 +1,63 @@ package types +import resource "github.com/cheqd/cheqd-node/x/resource/types" + type DereferencedResource struct { - Context []string `json:"@context,omitempty"` - CollectionId string `json:"collectionId,omitempty"` - Id string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - ResourceType string `json:"resourceType,omitempty"` - MediaType string `json:"mediaType,omitempty"` - Created string `json:"created,omitempty"` - Checksum string `json:"checksum,omitempty"` - PreviousVersionId string `json:"previousVersionId,omitempty"` - NextVersionId string `json:"nextVersionId,omitempty"` + ResourceURI string `json:"resourceURI"` + CollectionId string `json:"resourceCollectionId"` + ResourceId string `json:"resourceId"` + Name string `json:"resourceName"` + ResourceType string `json:"resourceType"` + MediaType string `json:"mediaType"` + Created string `json:"created"` + Checksum string `json:"checksum"` + PreviousVersionId *string `json:"previousVersionId"` + NextVersionId *string `json:"nextVersionId"` +} + +func NewDereferencedResource(did string, resource *resource.ResourceHeader) *DereferencedResource { + var previousVersionId, nextVersionId *string + if resource.PreviousVersionId != "" { + previousVersionId = &resource.PreviousVersionId + } + if resource.NextVersionId != "" { + nextVersionId = &resource.NextVersionId + } + return &DereferencedResource{ + ResourceURI: did + RESOURCE_PATH + resource.Id, + CollectionId: resource.CollectionId, + ResourceId: resource.Id, + Name: resource.Name, + ResourceType: resource.ResourceType, + MediaType: resource.MediaType, + Created: resource.Created, + Checksum: FixResourceChecksum(resource.Checksum), + PreviousVersionId: previousVersionId, + NextVersionId: nextVersionId, + } } + +type DereferencedResourceList struct { + Resources []DereferencedResource `json:"linkedResourceMetadata,omitempty"` +} + +func NewDereferencedResourceList(did string, protoResources []*resource.ResourceHeader) *DereferencedResourceList { + resourceList := []DereferencedResource{} + for _, r := range protoResources { + resourceList = append(resourceList, *NewDereferencedResource(did, r)) + } + + return &DereferencedResourceList{ + Resources: resourceList, + } +} + +func (e *DereferencedResourceList) AddContext(newProtocol string) {} +func (e *DereferencedResourceList) RemoveContext() {} +func (e *DereferencedResourceList) GetBytes() []byte { return []byte{} } + +type DereferencedResourceData []byte + +func (e *DereferencedResourceData) AddContext(newProtocol string) {} +func (e *DereferencedResourceData) RemoveContext() {} +func (e *DereferencedResourceData) GetBytes() []byte { return []byte(*e) } diff --git a/types/did_doc.go b/types/did_doc.go new file mode 100644 index 00000000..1232e2dd --- /dev/null +++ b/types/did_doc.go @@ -0,0 +1,92 @@ +package types + +import ( + cheqd "github.com/cheqd/cheqd-node/x/cheqd/types" +) + +type DidDoc struct { + Context []string `json:"@context,omitempty"` + Id string `json:"id,omitempty"` + Controller []string `json:"controller,omitempty"` + VerificationMethod []VerificationMethod `json:"verificationMethod,omitempty"` + Authentication []string `json:"authentication,omitempty"` + AssertionMethod []string `json:"assertionMethod,omitempty"` + CapabilityInvocation []string `json:"capabilityInvocation,omitempty"` + CapabilityDelegation []string `json:"capability_delegation,omitempty"` + KeyAgreement []string `json:"keyAgreement,omitempty"` + Service []Service `json:"service,omitempty"` + AlsoKnownAs []string `json:"alsoKnownAs,omitempty"` +} + +type VerificationMethod struct { + Context []string `json:"@context,omitempty"` + Id string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + Controller string `json:"controller,omitempty"` + PublicKeyJwk map[string]string `json:"publicKeyJwk,omitempty"` + PublicKeyMultibase string `json:"publicKeyMultibase,omitempty"` +} + +type Service struct { + Context []string `json:"@context,omitempty"` + Id string `json:"id,omitempty"` + Type string `json:"type,omitempty"` + ServiceEndpoint string `json:"serviceEndpoint,omitempty"` +} + +func NewDidDoc(protoDidDoc cheqd.Did) *DidDoc { + verificationMethods := []VerificationMethod{} + for _, vm := range protoDidDoc.VerificationMethod { + verificationMethods = append(verificationMethods, *NewVerificationMethod(vm)) + } + + services := []Service{} + for _, s := range protoDidDoc.Service { + services = append(services, *NewService(s)) + } + + return &DidDoc{ + Id: protoDidDoc.Id, + Controller: protoDidDoc.Controller, + VerificationMethod: verificationMethods, + Authentication: protoDidDoc.Authentication, + AssertionMethod: protoDidDoc.AssertionMethod, + CapabilityInvocation: protoDidDoc.CapabilityInvocation, + CapabilityDelegation: protoDidDoc.CapabilityDelegation, + KeyAgreement: protoDidDoc.KeyAgreement, + Service: services, + AlsoKnownAs: protoDidDoc.AlsoKnownAs, + } +} + +func NewVerificationMethod(protoVerificationMethod *cheqd.VerificationMethod) *VerificationMethod { + return &VerificationMethod{ + Id: protoVerificationMethod.Id, + Type: protoVerificationMethod.Type, + Controller: protoVerificationMethod.Controller, + PublicKeyJwk: cheqd.PubKeyJWKToMap(protoVerificationMethod.PublicKeyJwk), + PublicKeyMultibase: protoVerificationMethod.PublicKeyMultibase, + } +} + +func NewService(protoService *cheqd.Service) *Service { + return &Service{ + Id: protoService.Id, + Type: protoService.Type, + ServiceEndpoint: protoService.ServiceEndpoint, + } +} + +func (e *DidDoc) AddContext(newProtocol string) { e.Context = AddElemToSet(e.Context, newProtocol) } +func (e *DidDoc) RemoveContext() { e.Context = nil } +func (e *DidDoc) GetBytes() []byte { return []byte{} } + +func (e *Service) AddContext(newProtocol string) { e.Context = AddElemToSet(e.Context, newProtocol) } +func (e *Service) RemoveContext() { e.Context = nil } +func (e *Service) GetBytes() []byte { return []byte{} } + +func (e *VerificationMethod) AddContext(newProtocol string) { + e.Context = AddElemToSet(e.Context, newProtocol) +} +func (e *VerificationMethod) RemoveContext() { e.Context = nil } +func (e *VerificationMethod) GetBytes() []byte { return []byte{} } diff --git a/types/did_doc_metadata.go b/types/did_doc_metadata.go index 35ded6a0..d09bf39b 100644 --- a/types/did_doc_metadata.go +++ b/types/did_doc_metadata.go @@ -1,55 +1,42 @@ package types import ( - "fmt" - cheqd "github.com/cheqd/cheqd-node/x/cheqd/types" resource "github.com/cheqd/cheqd-node/x/resource/types" ) type ResolutionDidDocMetadata struct { - Created string `json:"created,omitempty"` - Updated string `json:"updated,omitempty"` - Deactivated bool `json:"deactivated,omitempty"` - VersionId string `json:"versionId,omitempty"` - Resources []ResourcePreview `json:"resources,omitempty"` + Created string `json:"created,omitempty"` + Updated string `json:"updated,omitempty"` + Deactivated bool `json:"deactivated,omitempty"` + VersionId string `json:"versionId,omitempty"` + Resources []DereferencedResource `json:"linkedResourceMetadata,omitempty"` } type ResourcePreview struct { - ResourceURI string `json:"resourceURI,omitempty"` - Name string `json:"name,omitempty"` - ResourceType string `json:"resourceType,omitempty"` - MediaType string `json:"mediaType,omitempty"` - Created string `json:"created,omitempty"` - Checksum string `json:"checksum,omitempty"` - PreviousVersionId string `json:"previousVersionId,omitempty"` - NextVersionId string `json:"nextVersionId,omitempty"` + ResourceURI string `json:"resourceURI"` + CollectionId string `json:"resourceCollectionId"` + ResourceId string `json:"resourceId"` + Name string `json:"resourceName"` + ResourceType string `json:"resourceType"` + MediaType string `json:"mediaType"` + Created string `json:"created"` + Checksum string `json:"checksum"` + PreviousVersionId string `json:"previousVersionId"` + NextVersionId string `json:"nextVersionId"` } func NewResolutionDidDocMetadata(did string, metadata cheqd.Metadata, resources []*resource.ResourceHeader) ResolutionDidDocMetadata { newMetadata := ResolutionDidDocMetadata{ - metadata.Created, - metadata.Updated, - metadata.Deactivated, - metadata.VersionId, - []ResourcePreview(nil), + Created: metadata.Created, + Updated: metadata.Updated, + Deactivated: metadata.Deactivated, + VersionId: metadata.VersionId, } - if metadata.Resources == nil { + if metadata.Resources == nil || len(resources) == 0 { return newMetadata } - for _, r := range resources { - resourcePreview := ResourcePreview{ - did + RESOURCE_PATH + r.Id, - r.Name, - r.ResourceType, - r.MediaType, - r.Created, - fmt.Sprintf("%x", r.Checksum), - r.PreviousVersionId, - r.NextVersionId, - } - newMetadata.Resources = append(newMetadata.Resources, resourcePreview) - } + newMetadata.Resources = NewDereferencedResourceList(did, resources).Resources return newMetadata } diff --git a/types/did_doc_metadata_test.go b/types/did_doc_metadata_test.go index bfdb6bba..84874f5d 100644 --- a/types/did_doc_metadata_test.go +++ b/types/did_doc_metadata_test.go @@ -1,7 +1,7 @@ package types import ( - "fmt" + "crypto/sha256" "testing" cheqd "github.com/cheqd/cheqd-node/x/cheqd/types" @@ -13,24 +13,29 @@ func TestNewResolutionDidDocMetadata(t *testing.T) { validIdentifier := "N22KY2Dyvmuu2Pyy" validDid := "did:cheqd:mainnet:" + validIdentifier validResourceId := "18e9d838-0bea-435b-964b-c6529ede6d2b" + resourceData := []byte("test_checksum") + h := sha256.New() + h.Write(resourceData) resourceHeader := resource.ResourceHeader{ CollectionId: validIdentifier, Id: validResourceId, Name: "Existing Resource Name", ResourceType: "CL-Schema", MediaType: "application/json", - Checksum: []byte("test_checksum"), + Checksum: h.Sum(nil), } - validMetadataResource := ResourcePreview{ + validMetadataResource := DereferencedResource{ ResourceURI: validDid + RESOURCE_PATH + resourceHeader.Id, + CollectionId: resourceHeader.CollectionId, + ResourceId: resourceHeader.Id, Name: resourceHeader.Name, ResourceType: resourceHeader.ResourceType, MediaType: resourceHeader.MediaType, Created: resourceHeader.Created, - Checksum: fmt.Sprintf("%x", resourceHeader.Checksum), - PreviousVersionId: resourceHeader.PreviousVersionId, - NextVersionId: resourceHeader.NextVersionId, + Checksum: FixResourceChecksum(resourceHeader.Checksum), + PreviousVersionId: nil, + NextVersionId: nil, } subtests := []struct { @@ -50,7 +55,7 @@ func TestNewResolutionDidDocMetadata(t *testing.T) { expectedResult: ResolutionDidDocMetadata{ VersionId: "test_version_id", Deactivated: false, - Resources: []ResourcePreview{validMetadataResource}, + Resources: []DereferencedResource{validMetadataResource}, }, }, { @@ -66,13 +71,12 @@ func TestNewResolutionDidDocMetadata(t *testing.T) { }, }, { - name: "matadata with resources", + name: "matadata without resources", metadata: cheqd.Metadata{ VersionId: "test_version_id", Deactivated: false, Resources: []string{validResourceId}, }, - resources: []*resource.ResourceHeader{}, expectedResult: ResolutionDidDocMetadata{ VersionId: "test_version_id", Deactivated: false, @@ -85,7 +89,6 @@ func TestNewResolutionDidDocMetadata(t *testing.T) { result := NewResolutionDidDocMetadata(validDid, subtest.metadata, subtest.resources) require.EqualValues(t, subtest.expectedResult, result) - // require.EqualValues(t, subtest.expectedError, err) }) } } diff --git a/types/helper.go b/types/helper.go new file mode 100644 index 00000000..9830aece --- /dev/null +++ b/types/helper.go @@ -0,0 +1,28 @@ +package types + +import ( + "crypto/sha256" + "fmt" +) + +func FixResourceChecksum(inputChecksum []byte) (hash string) { + if len(fmt.Sprintf("%x", inputChecksum)) == 64 { + return fmt.Sprintf("%x", inputChecksum) + } + h := sha256.New() + data := inputChecksum[:len(inputChecksum)-len(h.Sum(nil))] + h.Write(data) + return fmt.Sprintf("%x", h.Sum(nil)) +} + +func AddElemToSet(set []string, newElement string) []string { + if set == nil { + set = []string{} + } + for _, c := range set { + if c == newElement { + return set + } + } + return append(set, newElement) +} diff --git a/types/interfaces.go b/types/interfaces.go new file mode 100644 index 00000000..24e91016 --- /dev/null +++ b/types/interfaces.go @@ -0,0 +1,13 @@ +package types + +type ContentStreamI interface { + AddContext(newProtocol string) + RemoveContext() + GetBytes() []byte +} + +type ResolutionResultI interface { + GetStatus() int + GetContentType() string + GetBytes() []byte +} diff --git a/types/resolution_metadata.go b/types/resolution_metadata.go index edbbd7db..dfaa87cb 100644 --- a/types/resolution_metadata.go +++ b/types/resolution_metadata.go @@ -3,7 +3,6 @@ package types import ( "time" - cheqd "github.com/cheqd/cheqd-node/x/cheqd/types" cheqdUtils "github.com/cheqd/cheqd-node/x/cheqd/utils" ) @@ -25,9 +24,9 @@ type DidProperties struct { } type DidResolution struct { - Did cheqd.Did `json:"didDocument,omitempty"` - Metadata ResolutionDidDocMetadata `json:"didDocumentMetadata,omitempty"` - ResolutionMetadata ResolutionMetadata `json:"didResolutionMetadata,omitempty"` + ResolutionMetadata ResolutionMetadata `json:"didResolutionMetadata"` + Did *DidDoc `json:"didDocument"` + Metadata ResolutionDidDocMetadata `json:"didDocumentMetadata"` } func NewResolutionMetadata(didUrl string, contentType ContentType, resolutionError ErrorType) ResolutionMetadata { @@ -48,3 +47,15 @@ func NewResolutionMetadata(didUrl string, contentType ContentType, resolutionErr DidProperties: didProperties, } } + +func (r DidResolution) GetStatus() int { + return r.ResolutionMetadata.ResolutionError.GetStatusCode() +} + +func (r DidResolution) GetContentType() string { + return string(r.ResolutionMetadata.ContentType) +} + +func (r DidResolution) GetBytes() []byte { + return []byte{} +} diff --git a/utils/test_utils.go b/utils/test_utils.go new file mode 100644 index 00000000..86734b03 --- /dev/null +++ b/utils/test_utils.go @@ -0,0 +1,69 @@ +package utils + +import ( + "crypto/sha256" + + cheqd "github.com/cheqd/cheqd-node/x/cheqd/types" + resource "github.com/cheqd/cheqd-node/x/resource/types" +) + +const ( + ValidIdentifier = "N22KY2Dyvmuu2Pyy" + ValidMethod = "cheqd" + ValidNamespace = "mainnet" + ValidDid = "did:" + ValidMethod + ":" + ValidNamespace + ":" + ValidIdentifier + ValidResourceId = "a09abea0-22e0-4b35-8f70-9cc3a6d0b5fd" + ValidPubKeyJWK = "{" + + "\"crv\":\"Ed25519\"," + + "\"kid\":\"_Qq0UL2Fq651Q0Fjd6TvnYE-faHiOpRlPVQcY_-tA4A\"," + + "\"kty\":\"OKP\"," + + "\"x\":\"VCpo2LMLhn6iWku8MKvSLg2ZAoC-nlOyPVQaO3FxVeQ\"" + + "}" +) + +func ValidVerificationMethod() cheqd.VerificationMethod { + return cheqd.VerificationMethod{ + Id: ValidDid + "#key-1", + Type: "JsonWebKey2020", + Controller: ValidDid, + PublicKeyJwk: cheqd.JSONToPubKeyJWK(ValidPubKeyJWK), + } +} + +func ValidService() cheqd.Service { + return cheqd.Service{ + Id: ValidDid + "#service-1", + Type: "DIDCommMessaging", + ServiceEndpoint: "endpoint", + } +} + +func ValidDIDDoc() cheqd.Did { + service := ValidService() + verificationMethod := ValidVerificationMethod() + + return cheqd.Did{ + Id: ValidDid, + VerificationMethod: []*cheqd.VerificationMethod{&verificationMethod}, + Service: []*cheqd.Service{&service}, + } +} + +func ValidResource() resource.Resource { + data := []byte("{\"attr\":[\"name\",\"age\"]}") + return resource.Resource{ + Header: &resource.ResourceHeader{ + CollectionId: ValidIdentifier, + Id: ValidResourceId, + Name: "Existing_Resource_Name", + ResourceType: "CL-Schema", + MediaType: "application/json", + Checksum: sha256.New().Sum(data), + }, + Data: data, + } +} + +func ValidMetadata() cheqd.Metadata { + return cheqd.Metadata{VersionId: "test_version_id", Deactivated: false, Resources: []string{ValidResourceId}} +}