~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
91 lines · 2.4 KB Raw History
package plcresolver

import (
	"context"
	"errors"
	"fmt"
	"net"
	"net/http"
	"strings"

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

	"github.com/johnandersen777/socialweb-computer-kcp/internal/revocation"
)

type Options struct {
	URL string

	Client *http.Client
}

type Resolver struct {
	dir *identity.BaseDirectory
}

type nxdomainIsAnOutage struct{ inner http.RoundTripper }

func (t nxdomainIsAnOutage) RoundTrip(r *http.Request) (*http.Response, error) {
	resp, err := t.inner.RoundTrip(r)
	var dnsErr *net.DNSError
	if errors.As(err, &dnsErr) && dnsErr.IsNotFound {
		return nil, fmt.Errorf(
			"the name does not resolve, which is an outage and not an absence: %s", err)
	}
	return resp, err
}

func New(opts Options) (*Resolver, error) {
	if opts.URL == "" {
		return nil, errors.New("plcresolver: URL is required")
	}
	if opts.Client == nil {
		return nil, errors.New("plcresolver: Client is required")
	}
	client := *opts.Client
	transport := client.Transport
	if transport == nil {
		transport = http.DefaultTransport
	}
	client.Transport = nxdomainIsAnOutage{inner: transport}

	return &Resolver{dir: &identity.BaseDirectory{
		PLCURL:     strings.TrimSuffix(opts.URL, "/"),
		PLCClient:  &client,
		HTTPClient: client,
	}}, nil
}

func (r *Resolver) Resolve(ctx context.Context, did string) (revocation.PLCResolution, error) {
	parsed, err := syntax.ParseDID(did)
	if err != nil {
		return unknown(fmt.Errorf("plcresolver: %q is not a DID: %w", did, err))
	}
	switch parsed.Method() {
	case "plc", "web":
	default:
		return unknown(fmt.Errorf(
			"plcresolver: %s is a did:%s, and this package resolves only a method with a "+
				"document somewhere: a did:key's key IS its identity, so there is nothing to "+
				"resolve and nothing that could ever be found gone", did, parsed.Method()))
	}

	doc, err := r.dir.ResolveDID(ctx, parsed)
	switch {
	case errors.Is(err, identity.ErrDIDNotFound):
		return revocation.PLCResolution{Found: false}, nil
	case err != nil:
		return unknown(fmt.Errorf("plcresolver: resolve %s: %w", did, err))
	}

	keys := make([]string, 0, len(doc.VerificationMethod))
	for _, vm := range doc.VerificationMethod {
		keys = append(keys, vm.ID)
	}
	return revocation.PLCResolution{Found: true, Keys: keys}, nil
}

func unknown(err error) (revocation.PLCResolution, error) {
	return revocation.PLCResolution{Err: err}, err
}