1
0
Fork 0
httpserver/middleware/wellknown/wellknown.go

131 Zeilen
3.2 KiB
Go

package wellknown
import (
"encoding/json"
"net/url"
"github.com/gin-gonic/gin"
"github.com/rs/zerolog/log"
"go.sebtobie.de/httpserver"
"go.sebtobie.de/httpserver/middleware"
)
var _ middleware.Middleware = &Middleware{}
var _ httpserver.Site = &Middleware{}
type (
// Link is the reference where the application can find the object
Link struct {
Rel string
Type string
Href *url.URL
}
// Middleware is an middleware for sites to register themselfs to provide wellknown urls
Middleware struct {
// webfinger is an map consisting of protocol as key and an array of WebfingerAccount as value
webfinger map[string][]Webfinger
}
// Webfinger is an function that accepts the account part(after ?resource=<protocol>:) and returns the aliases and the links.
// The bool value if for faster detection if the account was found.
Webfinger func(resource string) ([]string, []*Link, bool)
)
// New creates a new initialized Middleware
func New() *Middleware {
return &Middleware{
webfinger: map[string][]Webfinger{},
}
}
// Defaults returns nothing
func (*Middleware) Defaults() middleware.Config {
return nil
}
// Gin does nothing.
func (*Middleware) Gin(c *gin.Context) {
c.Next()
}
// Setup does nothing
func (*Middleware) Setup(middleware.Config) {}
// Teardown does nothing
func (*Middleware) Teardown() {}
// Sites goes through all sites and collects all registrations for wellknown uris
func (m *Middleware) Sites(s []any) error {
for _, site := range s {
if wfs, ok := site.(FingerSite); ok {
for _, finger := range wfs.RegisterFingers() {
if _, ok := m.webfinger[finger.Protocol]; !ok {
m.webfinger[finger.Protocol] = []Webfinger{}
}
m.webfinger[finger.Protocol] = append(m.webfinger[finger.Protocol], finger.Webfinger)
}
}
}
return nil
}
// Init initializes the routergroup. It must always run on /
func (m *Middleware) Init(rg *gin.RouterGroup) {
if len(m.webfinger) > 0 {
rg.GET(".well-known/webfinger", m.webfingerhf)
}
}
func (m *Middleware) webfingerhf(c *gin.Context) {
resource := c.Query("resource")
if resource == "" {
c.AbortWithStatus(404)
return
}
uri, err := url.Parse(resource)
if err != nil {
log.Error().Err(err).Str("uri", resource).Msg("Failed to parse uri")
c.AbortWithStatus(404)
return
}
var wf []Webfinger
var found bool
if wf, found = m.webfinger[uri.Scheme]; !found {
c.AbortWithStatus(404)
return
}
var output = struct {
Subject string `json:"subject,omitempty"`
Aliases []string `json:"aliases,omitempty"`
Links []*Link `json:"links,omitempty"`
}{Subject: resource, Aliases: []string{}, Links: []*Link{}}
var aliases = []string{}
var links = []*Link{}
var input = uri.Opaque
if uri.Opaque == "" {
input = resource
}
outputok := false
for _, finger := range wf {
aliases, links, found = finger(input)
if !found {
continue
}
output.Aliases = append(output.Aliases, aliases...)
output.Links = append(output.Links, links...)
outputok = true
}
if outputok {
c.Header("Access-Control-Allow-Origin", "*")
json, err := json.Marshal(output)
if err != nil {
c.AbortWithStatus(500)
return
}
c.Data(200, "application/jrd+json", json)
}
c.AbortWithStatus(404)
}