diff --git a/did/ion/operations.go b/did/ion/operations.go index d22a33af..96dfc698 100644 --- a/did/ion/operations.go +++ b/did/ion/operations.go @@ -113,7 +113,7 @@ func NewIONResolver(client *http.Client, baseURL string) (*Resolver, error) { } // Resolve resolves a did:ion DID by appending the DID to the base URL with the identifiers path and making a GET request -func (i Resolver) Resolve(ctx context.Context, id string, _ did.ResolutionOptions) (*did.ResolutionResult, error) { +func (i Resolver) Resolve(ctx context.Context, id string, _ did.ResolutionOption) (*did.ResolutionResult, error) { if i.baseURL.String() == "" { return nil, errors.New("resolver URL cannot be empty") } diff --git a/did/ion/operations_test.go b/did/ion/operations_test.go index bb5db938..30e6ae92 100644 --- a/did/ion/operations_test.go +++ b/did/ion/operations_test.go @@ -48,7 +48,7 @@ func TestResolver(t *testing.T) { assert.NoError(tt, err) assert.NotEmpty(tt, resolver) - result, err := resolver.Resolve(context.TODO(), "bad", nil) + result, err := resolver.Resolve(context.Background(), "bad", nil) assert.Error(tt, err) assert.Empty(tt, result) assert.Contains(tt, err.Error(), "could not resolve DID") @@ -65,7 +65,7 @@ func TestResolver(t *testing.T) { assert.NoError(tt, err) assert.NotEmpty(tt, resolver) - result, err := resolver.Resolve(context.TODO(), "did:ion:test", nil) + result, err := resolver.Resolve(context.Background(), "did:ion:test", nil) assert.Error(tt, err) assert.Empty(tt, result) assert.Contains(tt, err.Error(), "could not parse DID Resolution Result or DID Document") @@ -82,7 +82,7 @@ func TestResolver(t *testing.T) { assert.NoError(tt, err) assert.NotEmpty(tt, resolver) - result, err := resolver.Resolve(context.TODO(), "did:ion:test", nil) + result, err := resolver.Resolve(context.Background(), "did:ion:test", nil) assert.NoError(tt, err) assert.NotEmpty(tt, result) assert.Equal(tt, "did:ion:test", result.Document.ID) @@ -98,7 +98,7 @@ func TestResolver(t *testing.T) { assert.NoError(tt, err) assert.NotEmpty(tt, resolver) - err = resolver.Anchor(context.TODO(), nil) + err = resolver.Anchor(context.Background(), nil) assert.Error(tt, err) assert.Contains(tt, err.Error(), "anchor operation failed") }) @@ -127,7 +127,7 @@ func TestResolver(t *testing.T) { assert.NotEmpty(tt, did) assert.NotEmpty(tt, createOp) - err = resolver.Anchor(context.TODO(), CreateRequest{ + err = resolver.Anchor(context.Background(), CreateRequest{ Type: Create, SuffixData: SuffixData{ DeltaHash: "deltaHash", diff --git a/did/key.go b/did/key.go index f11640bb..1a5a895a 100644 --- a/did/key.go +++ b/did/key.go @@ -1,6 +1,7 @@ package did import ( + "context" gocrypto "crypto" "fmt" "strings" @@ -24,8 +25,8 @@ type ( ) const ( - // DIDKeyPrefix did:key prefix - DIDKeyPrefix = "did:key" + // KeyPrefix did:key prefix + KeyPrefix = "did:key" ) func (d DIDKey) IsValid() bool { @@ -39,7 +40,7 @@ func (d DIDKey) String() string { // Suffix returns the value without the `did:key` prefix func (d DIDKey) Suffix() (string, error) { - split := strings.Split(string(d), DIDKeyPrefix+":") + split := strings.Split(string(d), KeyPrefix+":") if len(split) != 2 { return "", fmt.Errorf("invalid did:key: %s", d) } @@ -100,7 +101,7 @@ func CreateDIDKey(kt crypto.KeyType, publicKey []byte) (*DIDKey, error) { if err != nil { return nil, errors.Wrap(err, "could not encode did:key") } - did := DIDKey(fmt.Sprintf("%s:%s", DIDKeyPrefix, encoded)) + did := DIDKey(fmt.Sprintf("%s:%s", KeyPrefix, encoded)) return &did, nil } @@ -266,8 +267,8 @@ func GetSupportedDIDKeyTypes() []crypto.KeyType { type KeyResolver struct{} -func (KeyResolver) Resolve(did string, _ ResolutionOptions) (*ResolutionResult, error) { - if !strings.HasPrefix(did, DIDKeyPrefix) { +func (KeyResolver) Resolve(_ context.Context, did string, _ ...ResolutionOption) (*ResolutionResult, error) { + if !strings.HasPrefix(did, KeyPrefix) { return nil, fmt.Errorf("not a did:key DID: %s", did) } didKey := DIDKey(did) @@ -275,7 +276,6 @@ func (KeyResolver) Resolve(did string, _ ResolutionOptions) (*ResolutionResult, if err != nil { return nil, errors.Wrapf(err, "could not expand did:key DID: %s", did) } - // TODO(gabe) full resolution support to be added in https://github.com/TBD54566975/ssi-sdk/issues/38 return &ResolutionResult{Document: *doc}, nil } diff --git a/did/key_fuzz_test.go b/did/key_fuzz_test.go index 8a5f637d..dae8c747 100644 --- a/did/key_fuzz_test.go +++ b/did/key_fuzz_test.go @@ -1,6 +1,7 @@ package did import ( + "context" "testing" "github.com/stretchr/testify/assert" @@ -33,7 +34,7 @@ func FuzzCreateAndResolve(f *testing.F) { keytypes := GetSupportedDIDKeyTypes() ktLen := len(keytypes) - resolvers := []Resolution{KeyResolver{}, WebResolver{}, PKHResolver{}, PeerResolver{}} + resolvers := []Resolver{KeyResolver{}, WebResolver{}, PKHResolver{}, PeerResolver{}} resolver, _ := NewResolver(resolvers...) for i, pk := range mockPubKeys { @@ -46,7 +47,7 @@ func FuzzCreateAndResolve(f *testing.F) { didKey, err := CreateDIDKey(kt, pubKey) assert.NoError(t, err) - doc, err := resolver.Resolve(didKey.String()) + doc, err := resolver.Resolve(context.Background(), didKey.String()) if err != nil { t.Skip() } diff --git a/did/key_test.go b/did/key_test.go index 78fee5d5..a1cb6907 100644 --- a/did/key_test.go +++ b/did/key_test.go @@ -1,6 +1,7 @@ package did import ( + "context" gocrypto "crypto" "crypto/ecdsa" "crypto/ed25519" @@ -213,14 +214,14 @@ func TestGenerateAndDecode(t *testing.T) { } func TestGenerateAndResolve(t *testing.T) { - resolvers := []Resolution{KeyResolver{}, WebResolver{}, PKHResolver{}, PeerResolver{}} + resolvers := []Resolver{KeyResolver{}, WebResolver{}, PKHResolver{}, PeerResolver{}} resolver, _ := NewResolver(resolvers...) for _, kt := range GetSupportedDIDKeyTypes() { _, didKey, err := GenerateDIDKey(kt) assert.NoError(t, err) - doc, err := resolver.Resolve(didKey.String()) + doc, err := resolver.Resolve(context.Background(), didKey.String()) assert.NoError(t, err) assert.NotEmpty(t, doc) assert.Equal(t, didKey.String(), doc.Document.ID) diff --git a/did/peer.go b/did/peer.go index 62478f7a..a5f7981e 100644 --- a/did/peer.go +++ b/did/peer.go @@ -13,6 +13,7 @@ package did import ( + "context" gocrypto "crypto" b64 "encoding/base64" "fmt" @@ -190,8 +191,8 @@ func (DIDPeer) IsValidPurpose(p PurposeType) bool { // Resolve resolves a did:peer into a DID Document // To do so, it decodes the key, constructs a verification method, and returns a DID Document .This allows PeerMethod0 -// to implement the DID Resolution interface and be used to expand the did into the DID Document. -func (PeerMethod0) resolve(did DID, _ ResolutionOptions) (*ResolutionResult, error) { +// to implement the DID Resolver interface and be used to expand the did into the DID Document. +func (PeerMethod0) resolve(did DID, _ ResolutionOption) (*ResolutionResult, error) { d, ok := did.(DIDPeer) if !ok { return nil, errors.Wrap(util.CastingError, "did:peer") @@ -231,7 +232,7 @@ func (PeerMethod0) resolve(did DID, _ ResolutionOptions) (*ResolutionResult, err return &ResolutionResult{Document: document}, nil } -func (PeerMethod1) resolve(d DID, _ ResolutionOptions) (*ResolutionResult, error) { +func (PeerMethod1) resolve(d DID, _ ResolutionOption) (*ResolutionResult, error) { if _, ok := d.(DIDPeer); !ok { return nil, errors.Wrap(util.CastingError, DIDPeerPrefix) } @@ -256,7 +257,7 @@ func (DIDPeer) buildVerificationMethod(data, did string) (*VerificationMethod, e // Resolve Splits the DID string into element. // Extract element purpose and decode each key or service. // Insert each key or service into the document according to the designated pu -func (PeerMethod2) resolve(did DID, _ ResolutionOptions) (*ResolutionResult, error) { +func (PeerMethod2) resolve(did DID, _ ResolutionOption) (*ResolutionResult, error) { d, ok := did.(DIDPeer) if !ok { return nil, errors.Wrap(util.CastingError, "did:peer") @@ -512,7 +513,7 @@ func peerMethodAvailable(m string) bool { type PeerResolver struct{} -func (PeerResolver) Resolve(did string, opts ResolutionOptions) (*ResolutionResult, error) { +func (PeerResolver) Resolve(_ context.Context, did string, opts ...ResolutionOption) (*ResolutionResult, error) { if !strings.HasPrefix(did, DIDPeerPrefix) { return nil, fmt.Errorf("not a did:peer DID: %s", did) } diff --git a/did/peer_test.go b/did/peer_test.go index 48e0c3dc..7dd492e0 100644 --- a/did/peer_test.go +++ b/did/peer_test.go @@ -1,6 +1,7 @@ package did import ( + "context" "testing" "github.com/TBD54566975/ssi-sdk/crypto" @@ -118,30 +119,30 @@ func TestDIDPeerUtilities(t *testing.T) { func TestPeerResolver(t *testing.T) { bad := "asdf" var r PeerResolver - _, err := r.Resolve(bad, nil) + _, err := r.Resolve(context.Background(), bad, nil) assert.Error(t, err) m0 := "did:peer:0z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH" - _, err = r.Resolve(m0, nil) + _, err = r.Resolve(context.Background(), m0, nil) assert.NoError(t, err) mbad := "did:peer:4z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH" - _, err = r.Resolve(mbad, nil) + _, err = r.Resolve(context.Background(), mbad, nil) assert.Error(t, err) // https://identity.foundation/peer-did-method-spec/#multi-key-creation - key agreement m2 := "did:peer:2.Ez6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0=" - _, err = r.Resolve(m2, nil) + _, err = r.Resolve(context.Background(), m2, nil) assert.NoError(t, err) // https://identity.foundation/peer-did-method-spec/#multi-key-creation w/ key agreement // We currently don't support key agreement, so should throw error m2 = "did:peer:2.Ez6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH.VzXwpBnMdCm1cLmKuzgESn29nqnonp1ioqrQMRHNsmjMyppzx8xB2pv7cw8q1PdDacSrdWE3dtB9f7Nxk886mdzNFoPtY.SeyJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0=" - _, err = r.Resolve(m2, nil) + _, err = r.Resolve(context.Background(), m2, nil) assert.NoError(t, err) m1 := "did:peer:1z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH" - _, err = r.Resolve(m1, nil) + _, err = r.Resolve(context.Background(), m1, nil) assert.Error(t, err) } diff --git a/did/pkh.go b/did/pkh.go index b9d2d1b9..67515927 100644 --- a/did/pkh.go +++ b/did/pkh.go @@ -1,6 +1,7 @@ package did import ( + "context" "embed" "fmt" "regexp" @@ -246,7 +247,7 @@ func IsValidPKH(did DIDPKH) bool { type PKHResolver struct{} -func (PKHResolver) Resolve(did string, _ ResolutionOptions) (*ResolutionResult, error) { +func (PKHResolver) Resolve(_ context.Context, did string, _ ...ResolutionOption) (*ResolutionResult, error) { if !strings.HasPrefix(did, DIDPKHPrefix) { return nil, fmt.Errorf("not a did:pkh DID: %s", did) } @@ -255,7 +256,6 @@ func (PKHResolver) Resolve(did string, _ ResolutionOptions) (*ResolutionResult, if err != nil { return nil, errors.Wrapf(err, "could not expand did:pkh DID: %s", did) } - // TODO(gabe) full resolution support to be added in https://github.com/TBD54566975/ssi-sdk/issues/38 return &ResolutionResult{Document: *doc}, nil } diff --git a/did/resolver.go b/did/resolver.go index c123e0df..28fc7994 100644 --- a/did/resolver.go +++ b/did/resolver.go @@ -1,6 +1,7 @@ package did import ( + "context" "fmt" "strings" @@ -8,27 +9,27 @@ import ( "github.com/pkg/errors" ) -// ResolutionOptions https://www.w3.org/TR/did-spec-registries/#did-resolution-options -type ResolutionOptions any +// ResolutionOption https://www.w3.org/TR/did-spec-registries/#did-resolution-options +type ResolutionOption any -// Resolution provides an interface for resolving DIDs as per the spec https://www.w3.org/TR/did-core/#did-resolution -type Resolution interface { +// Resolver provides an interface for resolving DIDs as per the spec https://www.w3.org/TR/did-core/#did-resolution +type Resolver interface { // Resolve Attempts to resolve a DID for a given method - Resolve(did string, opts ResolutionOptions) (*ResolutionResult, error) + Resolve(ctx context.Context, did string, opts ...ResolutionOption) (*ResolutionResult, error) // Method provides the method for the given resolution implementation Method() Method } -// Resolver resolves a DID. The current implementation ssk-sdk does not have a universal resolver: +// MultiMethodResolver resolves a DID. The current implementation ssk-sdk does not have a universal resolver: // https://github.com/decentralized-identity/universal-resolver // In its place, this method attempts to resolve DID methods that can be resolved without relying on additional services. -type Resolver struct { - resolvers map[Method]Resolution +type MultiMethodResolver struct { + resolvers map[Method]Resolver methods []Method } -func NewResolver(resolvers ...Resolution) (*Resolver, error) { - r := make(map[Method]Resolution) +func NewResolver(resolvers ...Resolver) (*MultiMethodResolver, error) { + r := make(map[Method]Resolver) var methods []Method for _, resolver := range resolvers { method := resolver.Method() @@ -38,22 +39,22 @@ func NewResolver(resolvers ...Resolution) (*Resolver, error) { r[method] = resolver methods = append(methods, method) } - return &Resolver{resolvers: r, methods: methods}, nil + return &MultiMethodResolver{resolvers: r, methods: methods}, nil } // Resolve attempts to resolve a DID for a given method -func (dr Resolver) Resolve(did string, opts ...ResolutionOptions) (*ResolutionResult, error) { +func (dr MultiMethodResolver) Resolve(ctx context.Context, did string, opts ...ResolutionOption) (*ResolutionResult, error) { method, err := GetMethodForDID(did) if err != nil { return nil, errors.Wrap(err, "failed to get method for DID before resolving") } if resolver, ok := dr.resolvers[method]; ok { - return resolver.Resolve(did, opts) + return resolver.Resolve(ctx, did, opts) } return nil, fmt.Errorf("unsupported method: %s", method) } -func (dr Resolver) SupportedMethods() []Method { +func (dr MultiMethodResolver) SupportedMethods() []Method { return dr.methods } @@ -72,7 +73,7 @@ func ParseDIDResolution(resolvedDID []byte) (*ResolutionResult, error) { return nil, errors.New("cannot parse empty resolved DID") } - // first try to parse as a DID Resolution Result + // first try to parse as a DID Resolver Result var result ResolutionResult if err := json.Unmarshal(resolvedDID, &result); err == nil { if result.IsEmpty() { diff --git a/did/resolver_test.go b/did/resolver_test.go index 563cdc85..06dd09e5 100644 --- a/did/resolver_test.go +++ b/did/resolver_test.go @@ -1,6 +1,7 @@ package did import ( + "context" "testing" "github.com/TBD54566975/ssi-sdk/crypto" @@ -9,14 +10,14 @@ import ( ) func TestResolveDID(t *testing.T) { - resolvers := []Resolution{KeyResolver{}, WebResolver{}, PKHResolver{}, PeerResolver{}} + resolvers := []Resolver{KeyResolver{}, WebResolver{}, PKHResolver{}, PeerResolver{}} resolver, err := NewResolver(resolvers...) assert.NoError(t, err) assert.NotEmpty(t, resolver) assert.Equal(t, len(resolvers), len(resolver.SupportedMethods())) // unsupported type - _, err = resolver.Resolve("did:unsupported:123") + _, err = resolver.Resolve(context.Background(), "did:unsupported:123") assert.Error(t, err) assert.Contains(t, err.Error(), "unsupported method: unsupported") @@ -24,7 +25,7 @@ func TestResolveDID(t *testing.T) { _, didKey, err := GenerateDIDKey(crypto.Ed25519) assert.NoError(t, err) assert.NotEmpty(t, didKey) - doc, err := resolver.Resolve(didKey.String()) + doc, err := resolver.Resolve(context.Background(), didKey.String()) assert.NoError(t, err) assert.NotEmpty(t, doc) @@ -33,13 +34,13 @@ func TestResolveDID(t *testing.T) { didPKH, err := CreateDIDPKHFromNetwork(Ethereum, address) assert.NoError(t, err) assert.NotEmpty(t, didPKH) - doc, err = resolver.Resolve(didPKH.String()) + doc, err = resolver.Resolve(context.Background(), didPKH.String()) assert.NoError(t, err) assert.NotEmpty(t, doc) // did peer didPeer := "did:peer:0z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH" - doc, err = resolver.Resolve(didPeer) + doc, err = resolver.Resolve(context.Background(), didPeer) assert.NoError(t, err) assert.NotEmpty(t, doc) @@ -50,7 +51,7 @@ func TestResolveDID(t *testing.T) { BodyString(`{"didDocument": {"id": "did:web:demo.ssi-sdk.com"}}`) defer gock.Off() didWeb := "did:web:demo.ssi-sdk.com" - doc, err = resolver.Resolve(didWeb) + doc, err = resolver.Resolve(context.Background(), didWeb) assert.NoError(t, err) assert.NotEmpty(t, doc) } diff --git a/did/web.go b/did/web.go index b82b15a8..d7e4e924 100644 --- a/did/web.go +++ b/did/web.go @@ -1,6 +1,7 @@ package did import ( + "context" "fmt" "io" "net/http" @@ -182,7 +183,7 @@ func (WebResolver) Method() Method { // Resolve fetches and returns the Document from the expected URL // specification: https://w3c-ccg.github.io/did-method-web/#read-resolve -func (WebResolver) Resolve(did string, _ ResolutionOptions) (*ResolutionResult, error) { +func (WebResolver) Resolve(_ context.Context, did string, _ ...ResolutionOption) (*ResolutionResult, error) { if !strings.HasPrefix(did, WebPrefix) { return nil, fmt.Errorf("not a did:web DID: %s", did) } diff --git a/wasm/main.go b/wasm/main.go index bfc0943c..e2e6075b 100644 --- a/wasm/main.go +++ b/wasm/main.go @@ -3,6 +3,7 @@ package main import ( + "context" "crypto/ed25519" "encoding/base64" "log" @@ -78,13 +79,13 @@ func makeDid(_ js.Value, args []js.Value) any { func resolveDid(_ js.Value, args []js.Value) any { didString := args[0].String() - resolvers := []did.Resolution{did.KeyResolver{}, did.WebResolver{}, did.PKHResolver{}, did.PeerResolver{}} + resolvers := []did.Resolver{did.KeyResolver{}, did.WebResolver{}, did.PKHResolver{}, did.PeerResolver{}} resolver, err := did.NewResolver(resolvers...) if err != nil { return err } - doc, err := resolver.Resolve(didString) + doc, err := resolver.Resolve(context.Background(), didString) if err != nil { return err } diff --git a/wasm/static/main.wasm b/wasm/static/main.wasm index 16397f13..62d17899 100755 Binary files a/wasm/static/main.wasm and b/wasm/static/main.wasm differ