this repo has no description
1package main
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "io"
8 "net"
9 "net/http"
10 "strings"
11
12 "github.com/bluesky-social/indigo/atproto/syntax"
13)
14
15func resolveHandle(ctx context.Context, handle string) (string, error) {
16 var did string
17
18 _, err := syntax.ParseHandle(handle)
19 if err != nil {
20 return "", err
21 }
22
23 recs, err := net.LookupTXT(fmt.Sprintf("_atproto.%s", handle))
24 if err != nil {
25 return "", err
26 }
27
28 for _, rec := range recs {
29 if strings.HasPrefix(rec, "did=") {
30 did = strings.Split(rec, "did=")[1]
31 break
32 }
33 }
34
35 if did == "" {
36 req, err := http.NewRequestWithContext(
37 ctx,
38 "GET",
39 fmt.Sprintf("https://%s/.well-known/atproto-did", handle),
40 nil,
41 )
42 if err != nil {
43 return "", err
44 }
45
46 resp, err := http.DefaultClient.Do(req)
47 if err != nil {
48 return "", err
49 }
50 defer resp.Body.Close()
51
52 if resp.StatusCode != http.StatusOK {
53 io.Copy(io.Discard, resp.Body)
54 return "", fmt.Errorf("unable to resolve handle")
55 }
56
57 b, err := io.ReadAll(resp.Body)
58 if err != nil {
59 return "", err
60 }
61
62 maybeDid := string(b)
63
64 if _, err := syntax.ParseDID(maybeDid); err != nil {
65 return "", fmt.Errorf("unable to resolve handle")
66 }
67
68 did = maybeDid
69 }
70
71 return did, nil
72}
73
74func resolveService(ctx context.Context, did string) (string, error) {
75 type Identity struct {
76 Service []struct {
77 ID string `json:"id"`
78 Type string `json:"type"`
79 ServiceEndpoint string `json:"serviceEndpoint"`
80 } `json:"service"`
81 }
82
83 var ustr string
84 if strings.HasPrefix(did, "did:plc:") {
85 ustr = fmt.Sprintf("https://plc.directory/%s", did)
86 } else if strings.HasPrefix(did, "did:web:") {
87 ustr = fmt.Sprintf("https://%s/.well-known/did.json", strings.TrimPrefix(did, "did:web:"))
88 } else {
89 return "", fmt.Errorf("did was not a supported did type")
90 }
91
92 req, err := http.NewRequestWithContext(ctx, "GET", ustr, nil)
93 if err != nil {
94 return "", err
95 }
96
97 resp, err := http.DefaultClient.Do(req)
98 if err != nil {
99 return "", err
100 }
101 defer resp.Body.Close()
102
103 if resp.StatusCode != 200 {
104 io.Copy(io.Discard, resp.Body)
105 return "", fmt.Errorf("could not find identity in plc registry")
106 }
107
108 var identity Identity
109 if err := json.NewDecoder(resp.Body).Decode(&identity); err != nil {
110 return "", err
111 }
112
113 var service string
114 for _, svc := range identity.Service {
115 if svc.ID == "#atproto_pds" {
116 service = svc.ServiceEndpoint
117 }
118 }
119
120 if service == "" {
121 return "", fmt.Errorf("could not find atproto_pds service in identity services")
122 }
123
124 return service, nil
125}