Live video on the AT Protocol
at eli/oproxy-fix 124 lines 2.6 kB view raw
1package oproxy 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 15// mostly borrowed from github.com/haileyok/atproto-oauth-golang, MIT license 16func ResolveHandle(ctx context.Context, handle string) (string, error) { 17 var did string 18 19 _, err := syntax.ParseHandle(handle) 20 if err != nil { 21 return "", err 22 } 23 24 recs, err := net.LookupTXT(fmt.Sprintf("_atproto.%s", handle)) 25 if err == nil { 26 for _, rec := range recs { 27 if strings.HasPrefix(rec, "did=") { 28 did = strings.Split(rec, "did=")[1] 29 break 30 } 31 } 32 } 33 34 if did == "" { 35 req, err := http.NewRequestWithContext( 36 ctx, 37 "GET", 38 fmt.Sprintf("https://%s/.well-known/atproto-did", handle), 39 nil, 40 ) 41 if err != nil { 42 return "", err 43 } 44 45 resp, err := http.DefaultClient.Do(req) 46 if err != nil { 47 return "", err 48 } 49 defer resp.Body.Close() 50 51 if resp.StatusCode != http.StatusOK { 52 io.Copy(io.Discard, resp.Body) 53 return "", fmt.Errorf("unable to resolve handle") 54 } 55 56 b, err := io.ReadAll(resp.Body) 57 if err != nil { 58 return "", err 59 } 60 61 maybeDid := string(b) 62 63 if _, err := syntax.ParseDID(maybeDid); err != nil { 64 return "", fmt.Errorf("unable to resolve handle") 65 } 66 67 did = maybeDid 68 } 69 70 return did, nil 71} 72 73func ResolveService(ctx context.Context, did string) (string, error) { 74 type Identity struct { 75 Service []struct { 76 ID string `json:"id"` 77 Type string `json:"type"` 78 ServiceEndpoint string `json:"serviceEndpoint"` 79 } `json:"service"` 80 } 81 82 var ustr string 83 if strings.HasPrefix(did, "did:plc:") { 84 ustr = fmt.Sprintf("https://plc.directory/%s", did) 85 } else if strings.HasPrefix(did, "did:web:") { 86 ustr = fmt.Sprintf("https://%s/.well-known/did.json", strings.TrimPrefix(did, "did:web:")) 87 } else { 88 return "", fmt.Errorf("did was not a supported did type") 89 } 90 91 req, err := http.NewRequestWithContext(ctx, "GET", ustr, nil) 92 if err != nil { 93 return "", err 94 } 95 96 resp, err := http.DefaultClient.Do(req) 97 if err != nil { 98 return "", err 99 } 100 defer resp.Body.Close() 101 102 if resp.StatusCode != 200 { 103 io.Copy(io.Discard, resp.Body) 104 return "", fmt.Errorf("could not find identity in plc registry") 105 } 106 107 var identity Identity 108 if err := json.NewDecoder(resp.Body).Decode(&identity); err != nil { 109 return "", err 110 } 111 112 var service string 113 for _, svc := range identity.Service { 114 if svc.ID == "#atproto_pds" { 115 service = svc.ServiceEndpoint 116 } 117 } 118 119 if service == "" { 120 return "", fmt.Errorf("could not find atproto_pds service in identity services") 121 } 122 123 return service, nil 124}