mirror of
https://github.com/owncast/owncast.git
synced 2024-11-27 09:45:36 +03:00
101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
|
package controllers
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/owncast/owncast/core/data"
|
||
|
)
|
||
|
|
||
|
// RemoteFollow handles a request to begin the remote follow redirect flow.
|
||
|
func RemoteFollow(w http.ResponseWriter, r *http.Request) {
|
||
|
type followRequest struct {
|
||
|
Account string `json:"account"`
|
||
|
}
|
||
|
|
||
|
type followResponse struct {
|
||
|
RedirectURL string `json:"redirectUrl"`
|
||
|
}
|
||
|
|
||
|
var request followRequest
|
||
|
decoder := json.NewDecoder(r.Body)
|
||
|
if err := decoder.Decode(&request); err != nil {
|
||
|
WriteSimpleResponse(w, false, "unable to parse request")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if request.Account == "" {
|
||
|
WriteSimpleResponse(w, false, "Remote Fediverse account is required to follow.")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
localActorPath, _ := url.Parse(data.GetServerURL())
|
||
|
localActorPath.Path = fmt.Sprintf("/federation/user/%s", data.GetDefaultFederationUsername())
|
||
|
var template string
|
||
|
links, err := getWebfingerLinks(request.Account)
|
||
|
if err != nil {
|
||
|
WriteSimpleResponse(w, false, err.Error())
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Acquire the remote follow redirect template.
|
||
|
for _, link := range links {
|
||
|
for k, v := range link {
|
||
|
if k == "rel" && v == "http://ostatus.org/schema/1.0/subscribe" && link["template"] != nil {
|
||
|
template = link["template"].(string)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if localActorPath.String() == "" || template == "" {
|
||
|
WriteSimpleResponse(w, false, "unable to determine remote follow information for "+request.Account)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
redirectURL := strings.Replace(template, "{uri}", localActorPath.String(), 1)
|
||
|
response := followResponse{
|
||
|
RedirectURL: redirectURL,
|
||
|
}
|
||
|
|
||
|
WriteResponse(w, response)
|
||
|
}
|
||
|
|
||
|
func getWebfingerLinks(account string) ([]map[string]interface{}, error) {
|
||
|
type webfingerResponse struct {
|
||
|
Links []map[string]interface{} `json:"links"`
|
||
|
}
|
||
|
|
||
|
account = strings.TrimLeft(account, "@") // remove any leading @
|
||
|
accountComponents := strings.Split(account, "@")
|
||
|
fediverseServer := accountComponents[1]
|
||
|
|
||
|
// HTTPS is required.
|
||
|
requestURL, err := url.Parse("https://" + fediverseServer)
|
||
|
if err != nil {
|
||
|
return nil, fmt.Errorf("unable to parse fediverse server host %s", fediverseServer)
|
||
|
}
|
||
|
|
||
|
requestURL.Path = "/.well-known/webfinger"
|
||
|
query := requestURL.Query()
|
||
|
query.Add("resource", fmt.Sprintf("acct:%s", account))
|
||
|
requestURL.RawQuery = query.Encode()
|
||
|
|
||
|
response, err := http.DefaultClient.Get(requestURL.String())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
defer response.Body.Close()
|
||
|
|
||
|
var links webfingerResponse
|
||
|
decoder := json.NewDecoder(response.Body)
|
||
|
if err := decoder.Decode(&links); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return links.Links, nil
|
||
|
}
|