Skip to content

Commit

Permalink
identity package tweaks (#955)
Browse files Browse the repository at this point in the history
- add user-agent
- ensure we drain HTTP requests in more code paths (allows
connections/streams to be re-used more efficiently)
  • Loading branch information
bnewbold authored Feb 25, 2025
2 parents 8af67f5 + e952d24 commit dd179c3
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 9 deletions.
4 changes: 3 additions & 1 deletion atproto/identity/base_directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ type BaseDirectory struct {
//
// The intended use-case for this flag is as an optimization for services which do not care about handles, but still want to use the `Directory` interface (instead of `ResolveDID`). For example, relay implementations, or services validating inter-service auth requests.
SkipHandleVerification bool
// User-Agent header for HTTP requests. Optional (ignored if empty string).
UserAgent string
}

var _ Directory = (*BaseDirectory)(nil)
Expand Down Expand Up @@ -107,7 +109,7 @@ func (d *BaseDirectory) Lookup(ctx context.Context, a syntax.AtIdentifier) (*Ide
return nil, fmt.Errorf("at-identifier neither a Handle nor a DID")
}

func (d *BaseDirectory) Purge(ctx context.Context, a syntax.AtIdentifier) error {
func (d *BaseDirectory) Purge(ctx context.Context, atid syntax.AtIdentifier) error {
// BaseDirectory itself does not implement caching
return nil
}
6 changes: 3 additions & 3 deletions atproto/identity/cache_directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,14 @@ func (d *CacheDirectory) Lookup(ctx context.Context, a syntax.AtIdentifier) (*Id
return nil, fmt.Errorf("at-identifier neither a Handle nor a DID")
}

func (d *CacheDirectory) Purge(ctx context.Context, a syntax.AtIdentifier) error {
handle, err := a.AsHandle()
func (d *CacheDirectory) Purge(ctx context.Context, atid syntax.AtIdentifier) error {
handle, err := atid.AsHandle()
if nil == err { // if not an error, is a handle
handle = handle.Normalize()
d.handleCache.Remove(handle)
return nil
}
did, err := a.AsDID()
did, err := atid.AsDID()
if nil == err { // if not an error, is a DID
d.identityCache.Remove(did)
return nil
Expand Down
12 changes: 12 additions & 0 deletions atproto/identity/did.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ func (d *BaseDirectory) resolveDIDWeb(ctx context.Context, did syntax.DID) ([]by
if err != nil {
return nil, fmt.Errorf("constructing HTTP request for did:web resolution: %w", err)
}
if d.UserAgent != "" {
req.Header.Set("User-Agent", d.UserAgent)
}

resp, err := d.HTTPClient.Do(req)

// look for NXDOMAIN
Expand All @@ -112,9 +116,11 @@ func (d *BaseDirectory) resolveDIDWeb(ctx context.Context, did syntax.DID) ([]by
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusNotFound {
io.Copy(io.Discard, resp.Body)
return nil, fmt.Errorf("%w: did:web HTTP status 404", ErrDIDNotFound)
}
if resp.StatusCode != http.StatusOK {
io.Copy(io.Discard, resp.Body)
return nil, fmt.Errorf("%w: did:web HTTP status %d", ErrDIDResolutionFailed, resp.StatusCode)
}

Expand All @@ -141,15 +147,21 @@ func (d *BaseDirectory) resolveDIDPLC(ctx context.Context, did syntax.DID) ([]by
if err != nil {
return nil, fmt.Errorf("constructing HTTP request for did:plc resolution: %w", err)
}
if d.UserAgent != "" {
req.Header.Set("User-Agent", d.UserAgent)
}

resp, err := d.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("%w: PLC directory lookup: %w", ErrDIDResolutionFailed, err)
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusNotFound {
io.Copy(io.Discard, resp.Body)
return nil, fmt.Errorf("%w: PLC directory 404", ErrDIDNotFound)
}
if resp.StatusCode != http.StatusOK {
io.Copy(io.Discard, resp.Body)
return nil, fmt.Errorf("%w: PLC directory status %d", ErrDIDResolutionFailed, resp.StatusCode)
}

Expand Down
5 changes: 4 additions & 1 deletion atproto/identity/directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"time"

"github.com/bluesky-social/indigo/atproto/syntax"

"github.com/carlmjohnson/versioninfo"
)

// Ergonomic interface for atproto identity lookup, by DID or handle.
Expand All @@ -27,7 +29,7 @@ type Directory interface {
Lookup(ctx context.Context, atid syntax.AtIdentifier) (*Identity, error)

// Flushes any cache of the indicated identifier. If directory is not using caching, can ignore this.
Purge(ctx context.Context, i syntax.AtIdentifier) error
Purge(ctx context.Context, atid syntax.AtIdentifier) error
}

// Indicates that handle resolution failed. A wrapped error may provide more context. This is only returned when looking up a handle, not when looking up a DID.
Expand Down Expand Up @@ -80,6 +82,7 @@ func DefaultDirectory() Directory {
TryAuthoritativeDNS: true,
// primary Bluesky PDS instance only supports HTTP resolution method
SkipDNSDomainSuffixes: []string{".bsky.social"},
UserAgent: "indigo-identity/" + versioninfo.Short(),
}
cached := NewCacheDirectory(&base, 250_000, time.Hour*24, time.Minute*2, time.Minute*5)
return &cached
Expand Down
13 changes: 9 additions & 4 deletions atproto/identity/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ func (d *BaseDirectory) ResolveHandleWellKnown(ctx context.Context, handle synta
if err != nil {
return "", fmt.Errorf("constructing HTTP request for handle resolution: %w", err)
}
if d.UserAgent != "" {
req.Header.Set("User-Agent", d.UserAgent)
}

resp, err := d.HTTPClient.Do(req)
if err != nil {
Expand All @@ -144,17 +147,19 @@ func (d *BaseDirectory) ResolveHandleWellKnown(ctx context.Context, handle synta
return "", fmt.Errorf("%w: HTTP well-known request error: %w", ErrHandleResolutionFailed, err)
}
defer resp.Body.Close()
if resp.ContentLength > 2048 {
// NOTE: intentionally not draining body
return "", fmt.Errorf("%w: HTTP well-known body too large for %s", ErrHandleResolutionFailed, handle)
}
if resp.StatusCode == http.StatusNotFound {
io.Copy(io.Discard, resp.Body)
return "", fmt.Errorf("%w: HTTP 404 for %s", ErrHandleNotFound, handle)
}
if resp.StatusCode != http.StatusOK {
io.Copy(io.Discard, resp.Body)
return "", fmt.Errorf("%w: HTTP well-known status %d for %s", ErrHandleResolutionFailed, resp.StatusCode, handle)
}

if resp.ContentLength > 2048 {
return "", fmt.Errorf("%w: HTTP well-known body too large for %s", ErrHandleResolutionFailed, handle)
}

b, err := io.ReadAll(io.LimitReader(resp.Body, 2048))
if err != nil {
return "", fmt.Errorf("%w: HTTP well-known body read for %s: %w", ErrHandleResolutionFailed, handle, err)
Expand Down

0 comments on commit dd179c3

Please sign in to comment.