Skip to content

Commit

Permalink
Add did:web resolver (#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
KendallWeihe authored Mar 5, 2024
1 parent c05e1fc commit 256e911
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 2 deletions.
80 changes: 79 additions & 1 deletion dids/didweb/didweb.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package didweb

import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"strings"
Expand Down Expand Up @@ -130,7 +135,7 @@ func Create(domain string, opts ...CreateOption) (_did.BearerDID, error) {

if parsedDomain.Path != "" {
idPath := strings.ReplaceAll(parsedDomain.Path, "/", ":")
methodSpecificID += idPath
methodSpecificID += strings.TrimSuffix(idPath, ":")
}

did, err := _did.Parse("did:web:" + methodSpecificID)
Expand Down Expand Up @@ -182,3 +187,76 @@ func Create(domain string, opts ...CreateOption) (_did.BearerDID, error) {
Document: document,
}, nil
}

// DecodeID takes a did:web's identifier (the third part, after the method) and returns the web URL per the [spec]
//
// [spec]: https://w3c-ccg.github.io/did-method-web/#read-resolve
func DecodeID(id string) string {
var domain string

// "1. Replace ":" with "/" in the method specific identifier to obtain the fully qualified domain name and optional path."
domain = strings.ReplaceAll(id, ":", "/")

// "2. If the domain contains a port percent decode the colon."
domain = strings.Replace(domain, "%3A", ":", 1)

// "3. Generate an HTTPS URL to the expected location of the DID document by prepending https://."
domain = "https://" + domain

// "4. If no path has been specified in the URL, append /.well-known."
if strings.Count(domain, "/") == 2 {
domain += "/.well-known"
}

// "5. Append /did.json to complete the URL."
domain += "/did.json"

return domain
}

type Resolver struct{}

// ResolveWithContext the provided DID URI (must be a did:web) as per the [spec]
//
// [spec]: https://w3c-ccg.github.io/did-method-web/#read-resolve
func (r Resolver) ResolveWithContext(ctx context.Context, uri string) (didcore.ResolutionResult, error) {
return r.Resolve(uri)
}

// Resolve the provided DID URI (must be a did:web) as per the [spec]
//
// [spec]: https://w3c-ccg.github.io/did-method-web/#read-resolve
func (r Resolver) Resolve(uri string) (didcore.ResolutionResult, error) {
did, err := _did.Parse(uri)
if err != nil {
return didcore.ResolutionResultWithError("invalidDid"), didcore.ResolutionError{Code: "invalidDid"}
}

if did.Method != "web" {
return didcore.ResolutionResultWithError("invalidDid"), didcore.ResolutionError{Code: "invalidDid"}
}

domain := DecodeID(did.ID)

// TODO item 6 from https://w3c-ccg.github.io/did-method-web/#read-resolve https://github.com/TBD54566975/web5-go/issues/94
// TODO item 7 from https://w3c-ccg.github.io/did-method-web/#read-resolve https://github.com/TBD54566975/web5-go/issues/95

resp, err := http.Get(domain)
if err != nil {
return didcore.ResolutionResult{}, fmt.Errorf("failed to make GET request: %w", err)
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return didcore.ResolutionResult{}, fmt.Errorf("failed to read response body: %w", err)
}

var document didcore.Document
err = json.Unmarshal(body, &document)
if err != nil {
return didcore.ResolutionResult{}, fmt.Errorf("failed to deserialize document: %w", err)
}

return didcore.ResolutionResultWithDocument(document), errors.New("developing")
}
8 changes: 8 additions & 0 deletions dids/didweb/didweb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,11 @@ func TestCreate_WithOptions(t *testing.T) {
assert.Equal(t, "did:example:123", document.Controller[0])

}

func TestDecodeID(t *testing.T) {
portAndPathCase := didweb.DecodeID("localhost%3A8080:something")
assert.Equal(t, "https://localhost:8080/something/did.json", portAndPathCase)

wellKnownCase := didweb.DecodeID("localhost")
assert.Equal(t, "https://localhost/.well-known/did.json", wellKnownCase)
}
4 changes: 3 additions & 1 deletion dids/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/tbd54566975/web5-go/dids/didcore"
"github.com/tbd54566975/web5-go/dids/diddht"
"github.com/tbd54566975/web5-go/dids/didjwk"
"github.com/tbd54566975/web5-go/dids/didweb"
)

// Resolve resolves the provided DID URI. This function is capable of resolving
Expand All @@ -30,8 +31,9 @@ func getDefaultResolver() *didResolver {
once.Do(func() {
instance = &didResolver{
resolvers: map[string]didcore.MethodResolver{
"jwk": didjwk.Resolver{},
"dht": diddht.NewResolver("", http.DefaultClient),
"jwk": didjwk.Resolver{},
"web": didweb.Resolver{},
},
}
})
Expand Down

0 comments on commit 256e911

Please sign in to comment.