Skip to content

Commit

Permalink
Merge pull request #125 from TBD54566975/testvectors
Browse files Browse the repository at this point in the history
Add web5 spec resolve test vectors for did dht
  • Loading branch information
mihai-chiorean authored Mar 29, 2024
2 parents bca7db6 + 896fb59 commit deb5c77
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# Fetches all history for all tags and branches
fetch-depth: 0
# Initializes submodules recursively
submodules: recursive
- uses: ./.github/actions/setup
- run: just test
- name: Upload coverage reports to Codecov
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "web5-spec"]
path = web5-spec
url = [email protected]:TBD54566975/web5-spec.git
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ JWT signing and verification using DIDs
# Development

## Prerequisites
We use a submodule for test vectors that make sure we follow the appropriate spec. Running tests will fail without it.
To set up the submodule, clone using:

```
git clone --recurse-submodules [email protected]:TBD54566975/web5-go.git
```

If you've already cloned, add submodules:

```
git submodule update --init
```

### [`hermit`](https://cashapp.github.io/hermit/)
This repo uses hermit to manage all environment dependencies (e.g. `just`, `go`).
Expand Down
8 changes: 4 additions & 4 deletions dids/diddht/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,27 @@ func (r *Resolver) ResolveWithContext(ctx context.Context, uri string) (didcore.
}

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

// 2. ensure did ID is zbase32
identifier, err := zbase32.DecodeString(did.ID)
if err != nil {
// TODO log err
return didcore.ResolutionResultWithError("invalidDid"), didcore.ResolutionError{Code: "invalidDid"}
return didcore.ResolutionResultWithError("invalidPublicKey"), didcore.ResolutionError{Code: "invalidPublicKey"}
}

if len(identifier) == 0 {
// return nil, fmt.Errorf("no bytes decoded from zbase32 identifier %s", did.ID)
// TODO log err
return didcore.ResolutionResultWithError("invalidDid"), didcore.ResolutionError{Code: "invalidDid"}
return didcore.ResolutionResultWithError("invalidPublicKey"), didcore.ResolutionError{Code: "invalidPublicKey"}
}

// 3. fetch from the relay
bep44Message, err := r.relay.FetchWithContext(ctx, did.ID)
if err != nil {
// TODO log err
return didcore.ResolutionResultWithError("invalidDid"), didcore.ResolutionError{Code: "invalidDid"}
return didcore.ResolutionResultWithError("notFound"), didcore.ResolutionError{Code: "notFound"}
}

// get the dns payload from the bep44 message
Expand Down
119 changes: 119 additions & 0 deletions dids/diddht/resolver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package diddht

import (
"encoding/hex"
"encoding/json"
"net/http"
"net/http/httptest"
"os"
"testing"

"github.com/alecthomas/assert/v2"
)

const dhtSpecVectors string = "../../web5-spec/test-vectors/did_dht/resolve.json"

type vector struct {
Description string `json:"description"`
Input struct {
DIDUri string `json:"didUri"`
} `json:"input"`
Output struct {
DIDResolutionMetadata struct {
Error string `json:"error"`
} `json:"didResolutionMetadata"`
} `json:"output"`
Errors bool `json:"errors"`
}

func initVector() ([]vector, error) {
// Load test vectors from file
data, err := os.ReadFile(dhtSpecVectors)
if err != nil {
return nil, err
}

// Unmarshal test vectors
vectorData := struct {
Vectors []vector `json:"vectors"`
}{}
if err := json.Unmarshal(data, &vectorData); err != nil {
return nil, err
}
return vectorData.Vectors, nil
}

func Test_VectorsResolve(t *testing.T) {
vectors, err := initVector()
assert.NoError(t, err)

mocks := map[string]vector{}
for _, v := range vectors {
mocks[v.Input.DIDUri] = v
}

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
return
}))
defer ts.Close()

r := NewResolver(ts.URL, http.DefaultClient)

for _, v := range vectors {
vector := v
t.Run(vector.Description, func(t *testing.T) {
res, err := r.Resolve(vector.Input.DIDUri)
if vector.Errors {
assert.True(t, err != nil)
assert.Equal(t, res.ResolutionMetadata.Error, vector.Output.DIDResolutionMetadata.Error)
}
})
}
}

func Test_resolve(t *testing.T) {

// vector taken from https://github.com/TBD54566975/web5-js/blob/91d52aaa9410db5e5f7c3c31ebfe0d4956028496/packages/dids/tests/methods/did-dht.spec.ts#L725
vectors := map[string]string{
"did:dht:9tjoow45ef1hksoo96bmzkwwy3mhme95d7fsi3ezjyjghmp75qyo": "ea33e704f3a48a3392f54b28744cdfb4e24780699f92ba7df62fd486d2a2cda3f263e1c6bcbd" +
"75d438be7316e5d6e94b13e98151f599cfecefad0b37432bd90a0000000065b0ed1600008400" +
"0000000300000000035f6b30045f6469643439746a6f6f773435656631686b736f6f3936626d" +
"7a6b777779336d686d653935643766736933657a6a796a67686d70373571796f000010000100" +
"001c2000373669643d303b743d303b6b3d5f464d49553174425a63566145502d437536715542" +
"6c66466f5f73665332726c4630675362693239323445045f747970045f6469643439746a6f6f" +
"773435656631686b736f6f3936626d7a6b777779336d686d653935643766736933657a6a796a" +
"67686d70373571796f000010000100001c2000070669643d372c36045f6469643439746a6f6f" +
"773435656631686b736f6f3936626d7a6b777779336d686d653935643766736933657a6a796a" +
"67686d70373571796f000010000100001c20002726763d303b766d3d6b303b617574683d6b30" +
"3b61736d3d6b303b64656c3d6b303b696e763d6b30",
}

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
did := "did:dht:" + r.URL.Path[1:]
defer r.Body.Close()
buf, ok := vectors[did]
if !ok {
w.WriteHeader(http.StatusNotFound)
return
}
data, err := hex.DecodeString(buf)
assert.NoError(t, err)
_, err = w.Write(data)
assert.NoError(t, err)

}))
defer ts.Close()

r := NewResolver(ts.URL, http.DefaultClient)

for k := range vectors {
did := k
t.Run(did, func(t *testing.T) {
res, err := r.Resolve(did)
assert.NoError(t, err)
assert.NotZero(t, res.Document)
assert.Equal(t, res.Document.ID, did)
})
}
}
1 change: 1 addition & 0 deletions web5-spec
Submodule web5-spec added at 77f2cb

0 comments on commit deb5c77

Please sign in to comment.