diff --git a/pkg/didmethod/peer/resolver.go b/pkg/didmethod/peer/resolver.go index 3db9d963c..3e3b5d6b6 100644 --- a/pkg/didmethod/peer/resolver.go +++ b/pkg/didmethod/peer/resolver.go @@ -36,3 +36,8 @@ func (resl *DIDResolver) Read(did string, versionID interface{}, versionTime str return jsonDoc, nil } + +// Accept did method +func (resl *DIDResolver) Accept(method string) bool { + return "peer" == method +} diff --git a/pkg/didmethod/peer/resolver_test.go b/pkg/didmethod/peer/resolver_test.go index 61d942438..42c915576 100644 --- a/pkg/didmethod/peer/resolver_test.go +++ b/pkg/didmethod/peer/resolver_test.go @@ -115,7 +115,7 @@ func TestWithDIDResolveAPI(t *testing.T) { err = store.Put(peerDID, peerDoc, nil) require.NoError(t, err) - r := didresolver.New(didresolver.WithDidMethod("peer", NewDIDResolver(store))) + r := didresolver.New(didresolver.WithDidMethod(NewDIDResolver(store))) _, err = r.Resolve(peerDID) require.NoError(t, err) diff --git a/pkg/framework/didresolver/api.go b/pkg/framework/didresolver/api.go index d2ce5b7f4..c35245de3 100644 --- a/pkg/framework/didresolver/api.go +++ b/pkg/framework/didresolver/api.go @@ -5,7 +5,9 @@ SPDX-License-Identifier: Apache-2.0 package didresolver -import "time" +import ( + "time" +) // ResultType input option can be used to request a certain type of result. type ResultType int @@ -20,6 +22,7 @@ const ( // DidMethod operations type DidMethod interface { Read(did string, versionID interface{}, versionTime string, noCache bool) ([]byte, error) + Accept(method string) bool } // resolveOpts holds the options for did resolve @@ -63,15 +66,16 @@ func WithNoCache(noCache bool) ResolveOpt { // didResolverOpts holds the options for resolver instance type didResolverOpts struct { - didMethods map[string]DidMethod + didMethods []DidMethod } // Opt is a resolver instance option type Opt func(opts *didResolverOpts) // WithDidMethod to add did method -func WithDidMethod(id string, method DidMethod) Opt { +// DID methods are checked in the order added +func WithDidMethod(method DidMethod) Opt { return func(opts *didResolverOpts) { - opts.didMethods[id] = method + opts.didMethods = append(opts.didMethods, method) } } diff --git a/pkg/framework/didresolver/api_test.go b/pkg/framework/didresolver/api_test.go index 8d6564ee2..84dc631e3 100644 --- a/pkg/framework/didresolver/api_test.go +++ b/pkg/framework/didresolver/api_test.go @@ -43,9 +43,8 @@ func TestWithNoCache(t *testing.T) { } func TestWithDidMethod(t *testing.T) { - opt := WithDidMethod("test", nil) - resolverOpts := &didResolverOpts{didMethods: make(map[string]DidMethod)} + opt := WithDidMethod(nil) + resolverOpts := &didResolverOpts{didMethods: make([]DidMethod, 0)} opt(resolverOpts) - _, exist := resolverOpts.didMethods["test"] - require.True(t, exist) + require.True(t, len(resolverOpts.didMethods) == 1) } diff --git a/pkg/framework/didresolver/didresolver.go b/pkg/framework/didresolver/didresolver.go index cd868ab88..b35f4ba77 100644 --- a/pkg/framework/didresolver/didresolver.go +++ b/pkg/framework/didresolver/didresolver.go @@ -14,12 +14,12 @@ import ( // DIDResolver did resolver type DIDResolver struct { - didMethods map[string]DidMethod + didMethods []DidMethod } // New return new instance of did resolver func New(opts ...Opt) *DIDResolver { - resolverOpts := &didResolverOpts{didMethods: make(map[string]DidMethod)} + resolverOpts := &didResolverOpts{didMethods: make([]DidMethod, 0)} // Apply options for _, opt := range opts { opt(resolverOpts) @@ -44,9 +44,10 @@ func (r *DIDResolver) Resolve(did string, opts ...ResolveOpt) (*diddoc.Doc, erro // Determine if the input DID method is supported by the DID Resolver didMethod := didParts[1] - method, exist := r.didMethods[didMethod] - if !exist { - return nil, errors.Errorf("did method %s not supported", didMethod) + // resolve did method + method, err := r.resolveDidMethod(didMethod) + if err != nil { + return nil, err } // Obtain the DID Document @@ -73,3 +74,13 @@ func (r *DIDResolver) Resolve(did string, opts ...ResolveOpt) (*diddoc.Doc, erro return didDoc, nil } + +// resolveDidMethod resolve did method +func (r *DIDResolver) resolveDidMethod(method string) (DidMethod, error) { + for _, v := range r.didMethods { + if v.Accept(method) { + return v, nil + } + } + return nil, errors.Errorf("did method %s not supported", method) +} diff --git a/pkg/framework/didresolver/didresolver_test.go b/pkg/framework/didresolver/didresolver_test.go index e17171149..0d89ef2ac 100644 --- a/pkg/framework/didresolver/didresolver_test.go +++ b/pkg/framework/didresolver/didresolver_test.go @@ -59,68 +59,101 @@ var doc = `{ }` func TestNew(t *testing.T) { - r := New(WithDidMethod("test", nil)) - _, exist := r.didMethods["test"] - require.True(t, exist) + r := New(WithDidMethod(nil)) + require.True(t, len(r.didMethods) == 1) } func TestResolve(t *testing.T) { t.Run("test invalid did input", func(t *testing.T) { - r := New(WithDidMethod("test", nil)) + r := New(WithDidMethod(nil)) _, err := r.Resolve("did:example") require.Error(t, err) require.Contains(t, err.Error(), "wrong format did input") }) t.Run("test did method not supported", func(t *testing.T) { - r := New(WithDidMethod("test", nil)) + r := New(WithDidMethod(mockDidMethod{acceptFunc: func(method string) bool { + return false + }})) _, err := r.Resolve("did:example:1234") require.Error(t, err) require.Contains(t, err.Error(), "did method example not supported") }) t.Run("test did method read failed", func(t *testing.T) { - r := New(WithDidMethod("example", mockDidMethod{readErr: fmt.Errorf("read error")})) + r := New(WithDidMethod(mockDidMethod{readErr: fmt.Errorf("read error"), acceptFunc: func(method string) bool { + return true + }})) _, err := r.Resolve("did:example:1234") require.Error(t, err) require.Contains(t, err.Error(), "did method read failed") }) t.Run("test did input not found", func(t *testing.T) { - r := New(WithDidMethod("example", mockDidMethod{})) + r := New(WithDidMethod(mockDidMethod{acceptFunc: func(method string) bool { + return true + }})) didDoc, err := r.Resolve("did:example:1234") require.NoError(t, err) require.Nil(t, didDoc) }) t.Run("test did doc not valid", func(t *testing.T) { - r := New(WithDidMethod("example", mockDidMethod{readValue: []byte("wrongData")})) + r := New(WithDidMethod(mockDidMethod{readValue: []byte("wrongData"), acceptFunc: func(method string) bool { + return true + }})) _, err := r.Resolve("did:example:1234") require.Error(t, err) require.Contains(t, err.Error(), "Validation of did doc failed") }) t.Run("test result type resolution-result", func(t *testing.T) { - r := New(WithDidMethod("example", mockDidMethod{readValue: []byte(doc)})) + r := New(WithDidMethod(mockDidMethod{readValue: []byte(doc), acceptFunc: func(method string) bool { + return true + }})) _, err := r.Resolve("did:example:1234", WithResultType(ResolutionResult)) require.Error(t, err) require.Contains(t, err.Error(), "result type 'resolution-result' not supported") }) t.Run("test result type did-document", func(t *testing.T) { - r := New(WithDidMethod("example", mockDidMethod{readValue: []byte(doc)})) + r := New(WithDidMethod(mockDidMethod{readValue: []byte(doc), acceptFunc: func(method string) bool { + return true + }})) didDoc, err := r.Resolve("did:example:1234", WithResultType(DidDocumentResult)) require.NoError(t, err) require.Equal(t, didDoc.Context[0], "https://w3id.org/did/v1") }) + t.Run("test resolve did method in order", func(t *testing.T) { + r := New(WithDidMethod(mockDidMethod{readValue: []byte("did1"), acceptFunc: func(method string) bool { + return method == "did1" + }}), WithDidMethod(mockDidMethod{readValue: []byte("did2"), acceptFunc: func(method string) bool { + return true + }})) + didMethod, err := r.resolveDidMethod("did1") + require.NoError(t, err) + v, _ := didMethod.Read("", nil, "", false) + require.Equal(t, "did1", string(v)) + didMethod, err = r.resolveDidMethod("did2") + require.NoError(t, err) + v, _ = didMethod.Read("", nil, "", false) + require.Equal(t, "did2", string(v)) + + }) + } type mockDidMethod struct { - readValue []byte - readErr error + readValue []byte + readErr error + acceptFunc func(method string) bool } func (m mockDidMethod) Read(did string, versionID interface{}, versionTime string, noCache bool) ([]byte, error) { return m.readValue, m.readErr } + +func (m mockDidMethod) Accept(method string) bool { + return m.acceptFunc(method) +}