diff --git a/auth/api/iam/api.go b/auth/api/iam/api.go
index 816de10f7f..cc230072e4 100644
--- a/auth/api/iam/api.go
+++ b/auth/api/iam/api.go
@@ -30,7 +30,7 @@ import (
"github.com/nuts-foundation/nuts-node/core"
"github.com/nuts-foundation/nuts-node/vcr"
"github.com/nuts-foundation/nuts-node/vcr/openid4vci"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
+ "github.com/nuts-foundation/nuts-node/vdr/resolver"
vdr "github.com/nuts-foundation/nuts-node/vdr/types"
"html/template"
"net/http"
@@ -206,7 +206,7 @@ func (r Wrapper) OAuthAuthorizationServerMetadata(ctx context.Context, request O
owned, err := r.vdr.IsOwner(ctx, ownDID)
if err != nil {
- if didservice.IsFunctionalResolveError(err) {
+ if resolver.IsFunctionalResolveError(err) {
return nil, core.NotFoundError("authz server metadata: %w", err)
}
log.Logger().WithField("did", ownDID.String()).Errorf("authz server metadata: failed to assert ownership of did: %s", err.Error())
@@ -227,7 +227,7 @@ func (r Wrapper) GetWebDID(ctx context.Context, request GetWebDIDRequestObject)
document, err := r.vdr.DeriveWebDIDDocument(ctx, baseURL, ownDID)
if err != nil {
- if didservice.IsFunctionalResolveError(err) {
+ if resolver.IsFunctionalResolveError(err) {
return GetWebDID404Response{}, nil
}
log.Logger().WithError(err).Errorf("Could not resolve Nuts DID: %s", ownDID.String())
diff --git a/crypto/api/v1/api.go b/crypto/api/v1/api.go
index f105d4a53f..b81442ab28 100644
--- a/crypto/api/v1/api.go
+++ b/crypto/api/v1/api.go
@@ -35,7 +35,6 @@ import (
"github.com/nuts-foundation/nuts-node/audit"
"github.com/nuts-foundation/nuts-node/core"
"github.com/nuts-foundation/nuts-node/crypto"
- "github.com/nuts-foundation/nuts-node/vdr/types"
)
var _ StrictServerInterface = (*Wrapper)(nil)
@@ -196,14 +195,14 @@ func (w *Wrapper) resolvePublicKey(id *did.DID) (key crypt.PublicKey, keyID ssi.
if id.IsURL() {
// Assume it is a keyId
now := time.Now()
- key, err = w.K.ResolveKeyByID(id.String(), &now, types.KeyAgreement)
+ key, err = w.K.ResolveKeyByID(id.String(), &now, resolver.KeyAgreement)
if err != nil {
return nil, ssi.URI{}, err
}
keyID = id.URI()
} else {
// Assume it is a DID
- keyID, key, err = w.K.ResolveKey(*id, nil, types.KeyAgreement)
+ keyID, key, err = w.K.ResolveKey(*id, nil, resolver.KeyAgreement)
if err != nil {
return nil, ssi.URI{}, err
}
diff --git a/crypto/api/v1/api_test.go b/crypto/api/v1/api_test.go
index f04558e40d..1d928ff49a 100644
--- a/crypto/api/v1/api_test.go
+++ b/crypto/api/v1/api_test.go
@@ -253,7 +253,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
Payload: payload,
Headers: headers,
}
- ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(ssi.URI{}, nil, errors.New("FAIL"))
+ ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, resolver.KeyAgreement).Return(ssi.URI{}, nil, errors.New("FAIL"))
jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request})
assert.EqualError(t, err, "invalid receiver: FAIL")
@@ -268,7 +268,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
Payload: payload,
Headers: headers,
}
- ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(ssi.URI{}, nil, errors.New("FAIL"))
+ ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, resolver.KeyAgreement).Return(ssi.URI{}, nil, errors.New("FAIL"))
jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request})
assert.EqualError(t, err, "invalid receiver: FAIL")
@@ -283,7 +283,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
Payload: payload,
Headers: headers,
}
- ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), gomock.Any(), types.KeyAgreement).Return(ssi.URI{}, errors.New("FAIL"))
+ ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), gomock.Any(), resolver.KeyAgreement).Return(ssi.URI{}, errors.New("FAIL"))
jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request})
assert.EqualError(t, err, "invalid receiver: FAIL")
@@ -298,7 +298,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
Payload: payload,
Headers: headers,
}
- ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(ssi.URI{}, nil, resolver.ErrNotFound)
+ ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, resolver.KeyAgreement).Return(ssi.URI{}, nil, resolver.ErrNotFound)
jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request})
assert.EqualError(t, err, "unable to locate receiver did:nuts:12345: unable to find the DID document")
@@ -313,7 +313,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
Payload: payload,
Headers: headers,
}
- ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(ssi.URI{}, nil, resolver.ErrNotFound)
+ ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, resolver.KeyAgreement).Return(ssi.URI{}, nil, resolver.ErrNotFound)
jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request})
assert.EqualError(t, err, "unable to locate receiver did:nuts:12345: unable to find the DID document")
@@ -328,7 +328,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
Payload: payload,
Headers: headers,
}
- ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), gomock.Any(), types.KeyAgreement).Return(ssi.URI{}, resolver.ErrNotFound)
+ ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), gomock.Any(), resolver.KeyAgreement).Return(ssi.URI{}, resolver.ErrNotFound)
jwe, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request})
assert.EqualError(t, err, "unable to locate receiver did:nuts:12345#key-1: unable to find the DID document")
@@ -360,7 +360,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
did, _ := ssi.ParseURI("did:nuts:12345")
ctx.keyStore.EXPECT().EncryptJWE(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("", errors.New("b00m!"))
- ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(*did, nil, nil)
+ ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, resolver.KeyAgreement).Return(*did, nil, nil)
jwe, err := ctx.client.EncryptJwe(audit.TestContext(), EncryptJweRequestObject{Body: &request})
@@ -378,7 +378,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
Payload: payload,
}
ctx.keyStore.EXPECT().EncryptJWE(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("jwe", nil)
- ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(*did, nil, nil)
+ ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, resolver.KeyAgreement).Return(*did, nil, nil)
resp, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request})
@@ -396,7 +396,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
Payload: payload,
}
ctx.keyStore.EXPECT().EncryptJWE(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("jwe", nil)
- ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), gomock.Any(), types.KeyAgreement).Return(*did, nil)
+ ctx.keyResolver.EXPECT().ResolveKeyByID(gomock.Any(), gomock.Any(), resolver.KeyAgreement).Return(*did, nil)
resp, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request})
@@ -414,7 +414,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
}
did, _ := ssi.ParseURI(kid)
ctx.keyStore.EXPECT().EncryptJWE(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("jwe", nil)
- ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(*did, nil, nil)
+ ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, resolver.KeyAgreement).Return(*did, nil, nil)
resp, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request})
@@ -430,7 +430,7 @@ func TestWrapper_EncryptJwe(t *testing.T) {
Receiver: did.String(),
}
ctx.keyStore.EXPECT().EncryptJWE(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("jwe", nil)
- ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, types.KeyAgreement).Return(*did, nil, nil)
+ ctx.keyResolver.EXPECT().ResolveKey(gomock.Any(), nil, resolver.KeyAgreement).Return(*did, nil, nil)
resp, err := ctx.client.EncryptJwe(nil, EncryptJweRequestObject{Body: &request})
diff --git a/didman/didman.go b/didman/didman.go
index d82e8e8abe..9482ca8494 100644
--- a/didman/didman.go
+++ b/didman/didman.go
@@ -25,7 +25,6 @@ import (
"encoding/json"
"errors"
"fmt"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"net/url"
"sync"
@@ -283,7 +282,7 @@ func (d *didman) GetCompoundServiceEndpoint(id did.DID, compoundServiceType stri
}
func (d *didman) DeleteService(ctx context.Context, serviceID ssi.URI) error {
- id, err := didservice.GetDIDFromURL(serviceID.String())
+ id, err := resolver.GetDIDFromURL(serviceID.String())
if err != nil {
return err
}
@@ -299,7 +298,7 @@ func (d *didman) deleteService(ctx context.Context, serviceID ssi.URI) error {
log.Logger().
WithField(core.LogFieldServiceID, serviceID.String()).
Debug("Deleting service")
- id, err := didservice.GetDIDFromURL(serviceID.String())
+ id, err := resolver.GetDIDFromURL(serviceID.String())
if err != nil {
return err
}
@@ -469,7 +468,7 @@ func (d *didman) resolveOrganizationDIDDocuments(organizations []vc.VerifiableCr
j := 0
for i, organization := range organizations {
document, organizationDID, err := d.resolveOrganizationDIDDocument(organization)
- if didservice.IsFunctionalResolveError(err) {
+ if resolver.IsFunctionalResolveError(err) {
// Just ignore deactivated DID documents or VCs that don't refer to an existing DID document.
// Log it on debug, because it might be useful for finding VCs that need to be revoked (since they're invalid).
log.Logger().
diff --git a/golden_hammer/module.go b/golden_hammer/module.go
index 44cfda7b8c..5620c432bc 100644
--- a/golden_hammer/module.go
+++ b/golden_hammer/module.go
@@ -29,7 +29,6 @@ import (
"github.com/nuts-foundation/nuts-node/network/transport"
"github.com/nuts-foundation/nuts-node/vcr"
"github.com/nuts-foundation/nuts-node/vcr/openid4vci"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"github.com/nuts-foundation/nuts-node/vdr/types"
"net/url"
@@ -142,7 +141,7 @@ func (h *GoldenHammer) registerServiceBaseURLs() error {
serviceEndpoint := getServiceEndpoint(document, transport.NutsCommServiceType)
if resolver.IsServiceReference(serviceEndpoint) {
// Care organization DID document, register service pointing to vendor DID.
- parentDID, err := didservice.GetDIDFromURL(serviceEndpoint)
+ parentDID, err := resolver.GetDIDFromURL(serviceEndpoint)
if err != nil {
// Invalid NutsComm reference, skip
log.Logger().WithError(err).
@@ -194,7 +193,7 @@ func (h *GoldenHammer) listDocumentToFix() ([]did.Document, error) {
}
document, _, err := h.vdrInstance.Resolver().Resolve(id, nil)
if err != nil {
- if !didservice.IsFunctionalResolveError(err) {
+ if !resolver.IsFunctionalResolveError(err) {
log.Logger().WithError(err).Infof("Can't resolve DID document, skipping fix (did=%s)", id)
}
continue
@@ -238,7 +237,7 @@ func (h *GoldenHammer) tryResolveURL(id did.DID) (*url.URL, error) {
// resolveContainsService returns whether 1. given DID document can be resolved, and 2. it contains the specified service.
func (h *GoldenHammer) resolveContainsService(id did.DID, serviceType string) bool {
document, _, err := h.vdrInstance.Resolver().Resolve(id, nil)
- if didservice.IsFunctionalResolveError(err) {
+ if resolver.IsFunctionalResolveError(err) {
// Unresolvable DID document, nothing to do
return false
}
diff --git a/network/dag/keys.go b/network/dag/keys.go
index a041149d54..37036ca021 100644
--- a/network/dag/keys.go
+++ b/network/dag/keys.go
@@ -22,7 +22,6 @@ import (
"fmt"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/crypto/hash"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
resolver2 "github.com/nuts-foundation/nuts-node/vdr/resolver"
)
@@ -53,7 +52,7 @@ func resolvePublicKey(resolver resolver2.DIDResolver, kid string, metadata resol
if err != nil {
return nil, fmt.Errorf("invalid key ID (id=%s): %w", kid, err)
}
- holder, _ := didservice.GetDIDFromURL(kid) // can't fail, already parsed
+ holder, _ := resolver2.GetDIDFromURL(kid) // can't fail, already parsed
doc, _, err := resolver.Resolve(holder, &metadata)
if err != nil {
return nil, err
diff --git a/network/dag/pal.go b/network/dag/pal.go
index 373f2394f3..dd04449d3a 100644
--- a/network/dag/pal.go
+++ b/network/dag/pal.go
@@ -31,7 +31,6 @@ import (
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/crypto"
"github.com/nuts-foundation/nuts-node/network/log"
- "github.com/nuts-foundation/nuts-node/vdr/types"
)
// palHeaderDIDSeparator holds the character(s) that separate DID entries in the PAL header, before being encrypted.
@@ -59,7 +58,7 @@ func (pal PAL) Encrypt(keyResolver resolver.KeyResolver) (EncryptedPAL, error) {
var recipients [][]byte
for _, recipient := range pal {
recipients = append(recipients, []byte(recipient.String()))
- _, rawKak, err := keyResolver.ResolveKey(recipient, nil, types.KeyAgreement)
+ _, rawKak, err := keyResolver.ResolveKey(recipient, nil, resolver.KeyAgreement)
if err != nil {
return nil, fmt.Errorf("unable to resolve keyAgreement key (recipient=%s): %w", recipient, err)
}
diff --git a/network/dag/pal_test.go b/network/dag/pal_test.go
index c6ac09f015..c4a21da9b5 100644
--- a/network/dag/pal_test.go
+++ b/network/dag/pal_test.go
@@ -48,8 +48,8 @@ func TestEncryptPal(t *testing.T) {
// Encrypt
ctrl := gomock.NewController(t)
keyResolver := types.NewMockKeyResolver(ctrl)
- keyResolver.EXPECT().ResolveKey(*pA, nil, types.KeyAgreement).Return(ssi.URI{}, pkA.Public(), nil)
- keyResolver.EXPECT().ResolveKey(*pB, nil, types.KeyAgreement).Return(ssi.URI{}, pkB.Public(), nil)
+ keyResolver.EXPECT().ResolveKey(*pA, nil, resolver.KeyAgreement).Return(ssi.URI{}, pkA.Public(), nil)
+ keyResolver.EXPECT().ResolveKey(*pB, nil, resolver.KeyAgreement).Return(ssi.URI{}, pkB.Public(), nil)
expected := PAL{*pA, *pB}
pal, err := expected.Encrypt(keyResolver)
require.NoError(t, err)
@@ -72,7 +72,7 @@ func TestEncryptPal(t *testing.T) {
t.Run("error - keyAgreement key type is not supported", func(t *testing.T) {
ctrl := gomock.NewController(t)
keyResolver := types.NewMockKeyResolver(ctrl)
- keyResolver.EXPECT().ResolveKey(*pA, nil, types.KeyAgreement).Return(ssi.URI{}, &rsa.PublicKey{}, nil)
+ keyResolver.EXPECT().ResolveKey(*pA, nil, resolver.KeyAgreement).Return(ssi.URI{}, &rsa.PublicKey{}, nil)
pal, err := PAL{*pA}.Encrypt(keyResolver)
assert.Nil(t, pal)
assert.EqualError(t, err, "resolved keyAgreement key is not an elliptic curve key (recipient=did:nuts:A)")
@@ -80,7 +80,7 @@ func TestEncryptPal(t *testing.T) {
t.Run("error - no keyAgreements", func(t *testing.T) {
ctrl := gomock.NewController(t)
keyResolver := types.NewMockKeyResolver(ctrl)
- keyResolver.EXPECT().ResolveKey(*pA, nil, types.KeyAgreement).Return(ssi.URI{}, nil, resolver.ErrKeyNotFound)
+ keyResolver.EXPECT().ResolveKey(*pA, nil, resolver.KeyAgreement).Return(ssi.URI{}, nil, resolver.ErrKeyNotFound)
pal, err := PAL{*pA}.Encrypt(keyResolver)
assert.Nil(t, pal)
assert.EqualError(t, err, "unable to resolve keyAgreement key (recipient=did:nuts:A): key not found in DID document")
diff --git a/network/network.go b/network/network.go
index 59f139fe83..c5da1db41d 100644
--- a/network/network.go
+++ b/network/network.go
@@ -26,7 +26,7 @@ import (
"errors"
"fmt"
"github.com/nuts-foundation/nuts-node/vdr/didnuts/didstore"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
+ "github.com/nuts-foundation/nuts-node/vdr/management"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"net"
"strings"
@@ -46,7 +46,6 @@ import (
"github.com/nuts-foundation/nuts-node/network/transport/v2"
"github.com/nuts-foundation/nuts-node/pki"
"github.com/nuts-foundation/nuts-node/storage"
- "github.com/nuts-foundation/nuts-node/vdr/types"
"go.etcd.io/bbolt"
)
@@ -86,7 +85,7 @@ type Network struct {
peerID transport.PeerID
nodeDID did.DID
didStore didstore.Store
- didDocumentFinder types.DocFinder
+ didDocumentFinder management.DocFinder
serviceResolver resolver.ServiceResolver
eventPublisher events.Event
storeProvider storage.Provider
@@ -391,7 +390,7 @@ func (n *Network) connectToKnownNodes(nodeDID did.DID) error {
}
// start connecting to published NutsComm addresses
- otherNodes, err := n.didDocumentFinder.Find(didservice.IsActive(), didservice.ValidAt(time.Now()), didservice.ByServiceType(transport.NutsCommServiceType))
+ otherNodes, err := n.didDocumentFinder.Find(management.IsActive(), management.ValidAt(time.Now()), management.ByServiceType(transport.NutsCommServiceType))
if err != nil {
return err
}
diff --git a/network/network_test.go b/network/network_test.go
index 2a32514e77..5cbe50013f 100644
--- a/network/network_test.go
+++ b/network/network_test.go
@@ -464,8 +464,8 @@ func TestNetwork_CreateTransaction(t *testing.T) {
cxt.state.EXPECT().Head(gomock.Any())
cxt.state.EXPECT().Add(gomock.Any(), gomock.Any(), payload)
- cxt.keyResolver.EXPECT().ResolveKey(*sender, nil, vdrTypes.KeyAgreement).Return(ssi.MustParseURI("sender"), senderKey.Public(), nil)
- cxt.keyResolver.EXPECT().ResolveKey(*receiver, nil, vdrTypes.KeyAgreement).Return(ssi.MustParseURI("receiver"), receiverKey.Public(), nil)
+ cxt.keyResolver.EXPECT().ResolveKey(*sender, nil, resolver.KeyAgreement).Return(ssi.MustParseURI("sender"), senderKey.Public(), nil)
+ cxt.keyResolver.EXPECT().ResolveKey(*receiver, nil, resolver.KeyAgreement).Return(ssi.MustParseURI("receiver"), receiverKey.Public(), nil)
_, err = cxt.network.CreateTransaction(ctx, TransactionTemplate(payloadType, payload, key).WithPrivate([]did.DID{*sender, *receiver}))
assert.NoError(t, err)
diff --git a/vcr/credential/validator.go b/vcr/credential/validator.go
index 1bfae34b06..7aa72d7266 100644
--- a/vcr/credential/validator.go
+++ b/vcr/credential/validator.go
@@ -24,7 +24,7 @@ import (
"errors"
"fmt"
"github.com/nuts-foundation/go-did/did"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
+ "github.com/nuts-foundation/nuts-node/vdr/resolver"
"github.com/piprate/json-gold/ld"
"strings"
@@ -238,7 +238,7 @@ func validOperation(operation string) bool {
}
func validateNutsCredentialID(credential vc.VerifiableCredential) error {
- id, err := didservice.GetDIDFromURL(credential.ID.String())
+ id, err := resolver.GetDIDFromURL(credential.ID.String())
if err != nil {
return err
}
diff --git a/vcr/issuer/issuer.go b/vcr/issuer/issuer.go
index 40d9a6d7f1..fa6ee6a74a 100644
--- a/vcr/issuer/issuer.go
+++ b/vcr/issuer/issuer.go
@@ -23,7 +23,6 @@ import (
"encoding/json"
"fmt"
"github.com/nuts-foundation/nuts-node/vcr/openid4vci"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
resolver2 "github.com/nuts-foundation/nuts-node/vdr/resolver"
"time"
@@ -194,7 +193,7 @@ func (i issuer) buildVC(ctx context.Context, credentialOptions vc.VerifiableCred
if err != nil {
const errString = "failed to sign credential: could not resolve an assertionKey for issuer: %w"
// Differentiate between a DID document not found and some other error:
- if didservice.IsFunctionalResolveError(err) {
+ if resolver2.IsFunctionalResolveError(err) {
return nil, core.InvalidInputError(errString, err)
}
return nil, fmt.Errorf(errString, err)
@@ -298,7 +297,7 @@ func (i issuer) buildRevocation(ctx context.Context, credentialID ssi.URI) (*cre
if err != nil {
const errString = "failed to revoke credential (%s): could not resolve an assertionKey for issuer: %w"
// Differentiate between a DID document not found and some other error:
- if didservice.IsFunctionalResolveError(err) {
+ if resolver2.IsFunctionalResolveError(err) {
return nil, core.InvalidInputError(errString, credentialID, err)
}
return nil, fmt.Errorf(errString, credentialID, err)
diff --git a/vcr/issuer/keyresolver.go b/vcr/issuer/keyresolver.go
index bce16ffaf6..6256fb6045 100644
--- a/vcr/issuer/keyresolver.go
+++ b/vcr/issuer/keyresolver.go
@@ -24,7 +24,6 @@ import (
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/crypto"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
- vdr "github.com/nuts-foundation/nuts-node/vdr/types"
)
// vdrKeyResolver resolves private keys based upon the VDR document resolver
@@ -35,7 +34,7 @@ type vdrKeyResolver struct {
// ResolveAssertionKey is a convenience method which tries to find a assertionKey on in the VDR for a given issuerDID.
func (r vdrKeyResolver) ResolveAssertionKey(ctx context.Context, issuerDID did.DID) (crypto.Key, error) {
- kid, _, err := r.publicKeyResolver.ResolveKey(issuerDID, nil, vdr.AssertionMethod)
+ kid, _, err := r.publicKeyResolver.ResolveKey(issuerDID, nil, resolver.AssertionMethod)
if err != nil {
return nil, fmt.Errorf("invalid issuer: %w", err)
}
diff --git a/vcr/issuer/openid.go b/vcr/issuer/openid.go
index 29f4b8ee48..a8ee1ec298 100644
--- a/vcr/issuer/openid.go
+++ b/vcr/issuer/openid.go
@@ -37,7 +37,6 @@ import (
"github.com/nuts-foundation/nuts-node/vcr/issuer/assets"
"github.com/nuts-foundation/nuts-node/vcr/log"
"github.com/nuts-foundation/nuts-node/vcr/openid4vci"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"io/fs"
"net/http"
@@ -332,7 +331,7 @@ func (i *openidHandler) validateProof(ctx context.Context, flow *Flow, request o
}
// Proof must be signed by wallet to which it was offered (proof signer == offer receiver)
- if signerDID, err := didservice.GetDIDFromURL(signingKeyID); err != nil || signerDID.String() != wallet.String() {
+ if signerDID, err := resolver.GetDIDFromURL(signingKeyID); err != nil || signerDID.String() != wallet.String() {
return generateProofError(openid4vci.Error{
Err: fmt.Errorf("credential offer was signed by other DID than intended wallet: %s", signingKeyID),
Code: openid4vci.InvalidProof,
diff --git a/vcr/openid4vci/identifiers.go b/vcr/openid4vci/identifiers.go
index d52746c4a3..ffacf3cb3c 100644
--- a/vcr/openid4vci/identifiers.go
+++ b/vcr/openid4vci/identifiers.go
@@ -24,7 +24,6 @@ import (
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/core"
"github.com/nuts-foundation/nuts-node/vcr/log"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"net/http"
"net/url"
@@ -58,7 +57,7 @@ type DIDIdentifierResolver struct {
func (i DIDIdentifierResolver) Resolve(id did.DID) (string, error) {
service, err := i.ServiceResolver.Resolve(resolver.MakeServiceReference(id, resolver.BaseURLServiceType), resolver.DefaultMaxServiceReferenceDepth)
- if didservice.IsFunctionalResolveError(err) {
+ if resolver.IsFunctionalResolveError(err) {
return "", nil
} else if err != nil {
return "", fmt.Errorf("unable to resolve %s service: %w", resolver.BaseURLServiceType, err)
diff --git a/vdr/cmd/cmd.go b/vdr/cmd/cmd.go
index a3d1888e37..f10a202c3d 100644
--- a/vdr/cmd/cmd.go
+++ b/vdr/cmd/cmd.go
@@ -24,7 +24,7 @@ import (
"errors"
"fmt"
"github.com/nuts-foundation/nuts-node/vdr/didnuts"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
+ "github.com/nuts-foundation/nuts-node/vdr/resolver"
"io"
"os"
"strings"
@@ -286,7 +286,7 @@ func addKeyAgreementKeyCmd() *cobra.Command {
if err != nil {
return fmt.Errorf("invalid key ID '%s': %w", args[0], err)
}
- targetDID, _ := didservice.GetDIDFromURL(args[0]) // can't fail because we already parsed the key ID
+ targetDID, _ := resolver.GetDIDFromURL(args[0]) // can't fail because we already parsed the key ID
clientConfig := core.NewClientConfigForCommand(cmd)
client := httpClient(clientConfig)
diff --git a/vdr/did_owner.go b/vdr/did_owner.go
index d9fb9e3b6f..ae094f757e 100644
--- a/vdr/did_owner.go
+++ b/vdr/did_owner.go
@@ -23,7 +23,6 @@ import (
"fmt"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/crypto"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"github.com/nuts-foundation/nuts-node/vdr/types"
"strings"
@@ -77,7 +76,7 @@ func (t *cachingDocumentOwner) IsOwner(ctx context.Context, id did.DID) (bool, e
// First perform a cheap DID existence check (subsequent checks are more expensive),
// without caching it as negative match (would allow unbound number of negative matches).
_, _, err := t.didResolver.Resolve(id, nil)
- if didservice.IsFunctionalResolveError(err) {
+ if resolver.IsFunctionalResolveError(err) {
return false, nil
} else if err != nil {
return false, fmt.Errorf("unable to check ownership of DID: %w", err)
diff --git a/vdr/didnuts/creator.go b/vdr/didnuts/creator.go
index 03ae71f4ab..6e2e2e3df2 100644
--- a/vdr/didnuts/creator.go
+++ b/vdr/didnuts/creator.go
@@ -22,7 +22,7 @@ import (
"crypto"
"errors"
"fmt"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
+ "github.com/nuts-foundation/nuts-node/vdr/resolver"
ssi "github.com/nuts-foundation/go-did"
@@ -153,7 +153,7 @@ func (n Creator) Create(ctx context.Context, options vdr.DIDCreationOptions) (*d
}
// Create the bare document. The Document DID will be the keyIDStr without the fragment.
- didID, _ := didservice.GetDIDFromURL(key.KID())
+ didID, _ := resolver.GetDIDFromURL(key.KID())
doc := CreateDocument()
doc.ID = didID
doc.Controller = options.Controllers
diff --git a/vdr/didnuts/didstore/finder.go b/vdr/didnuts/didstore/finder.go
index ed839029c5..e6bc3c9c6d 100644
--- a/vdr/didnuts/didstore/finder.go
+++ b/vdr/didnuts/didstore/finder.go
@@ -19,8 +19,8 @@ package didstore
import (
"github.com/nuts-foundation/go-did/did"
+ "github.com/nuts-foundation/nuts-node/vdr/management"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
- "github.com/nuts-foundation/nuts-node/vdr/types"
)
// Finder is a helper that implements the DocFinder interface
@@ -28,7 +28,7 @@ type Finder struct {
Store Store
}
-func (f Finder) Find(predicate ...types.Predicate) ([]did.Document, error) {
+func (f Finder) Find(predicate ...management.Predicate) ([]did.Document, error) {
matches := make([]did.Document, 0)
err := f.Store.Iterate(func(doc did.Document, metadata resolver.DocumentMetadata) error {
diff --git a/vdr/didnuts/didstore/finder_test.go b/vdr/didnuts/didstore/finder_test.go
index 980f446b36..ef97bbd188 100644
--- a/vdr/didnuts/didstore/finder_test.go
+++ b/vdr/didnuts/didstore/finder_test.go
@@ -19,13 +19,12 @@ package didstore
import (
"errors"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
+ "github.com/nuts-foundation/nuts-node/vdr/management"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"github.com/stretchr/testify/require"
"testing"
"github.com/nuts-foundation/go-did/did"
- "github.com/nuts-foundation/nuts-node/vdr/types"
"github.com/stretchr/testify/assert"
"go.uber.org/mock/gomock"
)
@@ -36,11 +35,11 @@ func TestFinder_Find(t *testing.T) {
didStore := NewMockStore(ctrl)
finder := Finder{Store: didStore}
didStore.EXPECT().Iterate(gomock.Any()).Do(func(arg interface{}) {
- f := arg.(types.DocIterator)
+ f := arg.(management.DocIterator)
f(did.Document{}, resolver.DocumentMetadata{})
})
- docs, err := finder.Find(didservice.IsActive())
+ docs, err := finder.Find(management.IsActive())
require.NoError(t, err)
assert.Len(t, docs, 1)
@@ -52,7 +51,7 @@ func TestFinder_Find(t *testing.T) {
finder := Finder{Store: didStore}
didStore.EXPECT().Iterate(gomock.Any()).Return(errors.New("b00m!"))
- _, err := finder.Find(didservice.IsActive())
+ _, err := finder.Find(management.IsActive())
assert.Error(t, err)
})
diff --git a/vdr/didnuts/didstore/interface.go b/vdr/didnuts/didstore/interface.go
index 8b0418f38b..6b46c6a277 100644
--- a/vdr/didnuts/didstore/interface.go
+++ b/vdr/didnuts/didstore/interface.go
@@ -20,8 +20,8 @@ package didstore
import (
"github.com/nuts-foundation/go-did/did"
+ "github.com/nuts-foundation/nuts-node/vdr/management"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
- vdr "github.com/nuts-foundation/nuts-node/vdr/types"
)
// Store is the interface that groups all low level VDR DID storage operations.
@@ -29,14 +29,14 @@ type Store interface {
// Add a DID Document to the store. The store will place it on the timeline and reprocess other versions if needed
Add(didDocument did.Document, transaction Transaction) error
// Conflicted iterates over all conflicted documents
- Conflicted(fn vdr.DocIterator) error
+ Conflicted(fn management.DocIterator) error
// ConflictedCount returns the number of conflicted DID Documents
ConflictedCount() (uint, error)
// DocumentCount returns the number of DID Documents
DocumentCount() (uint, error)
// Iterate loops over all the latest versions of the stored DID Documents and applies fn.
// Calling any of the Store's functions from the given fn might cause a deadlock.
- Iterate(fn vdr.DocIterator) error
+ Iterate(fn management.DocIterator) error
// Resolve returns the DID Document for the provided DID.
// If metadata is not provided the latest version is returned.
// If metadata is provided then the result is filtered or scoped on that metadata.
diff --git a/vdr/didnuts/didstore/mock.go b/vdr/didnuts/didstore/mock.go
index 6ec865ffa6..d123833145 100644
--- a/vdr/didnuts/didstore/mock.go
+++ b/vdr/didnuts/didstore/mock.go
@@ -9,11 +9,11 @@
package didstore
import (
+ "github.com/nuts-foundation/nuts-node/vdr/management"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
reflect "reflect"
did "github.com/nuts-foundation/go-did/did"
- types "github.com/nuts-foundation/nuts-node/vdr/types"
gomock "go.uber.org/mock/gomock"
)
@@ -55,7 +55,7 @@ func (mr *MockStoreMockRecorder) Add(didDocument, transaction any) *gomock.Call
}
// Conflicted mocks base method.
-func (m *MockStore) Conflicted(fn types.DocIterator) error {
+func (m *MockStore) Conflicted(fn management.DocIterator) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Conflicted", fn)
ret0, _ := ret[0].(error)
@@ -99,7 +99,7 @@ func (mr *MockStoreMockRecorder) DocumentCount() *gomock.Call {
}
// Iterate mocks base method.
-func (m *MockStore) Iterate(fn types.DocIterator) error {
+func (m *MockStore) Iterate(fn management.DocIterator) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Iterate", fn)
ret0, _ := ret[0].(error)
diff --git a/vdr/didnuts/didstore/store.go b/vdr/didnuts/didstore/store.go
index 248fc5ea91..ddd4083f5c 100644
--- a/vdr/didnuts/didstore/store.go
+++ b/vdr/didnuts/didstore/store.go
@@ -27,8 +27,8 @@ import (
"github.com/nuts-foundation/go-stoabs"
"github.com/nuts-foundation/nuts-node/core"
"github.com/nuts-foundation/nuts-node/storage"
+ "github.com/nuts-foundation/nuts-node/vdr/management"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
- vdr "github.com/nuts-foundation/nuts-node/vdr/types"
)
var _ core.Configurable = (*store)(nil)
@@ -178,7 +178,7 @@ func (tl *store) Resolve(id did.DID, resolveMetadata *resolver.ResolveMetadata)
return
}
-func (tl *store) Iterate(fn vdr.DocIterator) error {
+func (tl *store) Iterate(fn management.DocIterator) error {
return tl.db.Read(context.Background(), func(tx stoabs.ReadTx) error {
latestReader := tx.GetShelfReader(latestShelf)
@@ -247,7 +247,7 @@ func (tl *store) removeCachedConflict(document did.Document) {
delete(tl.conflictedDocuments, document.ID.String())
}
-func (tl *store) Conflicted(fn vdr.DocIterator) error {
+func (tl *store) Conflicted(fn management.DocIterator) error {
for _, conflicted := range tl.conflictedDocuments {
if err := fn(conflicted.didDocument, conflicted.metadata.asVDRMetadata()); err != nil {
return err
diff --git a/vdr/didnuts/resolver.go b/vdr/didnuts/resolver.go
index 5bc9976e09..5be2bc14b8 100644
--- a/vdr/didnuts/resolver.go
+++ b/vdr/didnuts/resolver.go
@@ -23,9 +23,7 @@ import (
"fmt"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/vdr/didnuts/didstore"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
- "github.com/nuts-foundation/nuts-node/vdr/types"
)
const maxControllerDepth = 5
@@ -46,12 +44,12 @@ func (d Resolver) Resolve(id did.DID, metadata *resolver.ResolveMetadata) (*did.
return resolve(d.Store, id, metadata, 0)
}
-func resolve(resolver resolver.DIDResolver, id did.DID, metadata *resolver.ResolveMetadata, depth int) (*did.Document, *resolver.DocumentMetadata, error) {
+func resolve(didResolver resolver.DIDResolver, id did.DID, metadata *resolver.ResolveMetadata, depth int) (*did.Document, *resolver.DocumentMetadata, error) {
if depth >= maxControllerDepth {
return nil, nil, ErrNestedDocumentsTooDeep
}
- doc, meta, err := resolver.Resolve(id, metadata)
+ doc, meta, err := didResolver.Resolve(id, metadata)
if err != nil {
return nil, nil, err
}
@@ -60,7 +58,7 @@ func resolve(resolver resolver.DIDResolver, id did.DID, metadata *resolver.Resol
if len(doc.Controller) > 0 && (metadata == nil || !metadata.AllowDeactivated) {
// also check if the controller is not deactivated
// since ResolveControllers calls Resolve and propagates the metadata
- controllers, err := resolveControllers(resolver, *doc, metadata, depth+1)
+ controllers, err := resolveControllers(didResolver, *doc, metadata, depth+1)
if err != nil {
return nil, nil, err
}
@@ -78,7 +76,7 @@ func ResolveControllers(resolver resolver.DIDResolver, doc did.Document, metadat
return resolveControllers(resolver, doc, metadata, 0)
}
-func resolveControllers(resolver resolver.DIDResolver, doc did.Document, metadata *resolver.ResolveMetadata, depth int) ([]did.Document, error) {
+func resolveControllers(didResolver resolver.DIDResolver, doc did.Document, metadata *resolver.ResolveMetadata, depth int) ([]did.Document, error) {
var leaves []did.Document
var refsToResolve []did.DID
@@ -101,8 +99,8 @@ func resolveControllers(resolver resolver.DIDResolver, doc did.Document, metadat
// resolve all unresolved doc
for _, ref := range refsToResolve {
- node, _, err := resolve(resolver, ref, metadata, depth)
- if errors.Is(err, resolver.ErrDeactivated) || errors.Is(err, resolver.ErrNoActiveController) || errors.Is(err, resolver.ErrNotFound) || errors.Is(err, types.ErrDIDMethodNotSupported) {
+ node, _, err := resolve(didResolver, ref, metadata, depth)
+ if errors.Is(err, resolver.ErrDeactivated) || errors.Is(err, resolver.ErrNoActiveController) || errors.Is(err, resolver.ErrNotFound) || errors.Is(err, resolver.ErrDIDMethodNotSupported) {
continue
}
if errors.Is(err, ErrNestedDocumentsTooDeep) {
@@ -117,7 +115,7 @@ func resolveControllers(resolver resolver.DIDResolver, doc did.Document, metadat
// filter deactivated
j := 0
for _, leaf := range leaves {
- if !didservice.IsDeactivated(leaf) {
+ if !resolver.IsDeactivated(leaf) {
leaves[j] = leaf
j++
}
diff --git a/vdr/didnuts/resolver_test.go b/vdr/didnuts/resolver_test.go
index a6728ed544..45d98d8202 100644
--- a/vdr/didnuts/resolver_test.go
+++ b/vdr/didnuts/resolver_test.go
@@ -42,13 +42,13 @@ func TestNutsDIDResolver_Resolve(t *testing.T) {
t.Run("ok", func(t *testing.T) {
ctrl := gomock.NewController(t)
didStore := didstore.NewMockStore(ctrl)
- resolver := Resolver{Store: didStore}
+ nutsResolver := Resolver{Store: didStore}
doc := did.Document{ID: *id123}
id123Method1, _ := did.ParseDIDURL("did:nuts:123#method-1")
doc.AddCapabilityInvocation(&did.VerificationMethod{ID: *id123Method1})
didStore.EXPECT().Resolve(*id123, resolveMD).Return(&doc, &resolver.DocumentMetadata{}, nil)
- resultDoc, _, err := resolver.Resolve(*id123, resolveMD)
+ resultDoc, _, err := nutsResolver.Resolve(*id123, resolveMD)
require.NoError(t, err)
@@ -59,11 +59,11 @@ func TestNutsDIDResolver_Resolve(t *testing.T) {
t.Run("err - with resolver metadata", func(t *testing.T) {
ctrl := gomock.NewController(t)
didStore := didstore.NewMockStore(ctrl)
- resolver := Resolver{Store: didStore}
+ nutsResolver := Resolver{Store: didStore}
didStore.EXPECT().Resolve(*id456, resolveMD).Return(&docB, &resolver.DocumentMetadata{}, nil)
didStore.EXPECT().Resolve(*id123, resolveMD).Return(&docA, &resolver.DocumentMetadata{}, nil)
- doc, _, err := resolver.Resolve(*id456, resolveMD)
+ doc, _, err := nutsResolver.Resolve(*id456, resolveMD)
assert.Error(t, err)
assert.Equal(t, resolver.ErrNoActiveController, err)
@@ -73,11 +73,11 @@ func TestNutsDIDResolver_Resolve(t *testing.T) {
t.Run("err - without resolve metadata", func(t *testing.T) {
ctrl := gomock.NewController(t)
didStore := didstore.NewMockStore(ctrl)
- resolver := Resolver{Store: didStore}
+ nutsResolver := Resolver{Store: didStore}
didStore.EXPECT().Resolve(*id456, nil).Return(&docB, &resolver.DocumentMetadata{}, nil)
didStore.EXPECT().Resolve(*id123, nil).Return(&docA, &resolver.DocumentMetadata{}, nil)
- doc, _, err := resolver.Resolve(*id456, nil)
+ doc, _, err := nutsResolver.Resolve(*id456, nil)
assert.Error(t, err)
assert.Equal(t, resolver.ErrNoActiveController, err)
@@ -87,12 +87,12 @@ func TestNutsDIDResolver_Resolve(t *testing.T) {
t.Run("ok - allowed deactivated", func(t *testing.T) {
ctrl := gomock.NewController(t)
didStore := didstore.NewMockStore(ctrl)
- resolver := Resolver{Store: didStore}
+ nutsResolver := Resolver{Store: didStore}
resolveMD := &resolver.ResolveMetadata{ResolveTime: &resolveTime, AllowDeactivated: true}
didStore.EXPECT().Resolve(*id456, resolveMD).Return(&docB, &resolver.DocumentMetadata{}, nil)
- doc, _, err := resolver.Resolve(*id456, resolveMD)
+ doc, _, err := nutsResolver.Resolve(*id456, resolveMD)
assert.NoError(t, err)
assert.Equal(t, docB, *doc)
})
@@ -108,7 +108,7 @@ func TestNutsDIDResolver_Resolve(t *testing.T) {
prevID := rootID
prevDoc := rootDoc
didStore := didstore.NewMockStore(ctrl)
- resolver := Resolver{Store: didStore}
+ nutsResolver := Resolver{Store: didStore}
for i := 0; i < depth; i++ {
id, _ := did.ParseDID(fmt.Sprintf("did:nuts:%d", i))
d := did.Document{ID: *id, Controller: []did.DID{*prevID}}
@@ -120,7 +120,7 @@ func TestNutsDIDResolver_Resolve(t *testing.T) {
}
didStore.EXPECT().Resolve(*dids[depth-1], resolveMD).Return(&docs[depth-1], &resolver.DocumentMetadata{}, nil)
- _, _, err := resolver.Resolve(*dids[depth-1], resolveMD)
+ _, _, err := nutsResolver.Resolve(*dids[depth-1], resolveMD)
assert.Error(t, err)
assert.Equal(t, ErrNestedDocumentsTooDeep, err)
@@ -164,18 +164,18 @@ func TestResolveControllers(t *testing.T) {
t.Run("docA is controller of docB", func(t *testing.T) {
ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
+ nutsResolver := types.NewMockDIDResolver(ctrl)
docA := did.Document{ID: *id123}
docA.AddCapabilityInvocation(&did.VerificationMethod{ID: *id123Method1})
resolveTime := time.Date(2010, 1, 1, 1, 1, 1, 0, time.UTC)
resolveMD := &resolver.ResolveMetadata{ResolveTime: &resolveTime}
- resolver.EXPECT().Resolve(*id123, resolveMD).Return(&docA, &resolver.DocumentMetadata{}, nil)
+ nutsResolver.EXPECT().Resolve(*id123, resolveMD).Return(&docA, &resolver.DocumentMetadata{}, nil)
docB := did.Document{ID: *id456, Controller: []did.DID{*id123}}
- docs, err := ResolveControllers(resolver, docB, resolveMD)
+ docs, err := ResolveControllers(nutsResolver, docB, resolveMD)
assert.NoError(t, err)
assert.Len(t, docs, 1)
assert.Equal(t, docA, docs[0],
@@ -184,32 +184,32 @@ func TestResolveControllers(t *testing.T) {
t.Run("docA is controller of docB and docA is deactivated", func(t *testing.T) {
ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
+ nutsResolver := types.NewMockDIDResolver(ctrl)
docA := did.Document{ID: *id123}
resolveTime := time.Date(2010, 1, 1, 1, 1, 1, 0, time.UTC)
resolveMD := &resolver.ResolveMetadata{ResolveTime: &resolveTime}
- resolver.EXPECT().Resolve(*id123, resolveMD).Return(&docA, &resolver.DocumentMetadata{}, nil)
+ nutsResolver.EXPECT().Resolve(*id123, resolveMD).Return(&docA, &resolver.DocumentMetadata{}, nil)
docB := did.Document{ID: *id456, Controller: []did.DID{*id123}}
- docs, err := ResolveControllers(resolver, docB, resolveMD)
+ docs, err := ResolveControllers(nutsResolver, docB, resolveMD)
assert.NoError(t, err)
assert.Len(t, docs, 0)
})
t.Run("docA and docB are both the controllers of docB", func(t *testing.T) {
ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
+ nutsResolver := types.NewMockDIDResolver(ctrl)
docA := did.Document{ID: *id123}
docA.AddCapabilityInvocation(&did.VerificationMethod{ID: *id123Method1})
- resolver.EXPECT().Resolve(*id123, gomock.Any()).Return(&docA, &resolver.DocumentMetadata{}, nil)
+ nutsResolver.EXPECT().Resolve(*id123, gomock.Any()).Return(&docA, &resolver.DocumentMetadata{}, nil)
docB := did.Document{ID: *id456, Controller: []did.DID{*id123, *id456}}
docB.AddCapabilityInvocation(&did.VerificationMethod{ID: *id456Method1})
- docs, err := ResolveControllers(resolver, docB, nil)
+ docs, err := ResolveControllers(nutsResolver, docB, nil)
assert.NoError(t, err)
assert.Len(t, docs, 2)
assert.Equal(t, []did.Document{docB, docA}, docs,
@@ -218,17 +218,17 @@ func TestResolveControllers(t *testing.T) {
t.Run("docA and docB are both the controllers of docB, resolve by source transaction", func(t *testing.T) {
ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
+ nutsResolver := types.NewMockDIDResolver(ctrl)
docA := did.Document{ID: *id123}
docA.AddCapabilityInvocation(&did.VerificationMethod{ID: *id123Method1})
// when we resolve by source TX, we will not find the other controller
- resolver.EXPECT().Resolve(*id123, gomock.Any()).Return(nil, nil, resolver.ErrNotFound)
+ nutsResolver.EXPECT().Resolve(*id123, gomock.Any()).Return(nil, nil, resolver.ErrNotFound)
docB := did.Document{ID: *id456, Controller: []did.DID{*id123, *id456}}
docB.AddCapabilityInvocation(&did.VerificationMethod{ID: *id456Method1})
- docs, err := ResolveControllers(resolver, docB, nil)
+ docs, err := ResolveControllers(nutsResolver, docB, nil)
assert.NoError(t, err)
assert.Len(t, docs, 1)
assert.Equal(t, []did.Document{docB}, docs,
@@ -237,11 +237,11 @@ func TestResolveControllers(t *testing.T) {
t.Run("docA, docB and docC are controllers of docA, docB is deactivated", func(t *testing.T) {
ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
+ nutsResolver := types.NewMockDIDResolver(ctrl)
// Doc B is deactivated
docBID, _ := did.ParseDID("did:nuts:B")
docB := did.Document{ID: *docBID}
- resolver.EXPECT().Resolve(docB.ID, gomock.Any()).Return(&docB, &resolver.DocumentMetadata{}, nil)
+ nutsResolver.EXPECT().Resolve(docB.ID, gomock.Any()).Return(&docB, &resolver.DocumentMetadata{}, nil)
// Doc C is active
docCID, _ := did.ParseDID("did:nuts:C")
@@ -249,7 +249,7 @@ func TestResolveControllers(t *testing.T) {
docCIDCapInv.Fragment = "cap-inv"
docC := did.Document{ID: *docCID}
docC.AddCapabilityInvocation(&did.VerificationMethod{ID: docCIDCapInv})
- resolver.EXPECT().Resolve(docC.ID, gomock.Any()).Return(&docC, &resolver.DocumentMetadata{}, nil)
+ nutsResolver.EXPECT().Resolve(docC.ID, gomock.Any()).Return(&docC, &resolver.DocumentMetadata{}, nil)
// Doc A is active
docAID, _ := did.ParseDID("did:nuts:A")
@@ -259,7 +259,7 @@ func TestResolveControllers(t *testing.T) {
docA.Controller = []did.DID{docA.ID, docB.ID, docC.ID}
docA.AddCapabilityInvocation(&did.VerificationMethod{ID: docAIDCapInv})
- docs, err := ResolveControllers(resolver, docA, nil)
+ docs, err := ResolveControllers(nutsResolver, docA, nil)
assert.NoError(t, err)
assert.Len(t, docs, 2)
assert.Contains(t, docs, docA, "expected docA to be resolved as controller of docA")
@@ -268,15 +268,15 @@ func TestResolveControllers(t *testing.T) {
t.Run("docA is controller of docB, docA has explicit self link in Controllers", func(t *testing.T) {
ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
+ nutsResolver := types.NewMockDIDResolver(ctrl)
docA := did.Document{ID: *id123, Controller: []did.DID{*id123}}
docA.AddCapabilityInvocation(&did.VerificationMethod{ID: *id123Method1})
- resolver.EXPECT().Resolve(*id123, gomock.Any()).Return(&docA, &resolver.DocumentMetadata{}, nil)
+ nutsResolver.EXPECT().Resolve(*id123, gomock.Any()).Return(&docA, &resolver.DocumentMetadata{}, nil)
docB := did.Document{ID: *id456, Controller: []did.DID{*id123}}
- docs, err := ResolveControllers(resolver, docB, nil)
+ docs, err := ResolveControllers(nutsResolver, docB, nil)
assert.NoError(t, err)
assert.Len(t, docs, 1)
assert.Equal(t, docA, docs[0],
@@ -285,12 +285,12 @@ func TestResolveControllers(t *testing.T) {
t.Run("ok - Resolve can not find the document", func(t *testing.T) {
ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
- resolver.EXPECT().Resolve(*id123, gomock.Any()).Return(nil, nil, resolver.ErrNotFound)
+ nutsResolver := types.NewMockDIDResolver(ctrl)
+ nutsResolver.EXPECT().Resolve(*id123, gomock.Any()).Return(nil, nil, resolver.ErrNotFound)
docB := did.Document{ID: *id456, Controller: []did.DID{*id123}}
- docs, err := ResolveControllers(resolver, docB, nil)
+ docs, err := ResolveControllers(nutsResolver, docB, nil)
require.NoError(t, err)
assert.Len(t, docs, 0)
})
diff --git a/vdr/didservice/resolvers.go b/vdr/didservice/resolvers.go
deleted file mode 100644
index 79d9d28592..0000000000
--- a/vdr/didservice/resolvers.go
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2022 Nuts community
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-// Package service contains DID Document related functionality that only matters to the current node.
-// All functionality here has zero relations to the network.
-package didservice
-
-import (
- "errors"
- "github.com/nuts-foundation/go-did/did"
- "github.com/nuts-foundation/nuts-node/vdr/resolver"
- "github.com/nuts-foundation/nuts-node/vdr/types"
- "sync"
-)
-
-var _ resolver.DIDResolver = &DIDResolverRouter{}
-
-// DIDResolverRouter is a DID resolver that can route to different DID resolvers based on the DID method
-type DIDResolverRouter struct {
- resolvers sync.Map
-}
-
-// Resolve looks up the right resolver for the given DID and delegates the resolution to it.
-// If no resolver is registered for the given DID method, ErrDIDMethodNotSupported is returned.
-func (r *DIDResolverRouter) Resolve(id did.DID, metadata *resolver.ResolveMetadata) (*did.Document, *resolver.DocumentMetadata, error) {
- method := id.Method
- resolver, registered := r.resolvers.Load(method)
- if !registered {
- return nil, nil, types.ErrDIDMethodNotSupported
- }
- return resolver.(resolver.DIDResolver).Resolve(id, metadata)
-}
-
-// Register registers a DID resolver for the given DID method.
-func (r *DIDResolverRouter) Register(method string, resolver resolver.DIDResolver) {
- r.resolvers.Store(method, resolver)
-}
-
-// IsFunctionalResolveError returns true if the given error indicates the DID or service not being found or invalid,
-// e.g. because it is deactivated, referenced too deeply, etc.
-func IsFunctionalResolveError(target error) bool {
- return errors.Is(target, resolver.ErrNotFound) ||
- errors.Is(target, resolver.ErrDeactivated) ||
- errors.Is(target, resolver.ErrServiceNotFound) ||
- errors.Is(target, resolver.ErrNoActiveController) ||
- errors.Is(target, resolver.ErrServiceReferenceToDeep) ||
- errors.Is(target, did.InvalidDIDErr) ||
- errors.As(target, new(resolver.ServiceQueryError))
-}
diff --git a/vdr/didservice/resolvers_test.go b/vdr/didservice/resolvers_test.go
deleted file mode 100644
index 87e067eb3f..0000000000
--- a/vdr/didservice/resolvers_test.go
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 2022 Nuts community
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package didservice
-
-import (
- "crypto/ecdsa"
- "crypto/elliptic"
- "crypto/rand"
- "errors"
- "fmt"
- ssi "github.com/nuts-foundation/go-did"
- "github.com/nuts-foundation/go-did/did"
- "github.com/nuts-foundation/nuts-node/crypto/hash"
- resolver2 "github.com/nuts-foundation/nuts-node/vdr/resolver"
- "github.com/nuts-foundation/nuts-node/vdr/types"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "go.uber.org/mock/gomock"
- "testing"
-)
-
-func TestServiceResolver_Resolve(t *testing.T) {
- meta := &resolver2.DocumentMetadata{Hash: hash.EmptyHash()}
-
- didA, _ := did.ParseDID("did:nuts:A")
- didB, _ := did.ParseDID("did:nuts:B")
-
- serviceID := ssi.MustParseURI(fmt.Sprintf("%s#1", didA.String()))
- docA := did.Document{
- Context: []ssi.URI{did.DIDContextV1URI()},
- ID: *didA,
- Service: []did.Service{{
- ID: serviceID,
- Type: "hello",
- ServiceEndpoint: "http://hello",
- }},
- }
- docB := did.Document{
- Context: []ssi.URI{did.DIDContextV1URI()},
- ID: *didA,
- Service: []did.Service{
- {
- Type: "simple",
- ServiceEndpoint: "http://world",
- },
- {
- Type: "cyclic-ref",
- ServiceEndpoint: didB.String() + "/serviceEndpoint?type=cyclic-ref",
- },
- {
- Type: "invalid-ref",
- ServiceEndpoint: didB.String() + "?type=invalid-ref",
- },
- {
- Type: "external",
- ServiceEndpoint: resolver2.MakeServiceReference(docA.ID, "hello").String(),
- },
- },
- }
-
- t.Run("ok", func(t *testing.T) {
- ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
-
- resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(&docB, meta, nil)
-
- actual, err := resolver2.DIDServiceResolver{Resolver: resolver}.Resolve(resolver2.MakeServiceReference(*didB, "simple"), resolver2.DefaultMaxServiceReferenceDepth)
-
- assert.NoError(t, err)
- assert.Equal(t, docB.Service[0], actual)
- })
- t.Run("ok - external", func(t *testing.T) {
- ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
-
- resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(&docB, meta, nil)
- resolver.EXPECT().Resolve(*didA, nil).MinTimes(1).Return(&docA, meta, nil)
-
- actual, err := resolver2.DIDServiceResolver{Resolver: resolver}.Resolve(resolver2.MakeServiceReference(*didB, "external"), resolver2.DefaultMaxServiceReferenceDepth)
-
- assert.NoError(t, err)
- assert.Equal(t, docA.Service[0], actual)
- })
- t.Run("error - cyclic reference (yields refs too deep)", func(t *testing.T) {
- ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
-
- resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(&docB, meta, nil)
-
- actual, err := resolver2.DIDServiceResolver{Resolver: resolver}.Resolve(resolver2.MakeServiceReference(*didB, "cyclic-ref"), resolver2.DefaultMaxServiceReferenceDepth)
-
- assert.EqualError(t, err, "service references are nested to deeply before resolving to a non-reference")
- assert.Empty(t, actual)
- })
- t.Run("error - invalid ref", func(t *testing.T) {
- ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
-
- resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(&docB, meta, nil)
-
- actual, err := resolver2.DIDServiceResolver{Resolver: resolver}.Resolve(resolver2.MakeServiceReference(*didB, "invalid-ref"), resolver2.DefaultMaxServiceReferenceDepth)
-
- assert.EqualError(t, err, "DID service query invalid: endpoint URI path must be /serviceEndpoint")
- assert.Empty(t, actual)
- })
- t.Run("error - service not found", func(t *testing.T) {
- ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
-
- resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(&docB, meta, nil)
-
- actual, err := resolver2.DIDServiceResolver{Resolver: resolver}.Resolve(resolver2.MakeServiceReference(*didB, "non-existent"), resolver2.DefaultMaxServiceReferenceDepth)
-
- assert.EqualError(t, err, "service not found in DID Document")
- assert.Empty(t, actual)
- })
- t.Run("error - DID not found", func(t *testing.T) {
- ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
-
- resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(nil, nil, resolver2.ErrNotFound)
-
- actual, err := resolver2.DIDServiceResolver{Resolver: resolver}.Resolve(resolver2.MakeServiceReference(*didB, "non-existent"), resolver2.DefaultMaxServiceReferenceDepth)
-
- assert.EqualError(t, err, "unable to find the DID document")
- assert.Empty(t, actual)
- })
-}
-
-func TestKeyResolver_ResolveKey(t *testing.T) {
- ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
- keyResolver := resolver2.DIDKeyResolver{Resolver: resolver}
-
- doc := newDidDoc()
- resolver.EXPECT().Resolve(doc.ID, gomock.Any()).AnyTimes().Return(&doc, nil, nil)
-
- t.Run("ok - it finds the key", func(t *testing.T) {
- keyId, key, err := keyResolver.ResolveKey(doc.ID, nil, types.AssertionMethod)
- require.NoError(t, err)
- assert.Equal(t, doc.VerificationMethod[0].ID.URI(), keyId)
- assert.NotNil(t, key)
- })
-
- t.Run("error - document not found", func(t *testing.T) {
- unknownDID := did.MustParseDID("did:example:123")
- resolver.EXPECT().Resolve(unknownDID, gomock.Any()).Return(nil, nil, resolver2.ErrNotFound)
- keyId, key, err := keyResolver.ResolveKey(unknownDID, nil, types.AssertionMethod)
- assert.EqualError(t, err, "unable to find the DID document")
- assert.Empty(t, keyId)
- assert.Nil(t, key)
- })
-
- t.Run("error - key not found", func(t *testing.T) {
- keyId, key, err := keyResolver.ResolveKey(did.MustParseDIDURL(doc.ID.String()), nil, types.CapabilityDelegation)
- assert.EqualError(t, err, "key not found in DID document")
- assert.Empty(t, keyId)
- assert.Nil(t, key)
- })
-
- t.Run("error - unknown relationship type", func(t *testing.T) {
- keyId, key, err := keyResolver.ResolveKey(doc.ID, nil, 1000)
- assert.EqualError(t, err, "unable to locate RelationType 1000")
- assert.Empty(t, keyId)
- assert.Nil(t, key)
- })
-}
-
-func newDidDoc() did.Document {
- privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
- id := did.MustParseDID("did:example:sakjsakldjsakld")
- keyID := id
- keyID.Fragment = "key-1"
- vm, _ := did.NewVerificationMethod(keyID, ssi.JsonWebKey2020, id, privateKey.Public())
- doc := did.Document{
- ID: id,
- }
- doc.AddAssertionMethod(vm)
- return doc
-}
-
-func TestKeyResolver_ResolveKeyByID(t *testing.T) {
- ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
- keyResolver := resolver2.DIDKeyResolver{Resolver: resolver}
- doc := newDidDoc()
- resolver.EXPECT().Resolve(doc.ID, gomock.Any()).AnyTimes().Return(&doc, nil, nil)
- keyID := doc.VerificationMethod[0].ID
-
- t.Run("ok - it finds the key", func(t *testing.T) {
- key, err := keyResolver.ResolveKeyByID(keyID.String(), nil, types.AssertionMethod)
- assert.NoError(t, err)
- assert.NotNil(t, key)
- })
-
- t.Run("error - invalid key ID", func(t *testing.T) {
- key, err := keyResolver.ResolveKeyByID("abcdef", nil, types.AssertionMethod)
- assert.EqualError(t, err, "invalid key ID (id=abcdef): invalid DID")
- assert.Nil(t, key)
- })
-
- t.Run("error - document not found", func(t *testing.T) {
- unknownDID := did.MustParseDIDURL("did:example:123")
- resolver.EXPECT().Resolve(unknownDID, gomock.Any()).Return(nil, nil, resolver2.ErrNotFound)
- key, err := keyResolver.ResolveKeyByID(unknownDID.String()+"#456", nil, types.AssertionMethod)
- assert.EqualError(t, err, "unable to find the DID document")
- assert.Nil(t, key)
- })
-
- t.Run("error - key not found", func(t *testing.T) {
- key, err := keyResolver.ResolveKeyByID(did.MustParseDIDURL(doc.ID.String()+"#123").String(), nil, types.AssertionMethod)
- assert.EqualError(t, err, "key not found in DID document")
- assert.Nil(t, key)
- })
-
- t.Run("error - unknown relationship type", func(t *testing.T) {
- key, err := keyResolver.ResolveKeyByID(keyID.String(), nil, 1000)
- assert.EqualError(t, err, "unable to locate RelationType 1000")
- assert.Nil(t, key)
- })
-}
-
-func TestIsFunctionalResolveError(t *testing.T) {
- assert.True(t, IsFunctionalResolveError(resolver2.ErrNotFound))
- assert.True(t, IsFunctionalResolveError(resolver2.ErrDeactivated))
- assert.True(t, IsFunctionalResolveError(resolver2.ErrServiceNotFound))
- assert.True(t, IsFunctionalResolveError(resolver2.ErrServiceReferenceToDeep))
- assert.True(t, IsFunctionalResolveError(resolver2.ErrNoActiveController))
- assert.True(t, IsFunctionalResolveError(did.InvalidDIDErr))
- assert.True(t, IsFunctionalResolveError(resolver2.ServiceQueryError{Err: errors.New("oops")}))
-
- assert.False(t, IsFunctionalResolveError(errors.New("some error")))
- assert.False(t, IsFunctionalResolveError(resolver2.ErrDuplicateService))
-}
-
-func TestDIDResolverRouter_Resolve(t *testing.T) {
- doc := newDidDoc()
- t.Run("ok, 1 resolver", func(t *testing.T) {
- ctrl := gomock.NewController(t)
- resolver := types.NewMockDIDResolver(ctrl)
- resolver.EXPECT().Resolve(doc.ID, gomock.Any()).Return(&doc, nil, nil)
- router := &DIDResolverRouter{}
- router.Register(doc.ID.Method, resolver)
-
- actual, _, err := router.Resolve(doc.ID, nil)
- assert.NoError(t, err)
- assert.Equal(t, &doc, actual)
- })
- t.Run("ok, 2 resolvers", func(t *testing.T) {
- ctrl := gomock.NewController(t)
- otherResolver := types.NewMockDIDResolver(ctrl)
- resolver := types.NewMockDIDResolver(ctrl)
- resolver.EXPECT().Resolve(doc.ID, gomock.Any()).Return(&doc, nil, nil)
- router := &DIDResolverRouter{}
- router.Register(doc.ID.Method, resolver)
- router.Register("test2", otherResolver)
-
- actual, _, err := router.Resolve(doc.ID, nil)
- assert.NoError(t, err)
- assert.Equal(t, &doc, actual)
- })
- t.Run("error - resolver not found", func(t *testing.T) {
- ctrl := gomock.NewController(t)
- otherResolver := types.NewMockDIDResolver(ctrl)
- router := &DIDResolverRouter{}
- router.Register("other", otherResolver)
-
- actual, _, err := router.Resolve(doc.ID, nil)
- assert.EqualError(t, err, "DID method not supported")
- assert.Nil(t, actual)
- })
-}
diff --git a/vdr/didservice/test.go b/vdr/didservice/test.go
deleted file mode 100644
index 121faeab3b..0000000000
--- a/vdr/didservice/test.go
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Nuts node
- * Copyright (C) 2021 Nuts community
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package didservice
-
-import (
- ssi "github.com/nuts-foundation/go-did"
- "github.com/nuts-foundation/go-did/did"
-)
-
-// marshal/unmarshal safe notation
-var testServiceA = did.Service{ID: ssi.MustParseURI("did:nuts:service:a"), ServiceEndpoint: []interface{}{"http://a"}}
-var testServiceB = did.Service{ID: ssi.MustParseURI("did:nuts:service:b"), ServiceEndpoint: []interface{}{"http://b"}}
diff --git a/vdr/didservice/util.go b/vdr/didservice/util.go
deleted file mode 100644
index 39cfd980e9..0000000000
--- a/vdr/didservice/util.go
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2022 Nuts community
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package didservice
-
-import (
- "github.com/nuts-foundation/go-did/did"
-)
-
-// GetDIDFromURL returns the DID from the given URL, stripping any query parameters, path segments and fragments.
-func GetDIDFromURL(didURL string) (did.DID, error) {
- parsed, err := did.ParseDIDURL(didURL)
- if err != nil {
- return did.DID{}, err
- }
- return parsed.WithoutURL(), nil
-}
-
-// IsDeactivated returns true if the DID.Document has already been deactivated
-func IsDeactivated(document did.Document) bool {
- return len(document.Controller) == 0 && len(document.CapabilityInvocation) == 0
-}
diff --git a/vdr/didservice/util_test.go b/vdr/didservice/util_test.go
deleted file mode 100644
index 3d6907496a..0000000000
--- a/vdr/didservice/util_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2022 Nuts community
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package didservice
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestGetDIDFromURL(t *testing.T) {
- t.Run("just it", func(t *testing.T) {
- actual, err := GetDIDFromURL("did:nuts:abc")
- assert.NoError(t, err)
- assert.Equal(t, "did:nuts:abc", actual.String())
- })
- t.Run("with path", func(t *testing.T) {
- actual, err := GetDIDFromURL("did:nuts:abc/serviceEndpoint")
- assert.NoError(t, err)
- assert.Equal(t, "did:nuts:abc", actual.String())
- })
- t.Run("with fragment", func(t *testing.T) {
- actual, err := GetDIDFromURL("did:nuts:abc#key-1")
- assert.NoError(t, err)
- assert.Equal(t, "did:nuts:abc", actual.String())
- })
- t.Run("with params", func(t *testing.T) {
- actual, err := GetDIDFromURL("did:nuts:abc?foo=bar")
- assert.NoError(t, err)
- assert.Equal(t, "did:nuts:abc", actual.String())
- })
- t.Run("invalid DID", func(t *testing.T) {
- _, err := GetDIDFromURL("https://example.com")
- assert.Error(t, err)
- })
-}
diff --git a/vdr/didservice/finder.go b/vdr/management/finder.go
similarity index 62%
rename from vdr/didservice/finder.go
rename to vdr/management/finder.go
index 46c9cdf7d0..3cc9b12d1d 100644
--- a/vdr/didservice/finder.go
+++ b/vdr/management/finder.go
@@ -1,34 +1,29 @@
-/*
- * Copyright (C) 2022 Nuts community
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- */
-
-package didservice
+package management
import (
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
- "github.com/nuts-foundation/nuts-node/vdr/types"
"strings"
"time"
)
+// DocFinder is the interface that groups all methods for finding DID documents based on search conditions
+type DocFinder interface {
+ Find(...Predicate) ([]did.Document, error)
+}
+
+// Predicate is an interface for abstracting search options on DID documents
+type Predicate interface {
+ // Match returns true if the given DID Document passes the predicate condition
+ Match(did.Document, resolver.DocumentMetadata) bool
+}
+
+// DocIterator is the function type for iterating over the all current DID Documents in the store
+type DocIterator func(doc did.Document, metadata resolver.DocumentMetadata) error
+
// ByServiceType returns a predicate that matches on service type
// it only matches on DID Documents with a concrete endpoint (not starting with "did")
-func ByServiceType(serviceType string) types.Predicate {
+func ByServiceType(serviceType string) Predicate {
return servicePredicate{serviceType: serviceType}
}
@@ -49,7 +44,7 @@ func (s servicePredicate) Match(document did.Document, _ resolver.DocumentMetada
}
// ValidAt returns a predicate that matches on validity period.
-func ValidAt(at time.Time) types.Predicate {
+func ValidAt(at time.Time) Predicate {
return validAtPredicate{validAt: at}
}
@@ -72,7 +67,7 @@ func (v validAtPredicate) Match(_ did.Document, metadata resolver.DocumentMetada
}
// IsActive returns a predicate that matches DID Documents that are not deactivated.
-func IsActive() types.Predicate {
+func IsActive() Predicate {
return deactivatedPredicate{deactivated: false}
}
diff --git a/vdr/didservice/finder_test.go b/vdr/management/finder_test.go
similarity index 72%
rename from vdr/didservice/finder_test.go
rename to vdr/management/finder_test.go
index 5899aa62bb..d365451177 100644
--- a/vdr/didservice/finder_test.go
+++ b/vdr/management/finder_test.go
@@ -1,29 +1,11 @@
-/*
- * Copyright (C) 2022 Nuts community
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package didservice
+package management
import (
+ "github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
+ "github.com/stretchr/testify/assert"
"testing"
"time"
-
- "github.com/nuts-foundation/go-did/did"
- "github.com/stretchr/testify/assert"
)
func TestIsActive(t *testing.T) {
diff --git a/vdr/resolver/did.go b/vdr/resolver/did.go
index cc1ccf0d01..eec2a7025c 100644
--- a/vdr/resolver/did.go
+++ b/vdr/resolver/did.go
@@ -4,6 +4,7 @@ import (
"errors"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/crypto/hash"
+ "sync"
"time"
)
@@ -18,6 +19,9 @@ type DIDResolver interface {
Resolve(id did.DID, metadata *ResolveMetadata) (*did.Document, *DocumentMetadata, error)
}
+// ErrDIDMethodNotSupported is returned when a DID method is not supported by the DID resolver
+var ErrDIDMethodNotSupported = errors.New("DID method not supported")
+
// ErrDIDNotManagedByThisNode is returned when an operation needs the private key and if is not found on this host
var ErrDIDNotManagedByThisNode = errors.New("DID document not managed by this node")
@@ -94,3 +98,52 @@ type ResolveMetadata struct {
// Allow DIDs which are deactivated
AllowDeactivated bool
}
+
+var _ DIDResolver = &DIDResolverRouter{}
+
+// DIDResolverRouter is a DID resolver that can route to different DID resolvers based on the DID method
+type DIDResolverRouter struct {
+ resolvers sync.Map
+}
+
+// Resolve looks up the right resolver for the given DID and delegates the resolution to it.
+// If no resolver is registered for the given DID method, ErrDIDMethodNotSupported is returned.
+func (r *DIDResolverRouter) Resolve(id did.DID, metadata *ResolveMetadata) (*did.Document, *DocumentMetadata, error) {
+ method := id.Method
+ didResolver, registered := r.resolvers.Load(method)
+ if !registered {
+ return nil, nil, ErrDIDMethodNotSupported
+ }
+ return didResolver.(DIDResolver).Resolve(id, metadata)
+}
+
+// Register registers a DID resolver for the given DID method.
+func (r *DIDResolverRouter) Register(method string, resolver DIDResolver) {
+ r.resolvers.Store(method, resolver)
+}
+
+// IsFunctionalResolveError returns true if the given error indicates the DID or service not being found or invalid,
+// e.g. because it is deactivated, referenced too deeply, etc.
+func IsFunctionalResolveError(target error) bool {
+ return errors.Is(target, ErrNotFound) ||
+ errors.Is(target, ErrDeactivated) ||
+ errors.Is(target, ErrServiceNotFound) ||
+ errors.Is(target, ErrNoActiveController) ||
+ errors.Is(target, ErrServiceReferenceToDeep) ||
+ errors.Is(target, did.InvalidDIDErr) ||
+ errors.As(target, new(ServiceQueryError))
+}
+
+// GetDIDFromURL returns the DID from the given URL, stripping any query parameters, path segments and fragments.
+func GetDIDFromURL(didURL string) (did.DID, error) {
+ parsed, err := did.ParseDIDURL(didURL)
+ if err != nil {
+ return did.DID{}, err
+ }
+ return parsed.WithoutURL(), nil
+}
+
+// IsDeactivated returns true if the DID.Document has already been deactivated
+func IsDeactivated(document did.Document) bool {
+ return len(document.Controller) == 0 && len(document.CapabilityInvocation) == 0
+}
diff --git a/vdr/resolver/did_test.go b/vdr/resolver/did_test.go
index d5c96588ff..5e026971a0 100644
--- a/vdr/resolver/did_test.go
+++ b/vdr/resolver/did_test.go
@@ -1,8 +1,16 @@
package resolver
import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "errors"
+ "github.com/nuts-foundation/go-did"
+ "github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/crypto/hash"
+ "github.com/nuts-foundation/nuts-node/vdr/types"
"github.com/stretchr/testify/assert"
+ "go.uber.org/mock/gomock"
"io"
"reflect"
"testing"
@@ -68,3 +76,94 @@ func Test_deactivatedError_Is(t *testing.T) {
assert.ErrorIs(t, ErrNoActiveController, ErrDeactivated)
assert.NotErrorIs(t, io.EOF, ErrDeactivated)
}
+
+func newDidDoc() did.Document {
+ privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ id := did.MustParseDID("did:example:sakjsakldjsakld")
+ keyID := id
+ keyID.Fragment = "key-1"
+ vm, _ := did.NewVerificationMethod(keyID, ssi.JsonWebKey2020, id, privateKey.Public())
+ doc := did.Document{
+ ID: id,
+ }
+ doc.AddAssertionMethod(vm)
+ return doc
+}
+
+func TestDIDResolverRouter_Resolve(t *testing.T) {
+ doc := newDidDoc()
+ t.Run("ok, 1 resolver", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ resolver := types.NewMockDIDResolver(ctrl)
+ resolver.EXPECT().Resolve(doc.ID, gomock.Any()).Return(&doc, nil, nil)
+ router := &DIDResolverRouter{}
+ router.Register(doc.ID.Method, resolver)
+
+ actual, _, err := router.Resolve(doc.ID, nil)
+ assert.NoError(t, err)
+ assert.Equal(t, &doc, actual)
+ })
+ t.Run("ok, 2 resolvers", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ otherResolver := types.NewMockDIDResolver(ctrl)
+ resolver := types.NewMockDIDResolver(ctrl)
+ resolver.EXPECT().Resolve(doc.ID, gomock.Any()).Return(&doc, nil, nil)
+ router := &DIDResolverRouter{}
+ router.Register(doc.ID.Method, resolver)
+ router.Register("test2", otherResolver)
+
+ actual, _, err := router.Resolve(doc.ID, nil)
+ assert.NoError(t, err)
+ assert.Equal(t, &doc, actual)
+ })
+ t.Run("error - resolver not found", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ otherResolver := types.NewMockDIDResolver(ctrl)
+ router := &DIDResolverRouter{}
+ router.Register("other", otherResolver)
+
+ actual, _, err := router.Resolve(doc.ID, nil)
+ assert.EqualError(t, err, "DID method not supported")
+ assert.Nil(t, actual)
+ })
+}
+
+func TestIsFunctionalResolveError(t *testing.T) {
+ assert.True(t, IsFunctionalResolveError(ErrNotFound))
+ assert.True(t, IsFunctionalResolveError(ErrDeactivated))
+ assert.True(t, IsFunctionalResolveError(ErrServiceNotFound))
+ assert.True(t, IsFunctionalResolveError(ErrServiceReferenceToDeep))
+ assert.True(t, IsFunctionalResolveError(ErrNoActiveController))
+ assert.True(t, IsFunctionalResolveError(did.InvalidDIDErr))
+ assert.True(t, IsFunctionalResolveError(ServiceQueryError{Err: errors.New("oops")}))
+
+ assert.False(t, IsFunctionalResolveError(errors.New("some error")))
+ assert.False(t, IsFunctionalResolveError(ErrDuplicateService))
+}
+
+func TestGetDIDFromURL(t *testing.T) {
+ t.Run("just it", func(t *testing.T) {
+ actual, err := GetDIDFromURL("did:nuts:abc")
+ assert.NoError(t, err)
+ assert.Equal(t, "did:nuts:abc", actual.String())
+ })
+ t.Run("with path", func(t *testing.T) {
+ actual, err := GetDIDFromURL("did:nuts:abc/serviceEndpoint")
+ assert.NoError(t, err)
+ assert.Equal(t, "did:nuts:abc", actual.String())
+ })
+ t.Run("with fragment", func(t *testing.T) {
+ actual, err := GetDIDFromURL("did:nuts:abc#key-1")
+ assert.NoError(t, err)
+ assert.Equal(t, "did:nuts:abc", actual.String())
+ })
+ t.Run("with params", func(t *testing.T) {
+ actual, err := GetDIDFromURL("did:nuts:abc?foo=bar")
+ assert.NoError(t, err)
+ assert.Equal(t, "did:nuts:abc", actual.String())
+ })
+ t.Run("invalid DID", func(t *testing.T) {
+ _, err := GetDIDFromURL("https://example.com")
+ assert.Error(t, err)
+ })
+}
diff --git a/vdr/resolver/key.go b/vdr/resolver/key.go
index 9fcaab40d7..dfed19d4cc 100644
--- a/vdr/resolver/key.go
+++ b/vdr/resolver/key.go
@@ -7,8 +7,6 @@ import (
"github.com/nuts-foundation/go-did"
"github.com/nuts-foundation/go-did/did"
"github.com/nuts-foundation/nuts-node/crypto/hash"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
- "github.com/nuts-foundation/nuts-node/vdr/types"
"time"
)
@@ -16,7 +14,7 @@ import (
var ErrKeyNotFound = errors.New("key not found in DID document")
// NutsSigningKeyType defines the verification method relationship type for signing keys in Nuts DID Documents.
-const NutsSigningKeyType = types.AssertionMethod
+const NutsSigningKeyType = AssertionMethod
// KeyResolver is the interface for resolving keys.
// This can be used for checking if a signing key is valid at a point in time or to just find a valid key for signing.
@@ -24,11 +22,11 @@ type KeyResolver interface {
// ResolveKeyByID looks up a specific key of the given RelationType and returns it as crypto.PublicKey.
// If multiple keys are valid, the first one is returned.
// An ErrKeyNotFound is returned when no key (of the specified type) is found.
- ResolveKeyByID(keyID string, validAt *time.Time, relationType types.RelationType) (crypto.PublicKey, error)
+ ResolveKeyByID(keyID string, validAt *time.Time, relationType RelationType) (crypto.PublicKey, error)
// ResolveKey looks for a valid key of the given RelationType for the given DID, and returns its ID and the key itself.
// If multiple keys are valid, the first one is returned.
// An ErrKeyNotFound is returned when no key (of the specified type) is found.
- ResolveKey(id did.DID, validAt *time.Time, relationType types.RelationType) (ssi.URI, crypto.PublicKey, error)
+ ResolveKey(id did.DID, validAt *time.Time, relationType RelationType) (ssi.URI, crypto.PublicKey, error)
}
// NutsKeyResolver is the interface for resolving keys from Nuts DID Documents,
@@ -48,8 +46,8 @@ type DIDKeyResolver struct {
Resolver DIDResolver
}
-func (r DIDKeyResolver) ResolveKeyByID(keyID string, validAt *time.Time, relationType types.RelationType) (crypto.PublicKey, error) {
- holder, err := didservice.GetDIDFromURL(keyID)
+func (r DIDKeyResolver) ResolveKeyByID(keyID string, validAt *time.Time, relationType RelationType) (crypto.PublicKey, error) {
+ holder, err := GetDIDFromURL(keyID)
if err != nil {
return nil, fmt.Errorf("invalid key ID (id=%s): %w", keyID, err)
}
@@ -71,7 +69,7 @@ func (r DIDKeyResolver) ResolveKeyByID(keyID string, validAt *time.Time, relatio
return nil, ErrKeyNotFound
}
-func (r DIDKeyResolver) ResolveKey(id did.DID, validAt *time.Time, relationType types.RelationType) (ssi.URI, crypto.PublicKey, error) {
+func (r DIDKeyResolver) ResolveKey(id did.DID, validAt *time.Time, relationType RelationType) (ssi.URI, crypto.PublicKey, error) {
doc, _, err := r.Resolver.Resolve(id, &ResolveMetadata{
ResolveTime: validAt,
})
@@ -92,19 +90,31 @@ func (r DIDKeyResolver) ResolveKey(id did.DID, validAt *time.Time, relationType
return keys[0].ID.URI(), publicKey, nil
}
-func resolveRelationships(doc *did.Document, relationType types.RelationType) (relationships did.VerificationRelationships, err error) {
+func resolveRelationships(doc *did.Document, relationType RelationType) (relationships did.VerificationRelationships, err error) {
switch relationType {
- case types.Authentication:
+ case Authentication:
return doc.Authentication, nil
- case types.AssertionMethod:
+ case AssertionMethod:
return doc.AssertionMethod, nil
- case types.KeyAgreement:
+ case KeyAgreement:
return doc.KeyAgreement, nil
- case types.CapabilityInvocation:
+ case CapabilityInvocation:
return doc.CapabilityInvocation, nil
- case types.CapabilityDelegation:
+ case CapabilityDelegation:
return doc.CapabilityDelegation, nil
default:
return nil, fmt.Errorf("unable to locate RelationType %v", relationType)
}
}
+
+// RelationType is the type that contains the different possible relationships between a DID Document and a VerificationMethod
+// They are defined in the DID spec: https://www.w3.org/TR/did-core/#verification-relationships
+type RelationType uint
+
+const (
+ Authentication RelationType = iota
+ AssertionMethod RelationType = iota
+ KeyAgreement RelationType = iota
+ CapabilityInvocation RelationType = iota
+ CapabilityDelegation RelationType = iota
+)
diff --git a/vdr/resolver/key_test.go b/vdr/resolver/key_test.go
index 66dd69b0d3..b9293feb98 100644
--- a/vdr/resolver/key_test.go
+++ b/vdr/resolver/key_test.go
@@ -1,38 +1,90 @@
package resolver
import (
+ "github.com/nuts-foundation/go-did/did"
+ "github.com/nuts-foundation/nuts-node/vdr/types"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "go.uber.org/mock/gomock"
"testing"
)
-func TestKeyUsage_Is(t *testing.T) {
- types := []DIDKeyFlags{AssertionMethodUsage, AuthenticationUsage, CapabilityDelegationUsage, CapabilityInvocationUsage, KeyAgreementUsage}
- t.Run("one usage", func(t *testing.T) {
- for _, usage := range types {
- for _, other := range types {
- if usage == other {
- assert.True(t, usage.Is(other))
- assert.True(t, other.Is(usage)) // assert symmetry
- } else {
- assert.False(t, usage.Is(other))
- assert.False(t, other.Is(usage)) // assert symmetry
- }
- }
- }
- })
- t.Run("multiple usage", func(t *testing.T) {
- value := AssertionMethodUsage | CapabilityDelegationUsage | KeyAgreementUsage
- for _, other := range types {
- switch other {
- case AssertionMethodUsage:
- fallthrough
- case CapabilityDelegationUsage:
- fallthrough
- case KeyAgreementUsage:
- assert.True(t, value.Is(other))
- default:
- assert.False(t, value.Is(other))
- }
- }
+func TestKeyResolver_ResolveKey(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ resolver := types.NewMockDIDResolver(ctrl)
+ keyResolver := DIDKeyResolver{Resolver: resolver}
+
+ doc := newDidDoc()
+ resolver.EXPECT().Resolve(doc.ID, gomock.Any()).AnyTimes().Return(&doc, nil, nil)
+
+ t.Run("ok - it finds the key", func(t *testing.T) {
+ keyId, key, err := keyResolver.ResolveKey(doc.ID, nil, AssertionMethod)
+ require.NoError(t, err)
+ assert.Equal(t, doc.VerificationMethod[0].ID.URI(), keyId)
+ assert.NotNil(t, key)
+ })
+
+ t.Run("error - document not found", func(t *testing.T) {
+ unknownDID := did.MustParseDID("did:example:123")
+ resolver.EXPECT().Resolve(unknownDID, gomock.Any()).Return(nil, nil, ErrNotFound)
+ keyId, key, err := keyResolver.ResolveKey(unknownDID, nil, AssertionMethod)
+ assert.EqualError(t, err, "unable to find the DID document")
+ assert.Empty(t, keyId)
+ assert.Nil(t, key)
+ })
+
+ t.Run("error - key not found", func(t *testing.T) {
+ keyId, key, err := keyResolver.ResolveKey(did.MustParseDIDURL(doc.ID.String()), nil, CapabilityDelegation)
+ assert.EqualError(t, err, "key not found in DID document")
+ assert.Empty(t, keyId)
+ assert.Nil(t, key)
+ })
+
+ t.Run("error - unknown relationship type", func(t *testing.T) {
+ keyId, key, err := keyResolver.ResolveKey(doc.ID, nil, 1000)
+ assert.EqualError(t, err, "unable to locate RelationType 1000")
+ assert.Empty(t, keyId)
+ assert.Nil(t, key)
+ })
+}
+
+func TestKeyResolver_ResolveKeyByID(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ resolver := types.NewMockDIDResolver(ctrl)
+ keyResolver := DIDKeyResolver{Resolver: resolver}
+ doc := newDidDoc()
+ resolver.EXPECT().Resolve(doc.ID, gomock.Any()).AnyTimes().Return(&doc, nil, nil)
+ keyID := doc.VerificationMethod[0].ID
+
+ t.Run("ok - it finds the key", func(t *testing.T) {
+ key, err := keyResolver.ResolveKeyByID(keyID.String(), nil, AssertionMethod)
+ assert.NoError(t, err)
+ assert.NotNil(t, key)
+ })
+
+ t.Run("error - invalid key ID", func(t *testing.T) {
+ key, err := keyResolver.ResolveKeyByID("abcdef", nil, AssertionMethod)
+ assert.EqualError(t, err, "invalid key ID (id=abcdef): invalid DID")
+ assert.Nil(t, key)
+ })
+
+ t.Run("error - document not found", func(t *testing.T) {
+ unknownDID := did.MustParseDIDURL("did:example:123")
+ resolver.EXPECT().Resolve(unknownDID, gomock.Any()).Return(nil, nil, ErrNotFound)
+ key, err := keyResolver.ResolveKeyByID(unknownDID.String()+"#456", nil, AssertionMethod)
+ assert.EqualError(t, err, "unable to find the DID document")
+ assert.Nil(t, key)
+ })
+
+ t.Run("error - key not found", func(t *testing.T) {
+ key, err := keyResolver.ResolveKeyByID(did.MustParseDIDURL(doc.ID.String()+"#123").String(), nil, AssertionMethod)
+ assert.EqualError(t, err, "key not found in DID document")
+ assert.Nil(t, key)
+ })
+
+ t.Run("error - unknown relationship type", func(t *testing.T) {
+ key, err := keyResolver.ResolveKeyByID(keyID.String(), nil, 1000)
+ assert.EqualError(t, err, "unable to locate RelationType 1000")
+ assert.Nil(t, key)
})
}
diff --git a/vdr/resolver/service.go b/vdr/resolver/service.go
index 2ca809de5c..f3e386b38f 100644
--- a/vdr/resolver/service.go
+++ b/vdr/resolver/service.go
@@ -5,7 +5,6 @@ import (
"fmt"
"github.com/nuts-foundation/go-did"
"github.com/nuts-foundation/go-did/did"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
"strings"
)
@@ -49,7 +48,7 @@ func (s DIDServiceResolver) ResolveEx(endpoint ssi.URI, depth int, maxDepth int,
return did.Service{}, ErrServiceReferenceToDeep
}
- referencedDID, err := didservice.GetDIDFromURL(endpoint.String())
+ referencedDID, err := GetDIDFromURL(endpoint.String())
if err != nil {
// Shouldn't happen, because only DID URLs are passed?
return did.Service{}, err
diff --git a/vdr/resolver/service_test.go b/vdr/resolver/service_test.go
index 7e9a487b98..8fb7d424b4 100644
--- a/vdr/resolver/service_test.go
+++ b/vdr/resolver/service_test.go
@@ -1,9 +1,13 @@
package resolver
import (
+ "fmt"
ssi "github.com/nuts-foundation/go-did"
"github.com/nuts-foundation/go-did/did"
+ "github.com/nuts-foundation/nuts-node/crypto/hash"
+ "github.com/nuts-foundation/nuts-node/vdr/types"
"github.com/stretchr/testify/assert"
+ "go.uber.org/mock/gomock"
"testing"
)
@@ -52,3 +56,111 @@ func Test_ValidateServiceReference(t *testing.T) {
assert.ErrorContains(t, err, "endpoint URI with query parameter other than type")
})
}
+
+func TestServiceResolver_Resolve(t *testing.T) {
+ meta := &DocumentMetadata{Hash: hash.EmptyHash()}
+
+ didA, _ := did.ParseDID("did:nuts:A")
+ didB, _ := did.ParseDID("did:nuts:B")
+
+ serviceID := ssi.MustParseURI(fmt.Sprintf("%s#1", didA.String()))
+ docA := did.Document{
+ Context: []ssi.URI{did.DIDContextV1URI()},
+ ID: *didA,
+ Service: []did.Service{{
+ ID: serviceID,
+ Type: "hello",
+ ServiceEndpoint: "http://hello",
+ }},
+ }
+ docB := did.Document{
+ Context: []ssi.URI{did.DIDContextV1URI()},
+ ID: *didA,
+ Service: []did.Service{
+ {
+ Type: "simple",
+ ServiceEndpoint: "http://world",
+ },
+ {
+ Type: "cyclic-ref",
+ ServiceEndpoint: didB.String() + "/serviceEndpoint?type=cyclic-ref",
+ },
+ {
+ Type: "invalid-ref",
+ ServiceEndpoint: didB.String() + "?type=invalid-ref",
+ },
+ {
+ Type: "external",
+ ServiceEndpoint: MakeServiceReference(docA.ID, "hello").String(),
+ },
+ },
+ }
+
+ t.Run("ok", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ resolver := types.NewMockDIDResolver(ctrl)
+
+ resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(&docB, meta, nil)
+
+ actual, err := DIDServiceResolver{Resolver: resolver}.Resolve(MakeServiceReference(*didB, "simple"), DefaultMaxServiceReferenceDepth)
+
+ assert.NoError(t, err)
+ assert.Equal(t, docB.Service[0], actual)
+ })
+ t.Run("ok - external", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ resolver := types.NewMockDIDResolver(ctrl)
+
+ resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(&docB, meta, nil)
+ resolver.EXPECT().Resolve(*didA, nil).MinTimes(1).Return(&docA, meta, nil)
+
+ actual, err := DIDServiceResolver{Resolver: resolver}.Resolve(MakeServiceReference(*didB, "external"), DefaultMaxServiceReferenceDepth)
+
+ assert.NoError(t, err)
+ assert.Equal(t, docA.Service[0], actual)
+ })
+ t.Run("error - cyclic reference (yields refs too deep)", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ resolver := types.NewMockDIDResolver(ctrl)
+
+ resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(&docB, meta, nil)
+
+ actual, err := DIDServiceResolver{Resolver: resolver}.Resolve(MakeServiceReference(*didB, "cyclic-ref"), DefaultMaxServiceReferenceDepth)
+
+ assert.EqualError(t, err, "service references are nested to deeply before resolving to a non-reference")
+ assert.Empty(t, actual)
+ })
+ t.Run("error - invalid ref", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ resolver := types.NewMockDIDResolver(ctrl)
+
+ resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(&docB, meta, nil)
+
+ actual, err := DIDServiceResolver{Resolver: resolver}.Resolve(MakeServiceReference(*didB, "invalid-ref"), DefaultMaxServiceReferenceDepth)
+
+ assert.EqualError(t, err, "DID service query invalid: endpoint URI path must be /serviceEndpoint")
+ assert.Empty(t, actual)
+ })
+ t.Run("error - service not found", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ resolver := types.NewMockDIDResolver(ctrl)
+
+ resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(&docB, meta, nil)
+
+ actual, err := DIDServiceResolver{Resolver: resolver}.Resolve(MakeServiceReference(*didB, "non-existent"), DefaultMaxServiceReferenceDepth)
+
+ assert.EqualError(t, err, "service not found in DID Document")
+ assert.Empty(t, actual)
+ })
+ t.Run("error - DID not found", func(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ resolver := types.NewMockDIDResolver(ctrl)
+
+ resolver.EXPECT().Resolve(*didB, nil).MinTimes(1).Return(nil, nil, ErrNotFound)
+
+ actual, err := DIDServiceResolver{Resolver: resolver}.Resolve(MakeServiceReference(*didB, "non-existent"), DefaultMaxServiceReferenceDepth)
+
+ assert.EqualError(t, err, "unable to find the DID document")
+ assert.Empty(t, actual)
+ })
+}
diff --git a/vdr/types/interface.go b/vdr/types/interface.go
index 516734b9b6..2b35cb7e63 100644
--- a/vdr/types/interface.go
+++ b/vdr/types/interface.go
@@ -20,24 +20,12 @@ package types
import (
"context"
- "errors"
"github.com/nuts-foundation/go-did/did"
crypto2 "github.com/nuts-foundation/nuts-node/crypto"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"net/url"
)
-// Predicate is an interface for abstracting search options on DID documents
-type Predicate interface {
- // Match returns true if the given DID Document passes the predicate condition
- Match(did.Document, resolver.DocumentMetadata) bool
-}
-
-// DocFinder is the interface that groups all methods for finding DID documents based on search conditions
-type DocFinder interface {
- Find(...Predicate) ([]did.Document, error)
-}
-
// DocCreator is the interface that wraps the Create method
type DocCreator interface {
// Create creates a new DID document and returns it.
@@ -62,9 +50,6 @@ type DocUpdater interface {
Update(ctx context.Context, id did.DID, next did.Document) error
}
-// DocIterator is the function type for iterating over the all current DID Documents in the store
-type DocIterator func(doc did.Document, metadata resolver.DocumentMetadata) error
-
// VDR defines the public end facing methods for the Verifiable Data Registry.
type VDR interface {
DocumentOwner
@@ -115,18 +100,3 @@ type DocManipulator interface {
// It returns an ErrDIDNotManagedByThisNode if the DID document is not managed by this node.
AddVerificationMethod(ctx context.Context, id did.DID, keyUsage DIDKeyFlags) (*did.VerificationMethod, error)
}
-
-// ErrDIDMethodNotSupported is returned when a DID method is not supported by the DID resolver
-var ErrDIDMethodNotSupported = errors.New("DID method not supported")
-
-// RelationType is the type that contains the different possible relationships between a DID Document and a VerificationMethod
-// They are defined in the DID spec: https://www.w3.org/TR/did-core/#verification-relationships
-type RelationType uint
-
-const (
- Authentication RelationType = iota
- AssertionMethod RelationType = iota
- KeyAgreement RelationType = iota
- CapabilityInvocation RelationType = iota
- CapabilityDelegation RelationType = iota
-)
diff --git a/vdr/types/key.go b/vdr/types/key.go
deleted file mode 100644
index ab1254f4c2..0000000000
--- a/vdr/types/key.go
+++ /dev/null
@@ -1 +0,0 @@
-package types
diff --git a/vdr/types/management_test.go b/vdr/types/management_test.go
new file mode 100644
index 0000000000..21b7b8e37e
--- /dev/null
+++ b/vdr/types/management_test.go
@@ -0,0 +1,38 @@
+package types
+
+import (
+ "github.com/stretchr/testify/assert"
+ "testing"
+)
+
+func TestKeyUsage_Is(t *testing.T) {
+ types := []DIDKeyFlags{AssertionMethodUsage, AuthenticationUsage, CapabilityDelegationUsage, CapabilityInvocationUsage, KeyAgreementUsage}
+ t.Run("one usage", func(t *testing.T) {
+ for _, usage := range types {
+ for _, other := range types {
+ if usage == other {
+ assert.True(t, usage.Is(other))
+ assert.True(t, other.Is(usage)) // assert symmetry
+ } else {
+ assert.False(t, usage.Is(other))
+ assert.False(t, other.Is(usage)) // assert symmetry
+ }
+ }
+ }
+ })
+ t.Run("multiple usage", func(t *testing.T) {
+ value := AssertionMethodUsage | CapabilityDelegationUsage | KeyAgreementUsage
+ for _, other := range types {
+ switch other {
+ case AssertionMethodUsage:
+ fallthrough
+ case CapabilityDelegationUsage:
+ fallthrough
+ case KeyAgreementUsage:
+ assert.True(t, value.Is(other))
+ default:
+ assert.False(t, value.Is(other))
+ }
+ }
+ })
+}
diff --git a/vdr/types/mock.go b/vdr/types/mock.go
index af42fbe0be..d9ed3dd7b2 100644
--- a/vdr/types/mock.go
+++ b/vdr/types/mock.go
@@ -11,6 +11,7 @@ package types
import (
context "context"
crypto "crypto"
+ "github.com/nuts-foundation/nuts-node/vdr/management"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
url "net/url"
reflect "reflect"
@@ -123,7 +124,7 @@ func (m *MockDocFinder) EXPECT() *MockDocFinderMockRecorder {
}
// Find mocks base method.
-func (m *MockDocFinder) Find(arg0 ...Predicate) ([]did.Document, error) {
+func (m *MockDocFinder) Find(arg0 ...management.Predicate) ([]did.Document, error) {
m.ctrl.T.Helper()
varargs := []any{}
for _, a := range arg0 {
@@ -278,7 +279,7 @@ func (m *MockKeyResolver) EXPECT() *MockKeyResolverMockRecorder {
}
// ResolveKey mocks base method.
-func (m *MockKeyResolver) ResolveKey(id did.DID, validAt *time.Time, relationType RelationType) (ssi.URI, crypto.PublicKey, error) {
+func (m *MockKeyResolver) ResolveKey(id did.DID, validAt *time.Time, relationType resolver.RelationType) (ssi.URI, crypto.PublicKey, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ResolveKey", id, validAt, relationType)
ret0, _ := ret[0].(ssi.URI)
@@ -294,7 +295,7 @@ func (mr *MockKeyResolverMockRecorder) ResolveKey(id, validAt, relationType any)
}
// ResolveKeyByID mocks base method.
-func (m *MockKeyResolver) ResolveKeyByID(keyID string, validAt *time.Time, relationType RelationType) (crypto.PublicKey, error) {
+func (m *MockKeyResolver) ResolveKeyByID(keyID string, validAt *time.Time, relationType resolver.RelationType) (crypto.PublicKey, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ResolveKeyByID", keyID, validAt, relationType)
ret0, _ := ret[0].(crypto.PublicKey)
diff --git a/vdr/vdr.go b/vdr/vdr.go
index adcf0a3517..a64dde54ad 100644
--- a/vdr/vdr.go
+++ b/vdr/vdr.go
@@ -40,9 +40,9 @@ import (
"github.com/nuts-foundation/nuts-node/vdr/didjwk"
"github.com/nuts-foundation/nuts-node/vdr/didnuts"
didnutsStore "github.com/nuts-foundation/nuts-node/vdr/didnuts/didstore"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
"github.com/nuts-foundation/nuts-node/vdr/didweb"
"github.com/nuts-foundation/nuts-node/vdr/log"
+ "github.com/nuts-foundation/nuts-node/vdr/management"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"github.com/nuts-foundation/nuts-node/vdr/types"
"net/url"
@@ -63,7 +63,7 @@ type VDR struct {
network network.Transactions
networkAmbassador didnuts.Ambassador
didDocCreator types.DocCreator
- didResolver *didservice.DIDResolverRouter
+ didResolver *resolver.DIDResolverRouter
serviceResolver resolver.ServiceResolver
documentOwner types.DocumentOwner
keyStore crypto.KeyStore
@@ -115,7 +115,7 @@ func (r *VDR) Resolver() resolver.DIDResolver {
// NewVDR creates a new VDR with provided params
func NewVDR(cryptoClient crypto.KeyStore, networkClient network.Transactions,
didStore didnutsStore.Store, eventManager events.Event) *VDR {
- didResolver := &didservice.DIDResolverRouter{}
+ didResolver := &resolver.DIDResolverRouter{}
return &VDR{
network: networkClient,
eventManager: eventManager,
@@ -191,7 +191,7 @@ func (r *VDR) ListOwned(ctx context.Context) ([]did.DID, error) {
// newOwnConflictedDocIterator accepts two counters and returns a new DocIterator that counts the total number of
// conflicted documents, both total and owned by this node.
-func (r *VDR) newOwnConflictedDocIterator(totalCount, ownedCount *int) types.DocIterator {
+func (r *VDR) newOwnConflictedDocIterator(totalCount, ownedCount *int) management.DocIterator {
return func(doc did.Document, metadata resolver.DocumentMetadata) error {
*totalCount++
controllers, err := didnuts.ResolveControllers(r.store, doc, nil)
@@ -329,7 +329,7 @@ func (r *VDR) Update(ctx context.Context, id did.DID, next did.Document) error {
if err != nil {
return fmt.Errorf("update DID document: %w", err)
}
- if didservice.IsDeactivated(*currentDIDDocument) {
+ if resolver.IsDeactivated(*currentDIDDocument) {
return fmt.Errorf("update DID document: %w", resolver.ErrDeactivated)
}
diff --git a/vdr/vdr_test.go b/vdr/vdr_test.go
index 62253b765b..a200073f49 100644
--- a/vdr/vdr_test.go
+++ b/vdr/vdr_test.go
@@ -31,7 +31,6 @@ import (
"github.com/nuts-foundation/nuts-node/core"
"github.com/nuts-foundation/nuts-node/vdr/didnuts"
"github.com/nuts-foundation/nuts-node/vdr/didnuts/didstore"
- "github.com/nuts-foundation/nuts-node/vdr/didservice"
"github.com/nuts-foundation/nuts-node/vdr/resolver"
"io"
"net/http"
@@ -72,7 +71,7 @@ func newVDRTestCtx(t *testing.T) vdrTestCtx {
mockNetwork := network.NewMockTransactions(ctrl)
mockKeyStore := crypto.NewMockKeyStore(ctrl)
mockDocumentOwner := types.NewMockDocumentOwner(ctrl)
- resolverRouter := &didservice.DIDResolverRouter{}
+ resolverRouter := &resolver.DIDResolverRouter{}
vdr := VDR{
store: mockStore,
network: mockNetwork,