this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

identity: add simple authoritative DNS lookup

+68 -12
+2
atproto/identity/base_directory.go
··· 17 17 HTTPClient http.Client 18 18 // DNS resolver used for DNS handle resolution. Calling code can use a custom Dialer to query against a specific DNS server, or re-implement the interface for even more control over the resolution process 19 19 Resolver net.Resolver 20 + // when doing DNS handle resolution, should this resolver attempt re-try against an authoritative nameserver if the first TXT lookup fails? 21 + TryAuthoritativeDNS bool 20 22 } 21 23 22 24 var _ Directory = (*BaseDirectory)(nil)
+65 -12
atproto/identity/handle.go
··· 8 8 "net" 9 9 "net/http" 10 10 "strings" 11 + "time" 11 12 12 13 "github.com/bluesky-social/indigo/atproto/syntax" 13 14 ) 14 15 16 + func parseTXTResp(res []string) (syntax.DID, error) { 17 + for _, s := range res { 18 + if strings.HasPrefix(s, "did=") { 19 + parts := strings.SplitN(s, "=", 2) 20 + did, err := syntax.ParseDID(parts[1]) 21 + if err != nil { 22 + return "", fmt.Errorf("invalid DID in handle DNS record: %w", err) 23 + } 24 + return did, nil 25 + } 26 + } 27 + return "", ErrHandleNotFound 28 + } 29 + 15 30 // Does not cross-verify, only does the handle resolution step. 16 31 func (d *BaseDirectory) ResolveHandleDNS(ctx context.Context, handle syntax.Handle) (syntax.DID, error) { 17 32 res, err := d.Resolver.LookupTXT(ctx, "_atproto."+handle.String()) 18 - // look for NXDOMAIN 33 + // check for NXDOMAIN 19 34 var dnsErr *net.DNSError 20 35 if errors.As(err, &dnsErr) { 21 36 if dnsErr.IsNotFound { ··· 25 40 if err != nil { 26 41 return "", fmt.Errorf("handle DNS resolution failed: %w", err) 27 42 } 43 + return parseTXTResp(res) 44 + } 28 45 29 - for _, s := range res { 30 - if strings.HasPrefix(s, "did=") { 31 - parts := strings.SplitN(s, "=", 2) 32 - did, err := syntax.ParseDID(parts[1]) 33 - if err != nil { 34 - return "", fmt.Errorf("invalid DID in handle DNS record: %w", err) 46 + // this is a variant of ResolveHandleDNS which first does an authoritative nameserver lookup, then queries there 47 + func (d *BaseDirectory) ResolveHandleDNSAuthoritative(ctx context.Context, handle syntax.Handle) (syntax.DID, error) { 48 + // lookup nameserver using configured resolver 49 + resNS, err := d.Resolver.LookupNS(ctx, handle.String()) 50 + // check for NXDOMAIN 51 + var dnsErr *net.DNSError 52 + if errors.As(err, &dnsErr) { 53 + if dnsErr.IsNotFound { 54 + return "", ErrHandleNotFound 55 + } 56 + } 57 + if err != nil { 58 + return "", fmt.Errorf("handle DNS resolution failed: %w", err) 59 + } 60 + if len(resNS) == 0 { 61 + return "", ErrHandleNotFound 62 + } 63 + ns := resNS[0].Host 64 + if !strings.Contains(ns, ":") { 65 + ns = ns + ":53" 66 + } 67 + 68 + // create a custom resolver to use the specific nameserver for TXT lookup 69 + resolver := &net.Resolver{ 70 + PreferGo: true, 71 + Dial: func(ctx context.Context, network, address string) (net.Conn, error) { 72 + rd := net.Dialer{ 73 + Timeout: time.Second * 5, 35 74 } 36 - return did, nil 75 + return rd.DialContext(ctx, network, ns) 76 + }, 77 + } 78 + res, err := resolver.LookupTXT(ctx, "_atproto."+handle.String()) 79 + // check for NXDOMAIN 80 + if errors.As(err, &dnsErr) { 81 + if dnsErr.IsNotFound { 82 + return "", ErrHandleNotFound 37 83 } 38 84 } 39 - return "", ErrHandleNotFound 85 + if err != nil { 86 + return "", fmt.Errorf("handle DNS resolution failed: %w", err) 87 + } 88 + return parseTXTResp(res) 40 89 } 41 90 42 91 func (d *BaseDirectory) ResolveHandleWellKnown(ctx context.Context, handle syntax.Handle) (syntax.DID, error) { ··· 47 96 48 97 resp, err := d.HTTPClient.Do(req) 49 98 if err != nil { 50 - // look for NXDOMAIN 99 + // check for NXDOMAIN 51 100 var dnsErr *net.DNSError 52 101 if errors.As(err, &dnsErr) { 53 102 if dnsErr.IsNotFound { ··· 75 124 func (d *BaseDirectory) ResolveHandle(ctx context.Context, handle syntax.Handle) (syntax.DID, error) { 76 125 // TODO: *could* do resolution in parallel, but expecting that sequential is sufficient to start 77 126 did, dnsErr := d.ResolveHandleDNS(ctx, handle) 78 - if dnsErr == nil { 127 + if dnsErr == ErrHandleNotFound && d.TryAuthoritativeDNS { 128 + // try harder with authoritative lookup 129 + did, dnsErr = d.ResolveHandleDNSAuthoritative(ctx, handle) 130 + } 131 + if nil == dnsErr { // if *not* an error 79 132 return did, nil 80 133 } 81 134 did, httpErr := d.ResolveHandleWellKnown(ctx, handle) 82 - if httpErr == nil { 135 + if nil == httpErr { // if *not* an error 83 136 return did, nil 84 137 } 85 138
+1
atproto/identity/identity.go
··· 60 60 return d.DialContext(ctx, network, address) 61 61 }, 62 62 }, 63 + TryAuthoritativeDNS: true, 63 64 } 64 65 cached := NewCacheDirectory(&base, 10000, time.Hour*24, time.Minute*2) 65 66 return &cached