tangled
alpha
login
or
join now
willdot.net
/
cocoon
forked from
hailey.at/cocoon
0
fork
atom
An atproto PDS written in Go
0
fork
atom
overview
issues
pulls
pipelines
refactor identity package
hailey.at
7 months ago
6f90d8a4
5f0d713f
+89
-59
2 changed files
expand all
collapse all
unified
split
identity
identity.go
passport.go
+73
-54
identity/identity.go
···
13
13
"github.com/bluesky-social/indigo/util"
14
14
)
15
15
16
16
-
func ResolveHandle(ctx context.Context, cli *http.Client, handle string) (string, error) {
17
17
-
if cli == nil {
18
18
-
cli = util.RobustHTTPClient()
19
19
-
}
20
20
-
21
21
-
var did string
22
22
-
23
23
-
_, err := syntax.ParseHandle(handle)
16
16
+
func ResolveHandleFromTXT(ctx context.Context, handle string) (string, error) {
17
17
+
name := fmt.Sprintf("_atproto.%s", handle)
18
18
+
recs, err := net.LookupTXT(name)
24
19
if err != nil {
25
25
-
return "", err
20
20
+
return "", fmt.Errorf("handle could not be resolved via txt: %w", err)
26
21
}
27
22
28
28
-
recs, err := net.LookupTXT(fmt.Sprintf("_atproto.%s", handle))
29
29
-
if err == nil {
30
30
-
for _, rec := range recs {
31
31
-
if strings.HasPrefix(rec, "did=") {
32
32
-
did = strings.Split(rec, "did=")[1]
33
33
-
break
23
23
+
for _, rec := range recs {
24
24
+
if strings.HasPrefix(rec, "did=") {
25
25
+
maybeDid := strings.Split(rec, "did=")[1]
26
26
+
if _, err := syntax.ParseDID(maybeDid); err == nil {
27
27
+
return maybeDid, nil
34
28
}
35
29
}
36
36
-
} else {
37
37
-
fmt.Printf("erorr getting txt records: %v\n", err)
38
30
}
39
31
40
40
-
if did == "" {
41
41
-
req, err := http.NewRequestWithContext(
42
42
-
ctx,
43
43
-
"GET",
44
44
-
fmt.Sprintf("https://%s/.well-known/atproto-did", handle),
45
45
-
nil,
46
46
-
)
47
47
-
if err != nil {
48
48
-
return "", nil
49
49
-
}
32
32
+
return "", fmt.Errorf("handle could not be resolved via txt: no record found")
33
33
+
}
50
34
51
51
-
resp, err := http.DefaultClient.Do(req)
52
52
-
if err != nil {
53
53
-
return "", nil
54
54
-
}
55
55
-
defer resp.Body.Close()
35
35
+
func ResolveHandleFromWellKnown(ctx context.Context, cli *http.Client, handle string) (string, error) {
36
36
+
ustr := fmt.Sprintf("https://%s/.well=known/atproto-did", handle)
37
37
+
req, err := http.NewRequestWithContext(
38
38
+
ctx,
39
39
+
"GET",
40
40
+
ustr,
41
41
+
nil,
42
42
+
)
43
43
+
if err != nil {
44
44
+
return "", fmt.Errorf("handle could not be resolved via web: %w", err)
45
45
+
}
56
46
57
57
-
if resp.StatusCode != http.StatusOK {
58
58
-
io.Copy(io.Discard, resp.Body)
59
59
-
return "", fmt.Errorf("unable to resolve handle")
60
60
-
}
47
47
+
resp, err := cli.Do(req)
48
48
+
if err != nil {
49
49
+
return "", fmt.Errorf("handle could not be resolved via web: %w", err)
50
50
+
}
51
51
+
defer resp.Body.Close()
61
52
62
62
-
b, err := io.ReadAll(resp.Body)
63
63
-
if err != nil {
64
64
-
return "", err
65
65
-
}
53
53
+
b, err := io.ReadAll(resp.Body)
54
54
+
if err != nil {
55
55
+
return "", fmt.Errorf("handle could not be resolved via web: %w", err)
56
56
+
}
66
57
67
67
-
maybeDid := string(b)
58
58
+
if resp.StatusCode != http.StatusOK {
59
59
+
return "", fmt.Errorf("handle could not be resolved via web: invalid status code %d", resp.StatusCode)
60
60
+
}
68
61
69
69
-
if _, err := syntax.ParseDID(maybeDid); err != nil {
70
70
-
return "", fmt.Errorf("unable to resolve handle")
71
71
-
}
62
62
+
maybeDid := string(b)
72
63
73
73
-
did = maybeDid
64
64
+
if _, err := syntax.ParseDID(maybeDid); err != nil {
65
65
+
return "", fmt.Errorf("handle could not be resolved via web: invalid did in document")
74
66
}
75
67
76
76
-
return did, nil
68
68
+
return maybeDid, nil
77
69
}
78
70
79
79
-
func FetchDidDoc(ctx context.Context, cli *http.Client, did string) (*DidDoc, error) {
71
71
+
func ResolveHandle(ctx context.Context, cli *http.Client, handle string) (string, error) {
80
72
if cli == nil {
81
73
cli = util.RobustHTTPClient()
82
74
}
83
75
84
84
-
var ustr string
76
76
+
_, err := syntax.ParseHandle(handle)
77
77
+
if err != nil {
78
78
+
return "", err
79
79
+
}
80
80
+
81
81
+
if maybeDidFromTxt, err := ResolveHandleFromTXT(ctx, handle); err == nil {
82
82
+
return maybeDidFromTxt, nil
83
83
+
}
84
84
+
85
85
+
if maybeDidFromWeb, err := ResolveHandleFromWellKnown(ctx, cli, handle); err == nil {
86
86
+
return maybeDidFromWeb, nil
87
87
+
}
88
88
+
89
89
+
return "", fmt.Errorf("handle could not be resolved")
90
90
+
}
91
91
+
92
92
+
func DidToDocUrl(did string) (string, error) {
85
93
if strings.HasPrefix(did, "did:plc:") {
86
86
-
ustr = fmt.Sprintf("https://plc.directory/%s", did)
94
94
+
return fmt.Sprintf("https://plc.directory/%s", did), nil
87
95
} else if strings.HasPrefix(did, "did:web:") {
88
88
-
ustr = fmt.Sprintf("https://%s/.well-known/did.json", strings.TrimPrefix(did, "did:web:"))
96
96
+
return fmt.Sprintf("https://%s/.well-known/did.json", strings.TrimPrefix(did, "did:web:")), nil
89
97
} else {
90
90
-
return nil, fmt.Errorf("did was not a supported did type")
98
98
+
return "", fmt.Errorf("did was not a supported did type")
99
99
+
}
100
100
+
}
101
101
+
102
102
+
func FetchDidDoc(ctx context.Context, cli *http.Client, did string) (*DidDoc, error) {
103
103
+
if cli == nil {
104
104
+
cli = util.RobustHTTPClient()
105
105
+
}
106
106
+
107
107
+
ustr, err := DidToDocUrl(did)
108
108
+
if err != nil {
109
109
+
return nil, err
91
110
}
92
111
93
112
req, err := http.NewRequestWithContext(ctx, "GET", ustr, nil)
···
95
114
return nil, err
96
115
}
97
116
98
98
-
resp, err := http.DefaultClient.Do(req)
117
117
+
resp, err := cli.Do(req)
99
118
if err != nil {
100
119
return nil, err
101
120
}
···
103
122
104
123
if resp.StatusCode != 200 {
105
124
io.Copy(io.Discard, resp.Body)
106
106
-
return nil, fmt.Errorf("could not find identity in plc registry")
125
125
+
return nil, fmt.Errorf("unable to find did doc at url. did: %s. url: %s", did, ustr)
107
126
}
108
127
109
128
var diddoc DidDoc
···
127
146
return nil, err
128
147
}
129
148
130
130
-
resp, err := http.DefaultClient.Do(req)
149
149
+
resp, err := cli.Do(req)
131
150
if err != nil {
132
151
return nil, err
133
152
}
+16
-5
identity/passport.go
···
19
19
type Passport struct {
20
20
h *http.Client
21
21
bc BackingCache
22
22
-
lk sync.Mutex
22
22
+
mu sync.RWMutex
23
23
}
24
24
25
25
func NewPassport(h *http.Client, bc BackingCache) *Passport {
···
30
30
return &Passport{
31
31
h: h,
32
32
bc: bc,
33
33
-
lk: sync.Mutex{},
34
33
}
35
34
}
36
35
···
38
37
skipCache, _ := ctx.Value("skip-cache").(bool)
39
38
40
39
if !skipCache {
40
40
+
p.mu.RLock()
41
41
cached, ok := p.bc.GetDoc(did)
42
42
+
p.mu.RUnlock()
43
43
+
42
44
if ok {
43
45
return cached, nil
44
46
}
45
47
}
46
48
47
47
-
p.lk.Lock() // this is pretty pathetic, and i should rethink this. but for now, fuck it
48
48
-
defer p.lk.Unlock()
49
49
-
49
49
+
// TODO: should coalesce requests here
50
50
doc, err := FetchDidDoc(ctx, p.h, did)
51
51
if err != nil {
52
52
return nil, err
53
53
}
54
54
55
55
+
p.mu.Lock()
55
56
p.bc.PutDoc(did, doc)
57
57
+
p.mu.Unlock()
56
58
57
59
return doc, nil
58
60
}
···
61
63
skipCache, _ := ctx.Value("skip-cache").(bool)
62
64
63
65
if !skipCache {
66
66
+
p.mu.RLock()
64
67
cached, ok := p.bc.GetDid(handle)
68
68
+
p.mu.RUnlock()
69
69
+
65
70
if ok {
66
71
return cached, nil
67
72
}
···
72
77
return "", err
73
78
}
74
79
80
80
+
p.mu.Lock()
75
81
p.bc.PutDid(handle, did)
82
82
+
p.mu.Unlock()
76
83
77
84
return did, nil
78
85
}
79
86
80
87
func (p *Passport) BustDoc(ctx context.Context, did string) error {
88
88
+
p.mu.Lock()
89
89
+
defer p.mu.Unlock()
81
90
return p.bc.BustDoc(did)
82
91
}
83
92
84
93
func (p *Passport) BustDid(ctx context.Context, handle string) error {
94
94
+
p.mu.Lock()
95
95
+
defer p.mu.Unlock()
85
96
return p.bc.BustDid(handle)
86
97
}