owncast/controllers/remoteFollow.go
Gabe Kangas a082cf3a77
Fediverse-based authentication (#1846)
* Able to authenticate user against IndieAuth. For #1273

* WIP server indieauth endpoint. For https://github.com/owncast/owncast/issues/1272

* Add migration to remove access tokens from user

* Add authenticated bool to user for display purposes

* Add indieauth modal and auth flair to display names. For #1273

* Validate URLs and display errors

* Renames, cleanups

* Handle relative auth endpoint paths. Add error handling for missing redirects.

* Disallow using display names in use by registered users. Closes #1810

* Verify code verifier via code challenge on callback

* Use relative path to authorization_endpoint

* Post-rebase fixes

* Use a timestamp instead of a bool for authenticated

* Propertly handle and display error in modal

* Use auth'ed timestamp to derive authenticated flag to display in chat

* Fediverse chat auth via OTP

* Increase validity time just in case

* Add fediverse auth into auth modal

* Text, validation, cleanup updates for fedi auth

* Fix typo

* Remove unused images

* Remove unused file

* Add chat display name to auth modal text
2022-04-22 17:23:14 -07:00

66 lines
1.6 KiB
Go

package controllers
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/owncast/owncast/activitypub/webfinger"
"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 := webfinger.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)
}