mirror of
https://github.com/owncast/owncast.git
synced 2024-11-24 05:38:58 +03:00
b835de2dc4
* 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 * don't redirect unless a URL is present avoids redirecting to `undefined` if there was an error * improve error message if owncast server URL isn't set * fix IndieAuth PKCE implementation use SHA256 instead of SHA1, generates a longer code verifier (must be 43-128 chars long), fixes URL-safe SHA256 encoding * return real profile data for IndieAuth response * check the code verifier in the IndieAuth server * Linting * Add new chat settings modal anad split up indieauth ui * Remove logging error * Update the IndieAuth modal UI. For #1273 * Add IndieAuth repsonse error checking * Disable IndieAuth client if server URL is not set. * Add explicit error messages for specific error types * Fix bad logic * Return OAuth-keyed error responses for indieauth server * Display IndieAuth error in plain text with link to return to main page * Remove redundant check * Add additional detail to error * Hide IndieAuth details behind disclosure details * Break out migration into two steps because some people have been runing dev in production * Add auth option to user dropdown Co-authored-by: Aaron Parecki <aaron@parecki.com>
143 lines
5 KiB
Go
143 lines
5 KiB
Go
package controllers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
|
|
"github.com/owncast/owncast/activitypub"
|
|
"github.com/owncast/owncast/config"
|
|
"github.com/owncast/owncast/core/data"
|
|
"github.com/owncast/owncast/models"
|
|
"github.com/owncast/owncast/router/middleware"
|
|
"github.com/owncast/owncast/utils"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type webConfigResponse struct {
|
|
Name string `json:"name"`
|
|
Summary string `json:"summary"`
|
|
Logo string `json:"logo"`
|
|
Tags []string `json:"tags"`
|
|
Version string `json:"version"`
|
|
NSFW bool `json:"nsfw"`
|
|
SocketHostOverride string `json:"socketHostOverride,omitempty"`
|
|
ExtraPageContent string `json:"extraPageContent"`
|
|
StreamTitle string `json:"streamTitle,omitempty"` // What's going on with the current stream
|
|
SocialHandles []models.SocialHandle `json:"socialHandles"`
|
|
ChatDisabled bool `json:"chatDisabled"`
|
|
ExternalActions []models.ExternalAction `json:"externalActions"`
|
|
CustomStyles string `json:"customStyles"`
|
|
MaxSocketPayloadSize int `json:"maxSocketPayloadSize"`
|
|
Federation federationConfigResponse `json:"federation"`
|
|
Notifications notificationsConfigResponse `json:"notifications"`
|
|
Authentication authenticationConfigResponse `json:"authentication"`
|
|
}
|
|
|
|
type federationConfigResponse struct {
|
|
Enabled bool `json:"enabled"`
|
|
Account string `json:"account,omitempty"`
|
|
FollowerCount int `json:"followerCount,omitempty"`
|
|
}
|
|
|
|
type browserNotificationsConfigResponse struct {
|
|
Enabled bool `json:"enabled"`
|
|
PublicKey string `json:"publicKey,omitempty"`
|
|
}
|
|
|
|
type notificationsConfigResponse struct {
|
|
Browser browserNotificationsConfigResponse `json:"browser"`
|
|
}
|
|
|
|
type authenticationConfigResponse struct {
|
|
IndieAuthEnabled bool `json:"indieAuthEnabled"`
|
|
}
|
|
|
|
// GetWebConfig gets the status of the server.
|
|
func GetWebConfig(w http.ResponseWriter, r *http.Request) {
|
|
middleware.EnableCors(w)
|
|
middleware.DisableCache(w)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
pageContent := utils.RenderPageContentMarkdown(data.GetExtraPageBodyContent())
|
|
socialHandles := data.GetSocialHandles()
|
|
for i, handle := range socialHandles {
|
|
platform := models.GetSocialHandle(handle.Platform)
|
|
if platform != nil {
|
|
handle.Icon = platform.Icon
|
|
socialHandles[i] = handle
|
|
}
|
|
}
|
|
|
|
serverSummary := data.GetServerSummary()
|
|
serverSummary = utils.RenderPageContentMarkdown(serverSummary)
|
|
|
|
var federationResponse federationConfigResponse
|
|
federationEnabled := data.GetFederationEnabled()
|
|
|
|
followerCount, _ := activitypub.GetFollowerCount()
|
|
if federationEnabled {
|
|
serverURLString := data.GetServerURL()
|
|
serverURL, _ := url.Parse(serverURLString)
|
|
account := fmt.Sprintf("%s@%s", data.GetDefaultFederationUsername(), serverURL.Host)
|
|
federationResponse = federationConfigResponse{
|
|
Enabled: federationEnabled,
|
|
FollowerCount: int(followerCount),
|
|
Account: account,
|
|
}
|
|
}
|
|
|
|
browserPushEnabled := data.GetBrowserPushConfig().Enabled
|
|
browserPushPublicKey, err := data.GetBrowserPushPublicKey()
|
|
if err != nil {
|
|
log.Errorln("unable to fetch browser push notifications public key", err)
|
|
browserPushEnabled = false
|
|
}
|
|
|
|
notificationsResponse := notificationsConfigResponse{
|
|
Browser: browserNotificationsConfigResponse{
|
|
Enabled: browserPushEnabled,
|
|
PublicKey: browserPushPublicKey,
|
|
},
|
|
}
|
|
|
|
authenticationResponse := authenticationConfigResponse{
|
|
IndieAuthEnabled: data.GetServerURL() != "",
|
|
}
|
|
|
|
configuration := webConfigResponse{
|
|
Name: data.GetServerName(),
|
|
Summary: serverSummary,
|
|
Logo: "/logo",
|
|
Tags: data.GetServerMetadataTags(),
|
|
Version: config.GetReleaseString(),
|
|
NSFW: data.GetNSFW(),
|
|
SocketHostOverride: data.GetWebsocketOverrideHost(),
|
|
ExtraPageContent: pageContent,
|
|
StreamTitle: data.GetStreamTitle(),
|
|
SocialHandles: socialHandles,
|
|
ChatDisabled: data.GetChatDisabled(),
|
|
ExternalActions: data.GetExternalActions(),
|
|
CustomStyles: data.GetCustomStyles(),
|
|
MaxSocketPayloadSize: config.MaxSocketPayloadSize,
|
|
Federation: federationResponse,
|
|
Notifications: notificationsResponse,
|
|
Authentication: authenticationResponse,
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(configuration); err != nil {
|
|
BadRequestHandler(w, err)
|
|
}
|
|
}
|
|
|
|
// GetAllSocialPlatforms will return a list of all social platform types.
|
|
func GetAllSocialPlatforms(w http.ResponseWriter, r *http.Request) {
|
|
middleware.EnableCors(w)
|
|
w.Header().Set("Content-Type", "application/json")
|
|
|
|
platforms := models.GetAllSocialHandles()
|
|
if err := json.NewEncoder(w).Encode(platforms); err != nil {
|
|
InternalErrorHandler(w, err)
|
|
}
|
|
}
|