tavern/fed/webfinger.go

73 lines
2.1 KiB
Go

package fed
import (
"fmt"
"net/url"
"strings"
"go.uber.org/zap"
"github.com/ngerakines/tavern/common"
"github.com/ngerakines/tavern/errors"
"github.com/ngerakines/tavern/storage"
)
type WebFingerClient struct {
HTTPClient common.HTTPClient
Logger *zap.Logger
}
var invalidWebFingerResource = fmt.Errorf("invalid webfinger resource")
func (client WebFingerClient) Fetch(location string) (storage.Payload, error) {
destination, err := BuildWebFingerURL(location)
if err != nil {
return nil, err
}
client.Logger.Debug("Sending webfinger request", zap.String("url", destination))
_, payload, err := JRDJsonGet(client.HTTPClient, destination)
return payload, err
}
func BuildWebFingerURL(location string) (string, error) {
// example: https://webfinger.net/lookup/?resource=https%3A%2F%2Fmastodon.social%2F%40ngerakines
if strings.HasPrefix(location, "https://") {
u, err := url.Parse(location)
if err != nil {
return "", fmt.Errorf("%w: %s", invalidWebFingerResource, location)
}
domain := u.Hostname()
return fmt.Sprintf("https://%s/.well-known/webfinger?resource=%s", domain, url.QueryEscape(location)), nil
}
// Some acct lookups may have a prefix from user input.
location = strings.TrimPrefix(location, "@")
subjectParts := strings.FieldsFunc(location, func(r rune) bool { return r == '@' })
if len(subjectParts) != 2 {
return "", fmt.Errorf("%w: %s", invalidWebFingerResource, location)
}
return fmt.Sprintf("https://%s/.well-known/webfinger?resource=acct:%s", subjectParts[1], url.QueryEscape(location)), nil
}
func ActorIDFromWebFingerPayload(wfp storage.Payload) (string, string, error) {
subject, _ := storage.JSONString(wfp, "subject")
links, ok := storage.JSONMapList(wfp, "links")
if ok {
for _, link := range links {
rel, hasRel := storage.JSONString(link, "rel")
linkType, hasType := storage.JSONString(link, "type")
href, hasHref := storage.JSONString(link, "href")
if !hasRel || !hasType || !hasHref {
continue
}
if rel == "self" && linkType == "application/activity+json" {
return href, subject, nil
}
}
}
return "", "", errors.NewNotFoundError(nil)
}