diff --git a/identity/identity.go b/identity/identity.go --- a/identity/identity.go +++ b/identity/identity.go @@ -10,9 +10,14 @@ "net/http" "strings" "github.com/bluesky-social/indigo/atproto/syntax" + "github.com/bluesky-social/indigo/util" ) -func ResolveHandle(ctx context.Context, handle string) (string, error) { +func ResolveHandle(ctx context.Context, cli *http.Client, handle string) (string, error) { + if cli == nil { + cli = util.RobustHTTPClient() + } + var did string _, err := syntax.ParseHandle(handle) @@ -71,63 +76,11 @@ return did, nil } -type DidDoc struct { - Context []string `json:"@context"` - Id string `json:"id"` - AlsoKnownAs []string `json:"alsoKnownAs"` - VerificationMethods []DidDocVerificationMethod `json:"verificationMethods"` - Service []DidDocService `json:"service"` -} - -type DidDocVerificationMethod struct { - Id string `json:"id"` - Type string `json:"type"` - Controller string `json:"controller"` - PublicKeyMultibase string `json:"publicKeyMultibase"` -} - -type DidDocService struct { - Id string `json:"id"` - Type string `json:"type"` - ServiceEndpoint string `json:"serviceEndpoint"` -} - -type DidData struct { - Did string `json:"did"` - VerificationMethods map[string]string `json:"verificationMethods"` - RotationKeys []string `json:"rotationKeys"` - AlsoKnownAs []string `json:"alsoKnownAs"` - Services map[string]OperationService `json:"services"` -} - -type OperationService struct { - Type string `json:"type"` - Endpoint string `json:"endpoint"` -} +func FetchDidDoc(ctx context.Context, cli *http.Client, did string) (*DidDoc, error) { + if cli == nil { + cli = util.RobustHTTPClient() + } -type DidLog []DidLogEntry - -type DidLogEntry struct { - Sig string `json:"sig"` - Prev *string `json:"prev"` - Type string `json:"string"` - Services map[string]OperationService `json:"services"` - AlsoKnownAs []string `json:"alsoKnownAs"` - RotationKeys []string `json:"rotationKeys"` - VerificationMethods map[string]string `json:"verificationMethods"` -} - -type DidAuditEntry struct { - Did string `json:"did"` - Operation DidLogEntry `json:"operation"` - Cid string `json:"cid"` - Nullified bool `json:"nullified"` - CreatedAt string `json:"createdAt"` -} - -type DidAuditLog []DidAuditEntry - -func FetchDidDoc(ctx context.Context, did string) (*DidDoc, error) { var ustr string if strings.HasPrefix(did, "did:plc:") { ustr = fmt.Sprintf("https://plc.directory/%s", did) @@ -161,7 +114,11 @@ return &diddoc, nil } -func FetchDidData(ctx context.Context, did string) (*DidData, error) { +func FetchDidData(ctx context.Context, cli *http.Client, did string) (*DidData, error) { + if cli == nil { + cli = util.RobustHTTPClient() + } + var ustr string ustr = fmt.Sprintf("https://plc.directory/%s/data", did) @@ -189,7 +146,11 @@ return &diddata, nil } -func FetchDidAuditLog(ctx context.Context, did string) (DidAuditLog, error) { +func FetchDidAuditLog(ctx context.Context, cli *http.Client, did string) (DidAuditLog, error) { + if cli == nil { + cli = util.RobustHTTPClient() + } + var ustr string ustr = fmt.Sprintf("https://plc.directory/%s/log/audit", did) @@ -217,8 +178,12 @@ return didlog, nil } -func ResolveService(ctx context.Context, did string) (string, error) { - diddoc, err := FetchDidDoc(ctx, did) +func ResolveService(ctx context.Context, cli *http.Client, did string) (string, error) { + if cli == nil { + cli = util.RobustHTTPClient() + } + + diddoc, err := FetchDidDoc(ctx, cli, did) if err != nil { return "", err } diff --git a/identity/passport.go b/identity/passport.go --- a/identity/passport.go +++ b/identity/passport.go @@ -2,6 +2,7 @@ package identity import ( "context" + "net/http" "sync" ) @@ -16,12 +17,18 @@ BustDid(handle string) error } type Passport struct { + h *http.Client bc BackingCache lk sync.Mutex } -func NewPassport(bc BackingCache) *Passport { +func NewPassport(h *http.Client, bc BackingCache) *Passport { + if h == nil { + h = http.DefaultClient + } + return &Passport{ + h: h, bc: bc, lk: sync.Mutex{}, } @@ -40,7 +47,7 @@ p.lk.Lock() // this is pretty pathetic, and i should rethink this. but for now, fuck it defer p.lk.Unlock() - doc, err := FetchDidDoc(ctx, did) + doc, err := FetchDidDoc(ctx, p.h, did) if err != nil { return nil, err } @@ -60,7 +67,7 @@ return cached, nil } } - did, err := ResolveHandle(ctx, handle) + did, err := ResolveHandle(ctx, p.h, handle) if err != nil { return "", err } diff --git a/identity/types.go b/identity/types.go new file mode 100644 --- /dev/null +++ b/identity/types.go @@ -0,0 +1,57 @@ +package identity + +type DidDoc struct { + Context []string `json:"@context"` + Id string `json:"id"` + AlsoKnownAs []string `json:"alsoKnownAs"` + VerificationMethods []DidDocVerificationMethod `json:"verificationMethods"` + Service []DidDocService `json:"service"` +} + +type DidDocVerificationMethod struct { + Id string `json:"id"` + Type string `json:"type"` + Controller string `json:"controller"` + PublicKeyMultibase string `json:"publicKeyMultibase"` +} + +type DidDocService struct { + Id string `json:"id"` + Type string `json:"type"` + ServiceEndpoint string `json:"serviceEndpoint"` +} + +type DidData struct { + Did string `json:"did"` + VerificationMethods map[string]string `json:"verificationMethods"` + RotationKeys []string `json:"rotationKeys"` + AlsoKnownAs []string `json:"alsoKnownAs"` + Services map[string]OperationService `json:"services"` +} + +type OperationService struct { + Type string `json:"type"` + Endpoint string `json:"endpoint"` +} + +type DidLog []DidLogEntry + +type DidLogEntry struct { + Sig string `json:"sig"` + Prev *string `json:"prev"` + Type string `json:"string"` + Services map[string]OperationService `json:"services"` + AlsoKnownAs []string `json:"alsoKnownAs"` + RotationKeys []string `json:"rotationKeys"` + VerificationMethods map[string]string `json:"verificationMethods"` +} + +type DidAuditEntry struct { + Did string `json:"did"` + Operation DidLogEntry `json:"operation"` + Cid string `json:"cid"` + Nullified bool `json:"nullified"` + CreatedAt string `json:"createdAt"` +} + +type DidAuditLog []DidAuditEntry diff --git a/plc/client.go b/plc/client.go --- a/plc/client.go +++ b/plc/client.go @@ -15,6 +15,7 @@ "strings" "github.com/bluesky-social/indigo/atproto/crypto" "github.com/bluesky-social/indigo/util" + "github.com/haileyok/cocoon/identity" ) type Client struct { @@ -25,6 +26,7 @@ rotationKey *crypto.PrivateKeyK256 } type ClientArgs struct { + H *http.Client Service string RotationKey []byte PdsHostname string @@ -35,13 +37,17 @@ if args.Service == "" { args.Service = "https://plc.directory" } + if args.H == nil { + args.H = util.RobustHTTPClient() + } + rk, err := crypto.ParsePrivateBytesK256([]byte(args.RotationKey)) if err != nil { return nil, err } return &Client{ - h: util.RobustHTTPClient(), + h: args.H, service: args.Service, rotationKey: rk, pdsHostname: args.PdsHostname, @@ -80,7 +86,7 @@ RotationKeys: rotationKeys, AlsoKnownAs: []string{ "at://" + handle, }, - Services: map[string]OperationService{ + Services: map[string]identity.OperationService{ "atproto_pds": { Type: "AtprotoPersonalDataServer", Endpoint: "https://" + c.pdsHostname, diff --git a/server/handle_identity_update_handle.go b/server/handle_identity_update_handle.go --- a/server/handle_identity_update_handle.go +++ b/server/handle_identity_update_handle.go @@ -39,7 +39,7 @@ ctx := context.WithValue(e.Request().Context(), "skip-cache", true) if strings.HasPrefix(repo.Repo.Did, "did:plc:") { - log, err := identity.FetchDidAuditLog(ctx, repo.Repo.Did) + log, err := identity.FetchDidAuditLog(ctx, nil, repo.Repo.Did) if err != nil { s.logger.Error("error fetching doc", "error", err) return helpers.ServerError(e, nil) diff --git a/server/handle_server_create_account.go b/server/handle_server_create_account.go --- a/server/handle_server_create_account.go +++ b/server/handle_server_create_account.go @@ -116,7 +116,7 @@ s.logger.Error("error creating signing key", "endpoint", "com.atproto.server.createAccount", "error", err) return helpers.ServerError(e, nil) } - did, op, err := s.plcClient.CreateDID(e.Request().Context(), k, "", request.Handle) + did, op, err := s.plcClient.CreateDID(k, "", request.Handle) if err != nil { s.logger.Error("error creating operation", "endpoint", "com.atproto.server.createAccount", "error", err) return helpers.ServerError(e, nil) diff --git a/server/server.go b/server/server.go --- a/server/server.go +++ b/server/server.go @@ -15,6 +15,7 @@ "github.com/Azure/go-autorest/autorest/to" "github.com/bluesky-social/indigo/api/atproto" "github.com/bluesky-social/indigo/atproto/syntax" "github.com/bluesky-social/indigo/events" + "github.com/bluesky-social/indigo/util" "github.com/bluesky-social/indigo/xrpc" "github.com/go-playground/validator" "github.com/golang-jwt/jwt/v4" @@ -31,6 +32,7 @@ "gorm.io/gorm" ) type Server struct { + http *http.Client httpd *http.Server echo *echo.Echo db *gorm.DB @@ -268,7 +270,10 @@ if err != nil { return nil, err } + h := util.RobustHTTPClient() + plcClient, err := plc.NewClient(&plc.ClientArgs{ + H: h, Service: "https://plc.directory", PdsHostname: args.Hostname, RotationKey: rkbytes, @@ -293,6 +298,7 @@ return nil, err } s := &Server{ + http: h, httpd: httpd, echo: e, logger: args.Logger, @@ -308,7 +314,7 @@ EnforcePeering: false, Relays: args.Relays, }, evtman: events.NewEventManager(events.NewMemPersister()), - passport: identity.NewPassport(identity.NewMemCache(10_000)), + passport: identity.NewPassport(h, identity.NewMemCache(10_000)), } s.repoman = NewRepoMan(s) // TODO: this is way too lazy, stop it