112 lines
3.2 KiB
Go
112 lines
3.2 KiB
Go
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
|
|
}
|