|
| 1 | +package did_web |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "io" |
| 6 | + "net/http" |
| 7 | + "strings" |
| 8 | + "testing" |
| 9 | + |
| 10 | + "github.com/stretchr/testify/require" |
| 11 | + |
| 12 | + "github.com/MetaMask/go-did-it" |
| 13 | +) |
| 14 | + |
| 15 | +func TestDecode(t *testing.T) { |
| 16 | + testcases := []struct { |
| 17 | + did string |
| 18 | + valid bool |
| 19 | + }{ |
| 20 | + {"did:web:w3c-ccg.github.io", true}, |
| 21 | + {"did:web:w3c-ccg.github.io:user:alice", true}, |
| 22 | + {"did:web:example.com%3A3000", true}, |
| 23 | + } |
| 24 | + |
| 25 | + for _, tc := range testcases { |
| 26 | + t.Run(tc.did, func(t *testing.T) { |
| 27 | + _, err := Decode(tc.did) |
| 28 | + if tc.valid && err != nil { |
| 29 | + t.Errorf("Decode(%q) = %v, want nil", tc.did, err) |
| 30 | + } else if !tc.valid && err == nil { |
| 31 | + t.Errorf("Decode(%q) = nil, want error", tc.did) |
| 32 | + } |
| 33 | + }) |
| 34 | + } |
| 35 | +} |
| 36 | + |
| 37 | +func TestIsValidHost(t *testing.T) { |
| 38 | + testcases := []struct { |
| 39 | + host string |
| 40 | + valid bool |
| 41 | + }{ |
| 42 | + {"example.com", true}, |
| 43 | + {"sub.example.com", true}, |
| 44 | + {"example.com:8080", true}, |
| 45 | + {"w3c-ccg.github.io", true}, |
| 46 | + {"192.168.1.1", false}, |
| 47 | + {"invalid..com", false}, |
| 48 | + {".example.com", false}, |
| 49 | + {"example.com.", true}, |
| 50 | + {"", false}, |
| 51 | + {"just_invalid", false}, |
| 52 | + {"-example.com", false}, |
| 53 | + {"example.com-", false}, |
| 54 | + } |
| 55 | + for _, tc := range testcases { |
| 56 | + t.Run(tc.host, func(t *testing.T) { |
| 57 | + if isValidHost(tc.host) != tc.valid { |
| 58 | + t.Errorf("isValidHost(%q) = %v, want %v", tc.host, isValidHost(tc.host), tc.valid) |
| 59 | + } |
| 60 | + }) |
| 61 | + } |
| 62 | +} |
| 63 | + |
| 64 | +func TestResolution(t *testing.T) { |
| 65 | + client := &MockHTTPClient{ |
| 66 | + url: "https://example.com/.well-known/did.json", |
| 67 | + resp: `{ |
| 68 | + "@context": [ |
| 69 | + "https://www.w3.org/ns/did/v1", |
| 70 | + "https://w3id.org/security/suites/ed25519-2020/v1", |
| 71 | + "https://w3id.org/security/suites/x25519-2020/v1" |
| 72 | + ], |
| 73 | + "id": "did:web:example.com", |
| 74 | + "verificationMethod": [{ |
| 75 | + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", |
| 76 | + "type": "Ed25519VerificationKey2020", |
| 77 | + "controller": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", |
| 78 | + "publicKeyMultibase": "z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" |
| 79 | + }], |
| 80 | + "authentication": [ |
| 81 | + "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" |
| 82 | + ], |
| 83 | + "assertionMethod": [ |
| 84 | + "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" |
| 85 | + ], |
| 86 | + "capabilityDelegation": [ |
| 87 | + "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" |
| 88 | + ], |
| 89 | + "capabilityInvocation": [ |
| 90 | + "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK" |
| 91 | + ], |
| 92 | + "keyAgreement": [{ |
| 93 | + "id": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK#z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p", |
| 94 | + "type": "X25519KeyAgreementKey2020", |
| 95 | + "controller": "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK", |
| 96 | + "publicKeyMultibase": "z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p" |
| 97 | + }] |
| 98 | +}`, |
| 99 | + } |
| 100 | + |
| 101 | + d, err := Decode("did:web:example.com") |
| 102 | + require.NoError(t, err) |
| 103 | + |
| 104 | + doc, err := d.Document(did.WithHttpClient(client)) |
| 105 | + require.NoError(t, err) |
| 106 | + |
| 107 | + require.Equal(t, "did:web:example.com", doc.ID()) |
| 108 | + require.Len(t, doc.VerificationMethods(), 1) |
| 109 | + require.Len(t, doc.Authentication(), 1) |
| 110 | + require.Len(t, doc.Assertion(), 1) |
| 111 | + require.Len(t, doc.KeyAgreement(), 1) |
| 112 | +} |
| 113 | + |
| 114 | +type MockHTTPClient struct { |
| 115 | + url string |
| 116 | + resp string |
| 117 | +} |
| 118 | + |
| 119 | +func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) { |
| 120 | + if req.URL.String() != m.url { |
| 121 | + return nil, fmt.Errorf("unexpected url: %s", req.URL.String()) |
| 122 | + } |
| 123 | + |
| 124 | + return &http.Response{ |
| 125 | + StatusCode: http.StatusOK, |
| 126 | + Body: io.NopCloser(strings.NewReader(m.resp)), |
| 127 | + }, nil |
| 128 | +} |
0 commit comments