linstrom/server-old/endpoint_webfinger.go

113 lines
3.2 KiB
Go
Raw Normal View History

2024-08-22 17:57:53 +00:00
package server
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"github.com/sirupsen/logrus"
"gitlab.com/mstarongitlab/linstrom/config"
"gitlab.com/mstarongitlab/linstrom/server/middlewares"
"gitlab.com/mstarongitlab/linstrom/storage"
)
type webfingerUrl struct {
Relation string `json:"rel"`
Type string `json:"type"`
Url string `json:"href"`
}
// NOTE: Unused for now
// Reason: No endpoint for eg follow authorisation yet
type webfingerTemplate struct {
Relation string `json:"rel"`
Template string `json:"template"`
}
type webfingerResponse struct {
Subject string `json:"subject"`
// Any because it's either a webfingerTemplate or webfingerUrl
Links []any `json:"links"`
}
// Mount under /.well-known/webfinger
// Handles webfinger requests which are used to determine whether an account exists on this server
// Additionally, a sucessful query will return a set of links related to that account, such as the activitypub view and the web view
func webfingerHandler(w http.ResponseWriter, r *http.Request) {
logEntry, ok := r.Context().Value(middlewares.CONTEXT_KEY_LOGRUS).(*logrus.Entry)
if !ok {
http.Error(w, "couldn't get logging entry from context", http.StatusInternalServerError)
return
}
store := storage.Storage{}
requestedResource := r.FormValue("resource")
if requestedResource == "" {
http.Error(w, "bad request. Include \"resource\" parameter", http.StatusBadRequest)
logEntry.Infoln("No resource parameter. Cancelling")
return
}
accName := strings.TrimPrefix(requestedResource, "acc:")
acc, err := store.FindLocalAccount(accName)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
logEntry.WithError(err).Warningln("couldn't find account")
return
}
finger, err := accToWebfinger(acc)
if err != nil {
http.Error(w, "failed to build webfinger", http.StatusInternalServerError)
return
}
data, err := json.Marshal(finger)
if err != nil {
http.Error(w, "failed to build json", http.StatusInternalServerError)
return
}
fmt.Fprint(w, string(data))
}
func accToWebfinger(acc *storage.User) (*webfingerResponse, error) {
// First ensure config is set
if config.Global == nil {
return nil, config.ErrGlobalConfigNotSet
}
// Then build the ap link
apLink := webfingerUrl{
Relation: "self",
Type: "application/activity+json",
Url: config.Global.General.FullDomain,
}
if config.Global.General.PublicPort != 80 &&
config.Global.General.PublicPort != 443 {
apLink.Url += fmt.Sprintf(":%d", config.Global.General.PublicPort)
}
apLink.Url += "/api/ap/user/" + acc.ID
// Now the web view
viewLink := webfingerUrl{
Relation: "http://webfinger.net/rel/profile-page",
Type: "text/html",
Url: config.Global.General.FullDomain,
}
if config.Global.General.PublicPort != 80 &&
config.Global.General.PublicPort != 443 {
viewLink.Url += fmt.Sprintf(":%d", config.Global.General.PublicPort)
}
viewLink.Url += "/@" + acc.GetHandleNameOnly()
// TODO: Add follow authorisation template once the endpoint is available
response := webfingerResponse{
Subject: fmt.Sprintf("acct:%s", strings.TrimPrefix(acc.Handle, "@")),
Links: []any{
apLink,
viewLink,
},
}
return &response, nil
}