plc-mirror/util/resolver/resolver.go

101 lines
2.3 KiB
Go
Raw Normal View History

2024-02-15 17:10:39 +01:00
package resolver
import (
"context"
"errors"
"fmt"
"net/url"
2024-02-15 17:10:39 +01:00
"os"
"github.com/bluesky-social/indigo/api"
"github.com/bluesky-social/indigo/did"
"github.com/rs/zerolog"
2024-02-15 17:10:39 +01:00
)
var Resolver did.Resolver
func init() {
resolver := did.NewMultiResolver()
plcAddr := os.Getenv("ATP_PLC_ADDR")
if plcAddr == "" {
plcAddr = "https://plc.directory"
}
resolver.AddHandler("plc", &fallbackResolver{
resolvers: []did.Resolver{
&api.PLCServer{Host: plcAddr},
&api.PLCServer{Host: "https://plc.directory"},
}})
resolver.AddHandler("web", &did.WebResolver{})
Resolver = resolver
}
func GetDocument(ctx context.Context, didstr string) (*did.Document, error) {
return Resolver.GetDocument(ctx, didstr)
}
type fallbackResolver struct {
resolvers []did.Resolver
}
func (r *fallbackResolver) GetDocument(ctx context.Context, didstr string) (*did.Document, error) {
log := zerolog.Ctx(ctx)
2024-02-15 17:10:39 +01:00
errs := []error{}
for _, res := range r.resolvers {
if d, err := res.GetDocument(ctx, didstr); err == nil {
return d, nil
2024-02-16 09:50:37 +01:00
} else {
log.Trace().Err(err).Str("plc", res.(*api.PLCServer).Host).
Msgf("Failed to resolve %q using %q: %s", didstr, res.(*api.PLCServer).Host, err)
2024-02-16 09:50:37 +01:00
errs = append(errs, err)
2024-02-15 17:10:39 +01:00
}
}
return nil, errors.Join(errs...)
}
func (r *fallbackResolver) FlushCacheFor(did string) {
for _, res := range r.resolvers {
res.FlushCacheFor(did)
}
}
2024-04-06 22:50:32 +02:00
func GetPDSEndpointAndPublicKey(ctx context.Context, did string) (*url.URL, string, error) {
doc, err := GetDocument(ctx, did)
if err != nil {
2024-04-06 22:50:32 +02:00
return nil, "", fmt.Errorf("resolving did %q: %w", did, err)
}
pdsHost := ""
for _, srv := range doc.Service {
if srv.Type != "AtprotoPersonalDataServer" {
continue
}
pdsHost = srv.ServiceEndpoint
}
if pdsHost == "" {
2024-04-06 22:50:32 +02:00
return nil, "", fmt.Errorf("did not find any PDS in DID Document")
}
u, err := url.Parse(pdsHost)
if err != nil {
2024-04-06 22:50:32 +02:00
return nil, "", fmt.Errorf("PDS endpoint (%q) is an invalid URL: %w", pdsHost, err)
}
if u.Host == "" {
2024-04-06 22:50:32 +02:00
return nil, "", fmt.Errorf("PDS endpoint (%q) doesn't have a host part", pdsHost)
}
2024-04-06 22:50:32 +02:00
key := ""
for _, m := range doc.VerificationMethod {
if m.ID != fmt.Sprintf("%s#atproto", did) {
continue
}
if m.PublicKeyMultibase == nil {
continue
}
key = *m.PublicKeyMultibase
}
if key == "" {
return nil, "", fmt.Errorf("didn't find public key")
}
return u, key, nil
}