feat: add .well-known/webfinger
This commit is contained in:
parent
507b7349ba
commit
9bde1a1aa7
4 changed files with 133 additions and 0 deletions
13
web/wellknown/module.go
Normal file
13
web/wellknown/module.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package wellknown
|
||||
|
||||
import "git.sleepycat.moe/sam/mercury/web/app"
|
||||
|
||||
type App struct {
|
||||
*app.App
|
||||
}
|
||||
|
||||
func New(app *app.App) *App {
|
||||
return &App{
|
||||
App: app,
|
||||
}
|
||||
}
|
84
web/wellknown/webfinger.go
Normal file
84
web/wellknown/webfinger.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
package wellknown
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"git.sleepycat.moe/sam/mercury/internal/database/sql"
|
||||
"git.sleepycat.moe/sam/mercury/web/api"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (app *App) WebFinger(w http.ResponseWriter, r *http.Request) (any, error) {
|
||||
ctx := r.Context()
|
||||
validDomains := app.AppConfig.Web.WebFingerDomains()
|
||||
|
||||
resource, err := url.QueryUnescape(r.FormValue("resource"))
|
||||
if err != nil {
|
||||
return nil, api.Error{Code: api.ErrBadRequest}
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(resource, "acct:") {
|
||||
return nil, api.Error{Code: api.ErrBadRequest, Details: "WebFinger only supports `acct:` queries"}
|
||||
}
|
||||
resource = strings.TrimPrefix(resource, "acct:")
|
||||
username, domain, ok := strings.Cut(resource, "@")
|
||||
if !ok {
|
||||
return nil, api.Error{Code: api.ErrBadRequest}
|
||||
}
|
||||
if !anyMatches(validDomains, domain) {
|
||||
return nil, api.Error{Code: api.ErrBadRequest, Details: "Not a local user on this instance"}
|
||||
}
|
||||
|
||||
blog, err := app.Blog().ByName(ctx, username, "")
|
||||
if err != nil {
|
||||
if err == sql.ErrNotFound {
|
||||
return nil, api.Error{Code: api.ErrNotFound}
|
||||
}
|
||||
|
||||
log.Err(err).Str("username", username).Msg("looking up user for webfinger request")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
webFingerHref := fmt.Sprintf("%s/@%s", app.AppConfig.Web.Domain, blog.Name)
|
||||
|
||||
return WebFinger{
|
||||
Subject: fmt.Sprintf("acct:%s@%s", blog.Name, validDomains[0]),
|
||||
Aliases: []string{webFingerHref},
|
||||
Links: []WebFingerLink{
|
||||
{
|
||||
Rel: "http://webfinger.net/rel/profile-page",
|
||||
Type: "text/html",
|
||||
Href: webFingerHref,
|
||||
},
|
||||
{
|
||||
Rel: "self",
|
||||
Type: "application/activity+json",
|
||||
Href: webFingerHref,
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type WebFinger struct {
|
||||
Subject string `json:"subject"`
|
||||
Aliases []string `json:"aliases"`
|
||||
Links []WebFingerLink `json:"links"`
|
||||
}
|
||||
|
||||
type WebFingerLink struct {
|
||||
Rel string `json:"rel"`
|
||||
Type string `json:"type"`
|
||||
Href string `json:"href"`
|
||||
}
|
||||
|
||||
func anyMatches[T comparable](slice []T, t T) bool {
|
||||
for _, entry := range slice {
|
||||
if entry == t {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue