linstrom/endpoints/api/ap/webfinger.go

92 lines
2.3 KiB
Go
Raw Normal View History

// Copyright (c) 2024 mStar
//
// Licensed under the EUPL, Version 1.2
//
// You may not use this work except in compliance with the Licence.
// You should have received a copy of the Licence along with this work. If not, see:
// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
// See the Licence for the specific language governing permissions and limitations under the Licence.
//
package ap
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/julienschmidt/httprouter"
"gitlab.com/mstarongitlab/goutils/other"
"gitlab.com/mstarongitlab/linstrom/server"
"gitlab.com/mstarongitlab/linstrom/types"
)
var ErrInvalidResource = errors.New("invalid resource")
type webfingerLink struct {
Rel string `json:"self"`
Type string `json:"type"`
Target url.URL `json:"href"`
}
type WebfingerResponse struct {
Subject string `json:"subject"`
Links []webfingerLink `json:"links"`
}
func WebfingerEndpoint(server *server.Server) func(http.ResponseWriter, *http.Request, httprouter.Params) {
return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
r.ParseForm()
req := r.FormValue("resource")
if req == "" {
http.NotFound(w, r)
return
}
acc, err := getAccountFromWebfingerResource(req)
if errors.Is(err, ErrInvalidResource) {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if acc.Host.Hostname() != server.Config.General.Domain {
http.Error(w, fmt.Sprintf("wrong host, try %s", &acc.Host), http.StatusNotFound)
return
}
response := WebfingerResponse{
Links: []webfingerLink{
{
Rel: "me",
Type: "application/activity+json",
Target: *other.Must(url.Parse("https://example.com")), // TODO: Replace this with actual link generation
},
},
}
json.Marshal(response)
}
}
// acct:bugle@bugle.lol
func getAccountFromWebfingerResource(r string) (*types.AccountHandle, error) {
acctCheck, acc, found := strings.Cut(r, ":")
if !found || acctCheck != "acct" {
return nil, ErrInvalidResource
}
name, rawHost, found := strings.Cut(acc, "@")
if !found {
return nil, ErrInvalidResource
}
host, err := url.Parse(rawHost)
if err != nil {
return nil, fmt.Errorf("%w: Invalid url: %w", ErrInvalidResource, err)
}
return &types.AccountHandle{
Name: name,
Host: *host,
}, nil
}