···11+package identity
22+33+import (
44+ "context"
55+ "errors"
66+ "net"
77+ "net/http"
88+ "time"
99+1010+ "github.com/bluesky-social/indigo/atproto/syntax"
1111+)
1212+1313+// API for doing account lookups by DID or handle, with bi-directional verification handled automatically. Almost all atproto services and clients should use an implementation of this interface instead of resolving handles or DIDs separately
1414+//
1515+// Handles which fail to resolve, or don't match DID alsoKnownAs, are an error. DIDs which resolve but the handle does not resolve back to the DID return an Identity where the Handle is the special `handle.invalid` value.
1616+//
1717+// Some example implementations of this interface could be:
1818+// - basic direct resolution on every call
1919+// - local in-memory caching layer to reduce network hits
2020+// - API client, which just makes requests to PDS (or other remote service)
2121+// - client for shared network cache (eg, Redis)
2222+type Directory interface {
2323+ LookupHandle(ctx context.Context, h syntax.Handle) (*Identity, error)
2424+ LookupDID(ctx context.Context, d syntax.DID) (*Identity, error)
2525+ Lookup(ctx context.Context, i syntax.AtIdentifier) (*Identity, error)
2626+2727+ // Flushes any cache of the indicated identifier. If directory is not using caching, can ignore this.
2828+ Purge(ctx context.Context, i syntax.AtIdentifier) error
2929+}
3030+3131+// 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.
3232+var ErrHandleResolutionFailed = errors.New("handle resolution failed")
3333+3434+// Indicates that resolution process completed successfully, but handle does not exist. This is only returned when looking up a handle, not when looking up a DID.
3535+var ErrHandleNotFound = errors.New("handle not found")
3636+3737+// Indicates that resolution process completed successfully, handle mapped to a different DID. This is only returned when looking up a handle, not when looking up a DID.
3838+var ErrHandleMismatch = errors.New("handle/DID mismatch")
3939+4040+// Indicates that DID document did not include any handle ("alsoKnownAs"). This is only returned when looking up a handle, not when looking up a DID.
4141+var ErrHandleNotDeclared = errors.New("DID document did not declare a handle")
4242+4343+// Handle top-level domain (TLD) is one of the special "Reserved" suffixes, and not allowed for atproto use
4444+var ErrHandleReservedTLD = errors.New("handle top-level domain is disallowed")
4545+4646+// Indicates that resolution process completed successfully, but the DID does not exist.
4747+var ErrDIDNotFound = errors.New("DID not found")
4848+4949+// Indicates that DID resolution process failed. A wrapped error may provide more context.
5050+var ErrDIDResolutionFailed = errors.New("DID resolution failed")
5151+5252+// Indicates that DID document did not include a public key with the specified ID
5353+var ErrKeyNotDeclared = errors.New("DID document did not declare a relevant public key")
5454+5555+var DefaultPLCURL = "https://plc.directory"
5656+5757+// Returns a reasonable Directory implementation for applications
5858+func DefaultDirectory() Directory {
5959+ base := BaseDirectory{
6060+ PLCURL: DefaultPLCURL,
6161+ HTTPClient: http.Client{
6262+ Timeout: time.Second * 10,
6363+ Transport: &http.Transport{
6464+ // would want this around 100ms for services doing lots of handle resolution. Impacts PLC connections as well, but not too bad.
6565+ IdleConnTimeout: time.Millisecond * 1000,
6666+ MaxIdleConns: 100,
6767+ },
6868+ },
6969+ Resolver: net.Resolver{
7070+ Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
7171+ d := net.Dialer{Timeout: time.Second * 3}
7272+ return d.DialContext(ctx, network, address)
7373+ },
7474+ },
7575+ TryAuthoritativeDNS: true,
7676+ // primary Bluesky PDS instance only supports HTTP resolution method
7777+ SkipDNSDomainSuffixes: []string{".bsky.social"},
7878+ }
7979+ cached := NewCacheDirectory(&base, 250_000, time.Hour*24, time.Minute*2, time.Minute*5)
8080+ return &cached
8181+}
-75
atproto/identity/identity.go
···11package identity
2233import (
44- "context"
55- "errors"
64 "fmt"
77- "net"
88- "net/http"
95 "net/url"
106 "strings"
1111- "time"
127138 "github.com/bluesky-social/indigo/atproto/crypto"
149 "github.com/bluesky-social/indigo/atproto/syntax"
15101611 "github.com/mr-tron/base58"
1712)
1818-1919-// API for doing account lookups by DID or handle, with bi-directional verification handled automatically. Almost all atproto services and clients should use an implementation of this interface instead of resolving handles or DIDs separately
2020-//
2121-// Handles which fail to resolve, or don't match DID alsoKnownAs, are an error. DIDs which resolve but the handle does not resolve back to the DID return an Identity where the Handle is the special `handle.invalid` value.
2222-//
2323-// Some example implementations of this interface could be:
2424-// - basic direct resolution on every call
2525-// - local in-memory caching layer to reduce network hits
2626-// - API client, which just makes requests to PDS (or other remote service)
2727-// - client for shared network cache (eg, Redis)
2828-type Directory interface {
2929- LookupHandle(ctx context.Context, h syntax.Handle) (*Identity, error)
3030- LookupDID(ctx context.Context, d syntax.DID) (*Identity, error)
3131- Lookup(ctx context.Context, i syntax.AtIdentifier) (*Identity, error)
3232-3333- // Flushes any cache of the indicated identifier. If directory is not using caching, can ignore this.
3434- Purge(ctx context.Context, i syntax.AtIdentifier) error
3535-}
3636-3737-// 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.
3838-var ErrHandleResolutionFailed = errors.New("handle resolution failed")
3939-4040-// Indicates that resolution process completed successfully, but handle does not exist. This is only returned when looking up a handle, not when looking up a DID.
4141-var ErrHandleNotFound = errors.New("handle not found")
4242-4343-// Indicates that resolution process completed successfully, handle mapped to a different DID. This is only returned when looking up a handle, not when looking up a DID.
4444-var ErrHandleMismatch = errors.New("handle/DID mismatch")
4545-4646-// Indicates that DID document did not include any handle ("alsoKnownAs"). This is only returned when looking up a handle, not when looking up a DID.
4747-var ErrHandleNotDeclared = errors.New("DID document did not declare a handle")
4848-4949-// Handle top-level domain (TLD) is one of the special "Reserved" suffixes, and not allowed for atproto use
5050-var ErrHandleReservedTLD = errors.New("handle top-level domain is disallowed")
5151-5252-// Indicates that resolution process completed successfully, but the DID does not exist.
5353-var ErrDIDNotFound = errors.New("DID not found")
5454-5555-// Indicates that DID resolution process failed. A wrapped error may provide more context.
5656-var ErrDIDResolutionFailed = errors.New("DID resolution failed")
5757-5858-// Indicates that DID document did not include a public key with the specified ID
5959-var ErrKeyNotDeclared = errors.New("DID document did not declare a relevant public key")
6060-6161-var DefaultPLCURL = "https://plc.directory"
6262-6363-// Returns a reasonable Directory implementation for applications
6464-func DefaultDirectory() Directory {
6565- base := BaseDirectory{
6666- PLCURL: DefaultPLCURL,
6767- HTTPClient: http.Client{
6868- Timeout: time.Second * 10,
6969- Transport: &http.Transport{
7070- // would want this around 100ms for services doing lots of handle resolution. Impacts PLC connections as well, but not too bad.
7171- IdleConnTimeout: time.Millisecond * 1000,
7272- MaxIdleConns: 100,
7373- },
7474- },
7575- Resolver: net.Resolver{
7676- Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
7777- d := net.Dialer{Timeout: time.Second * 3}
7878- return d.DialContext(ctx, network, address)
7979- },
8080- },
8181- TryAuthoritativeDNS: true,
8282- // primary Bluesky PDS instance only supports HTTP resolution method
8383- SkipDNSDomainSuffixes: []string{".bsky.social"},
8484- }
8585- cached := NewCacheDirectory(&base, 250_000, time.Hour*24, time.Minute*2, time.Minute*5)
8686- return &cached
8787-}
88138914// Represents an atproto identity. Could be a regular user account, or a service account (eg, feed generator)
9015type Identity struct {