+1
atproto/identity/apidir/apidir.go
+1
atproto/identity/apidir/apidir.go
+1
atproto/identity/base_directory.go
+1
atproto/identity/base_directory.go
···
55
55
if err != nil {
56
56
return nil, fmt.Errorf("could not verify handle/DID match: %w", err)
57
57
}
58
+
// NOTE: DeclaredHandle() returns a normalized handle, and we already normalized 'h' above
58
59
if declared != h {
59
60
return nil, fmt.Errorf("%w: %s != %s", ErrHandleMismatch, declared, h)
60
61
}
+2
atproto/identity/cache_directory.go
+2
atproto/identity/cache_directory.go
···
93
93
}
94
94
95
95
func (d *CacheDirectory) ResolveHandle(ctx context.Context, h syntax.Handle) (syntax.DID, error) {
96
+
h = h.Normalize()
96
97
if h.IsInvalidHandle() {
97
98
return "", fmt.Errorf("can not resolve handle: %w", ErrInvalidHandle)
98
99
}
···
251
252
if err != nil {
252
253
return nil, hit, fmt.Errorf("could not verify handle/DID mapping: %w", err)
253
254
}
255
+
// NOTE: DeclaredHandle() returns a normalized handle, and we already normalized 'h' above
254
256
if declared != h {
255
257
return nil, hit, fmt.Errorf("%w: %s != %s", ErrHandleMismatch, declared, h)
256
258
}
+2
atproto/identity/handle.go
+2
atproto/identity/handle.go
+5
-1
atproto/identity/identity.go
+5
-1
atproto/identity/identity.go
···
198
198
func (i *Identity) DeclaredHandle() (syntax.Handle, error) {
199
199
for _, u := range i.AlsoKnownAs {
200
200
if strings.HasPrefix(u, "at://") && len(u) > len("at://") {
201
-
return syntax.ParseHandle(u[5:])
201
+
hdl, err := syntax.ParseHandle(u[5:])
202
+
if err != nil {
203
+
continue
204
+
}
205
+
return hdl.Normalize(), nil
202
206
}
203
207
}
204
208
return "", ErrHandleNotDeclared
+70
atproto/identity/identity_test.go
+70
atproto/identity/identity_test.go
···
1
+
package identity
2
+
3
+
import (
4
+
"encoding/json"
5
+
"io"
6
+
"os"
7
+
"testing"
8
+
9
+
"github.com/stretchr/testify/assert"
10
+
)
11
+
12
+
// Tests parsing and normalizing handles from DID documents
13
+
func TestHandleExtraction(t *testing.T) {
14
+
assert := assert.New(t)
15
+
f, err := os.Open("testdata/did_plc_doc.json")
16
+
if err != nil {
17
+
t.Fatal(err)
18
+
}
19
+
defer f.Close()
20
+
21
+
docBytes, err := io.ReadAll(f)
22
+
if err != nil {
23
+
t.Fatal(err)
24
+
}
25
+
26
+
var doc DIDDocument
27
+
err = json.Unmarshal(docBytes, &doc)
28
+
assert.NoError(err)
29
+
30
+
{
31
+
ident := ParseIdentity(&doc)
32
+
hdl, err := ident.DeclaredHandle()
33
+
assert.NoError(err)
34
+
assert.Equal("atproto.com", hdl.String())
35
+
}
36
+
37
+
{
38
+
doc.AlsoKnownAs = []string{
39
+
"at://BLAH.com",
40
+
"at://other.org",
41
+
}
42
+
ident := ParseIdentity(&doc)
43
+
hdl, err := ident.DeclaredHandle()
44
+
assert.NoError(err)
45
+
assert.Equal("blah.com", hdl.String())
46
+
}
47
+
48
+
{
49
+
doc.AlsoKnownAs = []string{
50
+
"https://http.example.com",
51
+
"at://under_example_com",
52
+
"at://correct.EXAMPLE.com",
53
+
"at://other.example.com",
54
+
}
55
+
ident := ParseIdentity(&doc)
56
+
hdl, err := ident.DeclaredHandle()
57
+
assert.NoError(err)
58
+
assert.Equal("correct.example.com", hdl.String())
59
+
}
60
+
61
+
{
62
+
doc.AlsoKnownAs = []string{
63
+
"https://http.example.com",
64
+
}
65
+
ident := ParseIdentity(&doc)
66
+
_, err := ident.DeclaredHandle()
67
+
assert.Error(err)
68
+
assert.Equal("handle.invalid", ident.Handle.String())
69
+
}
70
+
}
+1
-1
atproto/identity/mock_directory.go
+1
-1
atproto/identity/mock_directory.go
+5
atproto/identity/mock_directory_test.go
+5
atproto/identity/mock_directory_test.go
···
65
65
66
66
_, err = c.ResolveDID(ctx, syntax.DID("did:plc:abc999"))
67
67
assert.ErrorIs(err, ErrDIDNotFound)
68
+
69
+
// handle lookups should be case-insensitive
70
+
_, err = c.ResolveHandle(ctx, syntax.Handle("handle.EXAMPLE.com"))
71
+
assert.NoError(err)
72
+
assert.Equal(id1.DID, did)
68
73
}
+2
atproto/identity/redisdir/redis_directory.go
+2
atproto/identity/redisdir/redis_directory.go
···
156
156
157
157
func (d *RedisDirectory) ResolveHandle(ctx context.Context, h syntax.Handle) (syntax.DID, error) {
158
158
start := time.Now()
159
+
h = h.Normalize()
159
160
if h.IsInvalidHandle() {
160
161
return "", fmt.Errorf("can not resolve handle: %w", identity.ErrInvalidHandle)
161
162
}
···
359
360
if err != nil {
360
361
return nil, hit, err
361
362
}
363
+
// NOTE: DeclaredHandle() returns a normalized handle, and we already normalized 'h' above
362
364
if declared != h {
363
365
return nil, hit, identity.ErrHandleMismatch
364
366
}
+3
cmd/bluepages/handlers.go
+3
cmd/bluepages/handlers.go
···
74
74
func (srv *Server) resolveIdentityFromHandle(c echo.Context, handle syntax.Handle) error {
75
75
ctx := c.Request().Context()
76
76
77
+
handle = handle.Normalize()
78
+
77
79
did, err := srv.dir.ResolveHandle(ctx, handle)
78
80
if err != nil && errors.Is(err, identity.ErrHandleNotFound) {
79
81
return c.JSON(404, GenericError{
···
110
112
}
111
113
112
114
ident := identity.ParseIdentity(&doc)
115
+
// NOTE: 'handle' was resolved above, and 'DeclaredHandle()' returns a normalized handle
113
116
declHandle, err := ident.DeclaredHandle()
114
117
if err != nil || declHandle != handle {
115
118
return c.JSON(400, GenericError{