owncast/webserver/router.go
Gabe Kangas b80ccc4966
WIP
2024-03-25 09:04:05 -07:00

437 lines
20 KiB
Go

package webserver
import (
"net/http"
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/services/config"
"github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/handlers/federation"
"github.com/owncast/owncast/webserver/middleware"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
func (s *webServer) setupRoutes() {
s.setupWebAssetRoutes()
s.setupInternalAPIRoutes()
s.setupAdminAPIRoutes()
s.setupExternalThirdPartyAPIRoutes()
s.setupModerationAPIRoutes()
s.setupActivityPubFederationRoutes()
s.router.HandleFunc("/hls/", s.handlers.HandleHLSRequest)
// websocket
s.router.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
s.chatService.HandleClientConnection(w, r)
})
s.router.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// This is a hack because Prometheus enables this endpoint by default
// due to its use of expvar and we do not want this exposed.
if r.URL.Path == "/debug/vars" {
w.WriteHeader(http.StatusNotFound)
return
} else if r.URL.Path == "/embed/chat/" || r.URL.Path == "/embed/chat" {
// Redirect /embed/chat
http.Redirect(w, r, "/embed/chat/readonly", http.StatusTemporaryRedirect)
} else {
s.handlers.IndexHandler(w, r)
// s.ServeHTTP(w, r)
}
})
}
func (s *webServer) setupWebAssetRoutes() {
c := config.Get()
// The admin web app.
s.router.HandleFunc("/admin/", middleware.RequireAdminAuth(s.handlers.IndexHandler))
// Images
s.router.HandleFunc("/thumbnail.jpg", s.handlers.GetThumbnail)
s.router.HandleFunc("/preview.gif", s.handlers.GetPreview)
s.router.HandleFunc("/logo", s.handlers.GetLogo)
// Custom Javascript
s.router.HandleFunc("/customjavascript", s.handlers.ServeCustomJavascript)
// Return a single emoji image.
s.router.HandleFunc(config.EmojiDir, s.handlers.GetCustomEmojiImage)
// return the logo
// return a logo that's compatible with external social networks
s.router.HandleFunc("/logo/external", s.handlers.GetCompatibleLogo)
// robots.txt
s.router.HandleFunc("/robots.txt", s.handlers.GetRobotsDotTxt)
// Optional public static files
s.router.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir(c.PublicFilesPath))))
}
func (s *webServer) setupInternalAPIRoutes() {
// Internal APIs
// status of the system
s.router.HandleFunc("/api/status", s.handlers.GetStatus)
// custom emoji supported in the chat
s.router.HandleFunc("/api/emoji", s.handlers.GetCustomEmojiList)
// chat history api
s.router.HandleFunc("/api/chat", middleware.RequireUserAccessToken(s.handlers.GetChatMessages))
// web config api
s.router.HandleFunc("/api/config", s.handlers.GetWebConfig)
// return the YP protocol data
s.router.HandleFunc("/api/yp", s.handlers.GetYPResponse)
// list of all social platforms
s.router.HandleFunc("/api/socialplatforms", s.handlers.GetAllSocialPlatforms)
// return the list of video variants available
s.router.HandleFunc("/api/video/variants", s.handlers.GetVideoStreamOutputVariants)
// tell the backend you're an active viewer
s.router.HandleFunc("/api/ping", s.handlers.Ping)
// register a new chat user
s.router.HandleFunc("/api/chat/register", s.handlers.RegisterAnonymousChatUser)
// return remote follow details
s.router.HandleFunc("/api/remotefollow", s.handlers.RemoteFollow)
// return followers
s.router.HandleFunc("/api/followers", middleware.HandlePagination(s.handlers.GetFollowers))
// save client video playback metrics
s.router.HandleFunc("/api/metrics/playback", s.handlers.ReportPlaybackMetrics)
// Register for notifications
s.router.HandleFunc("/api/notifications/register", middleware.RequireUserAccessToken(s.handlers.RegisterForLiveNotifications))
// Start auth flow
s.router.HandleFunc("/api/auth/indieauth", middleware.RequireUserAccessToken(s.indieAuthHandlers.StartAuthFlow))
s.router.HandleFunc("/api/auth/indieauth/callback", s.indieAuthHandlers.HandleRedirect)
s.router.HandleFunc("/api/auth/provider/indieauth", s.indieAuthHandlers.HandleAuthEndpoint)
s.router.HandleFunc("/api/auth/fediverse", middleware.RequireUserAccessToken(s.fediAuthHandlers.RegisterFediverseOTPRequest))
s.router.HandleFunc("/api/auth/fediverse/verify", s.fediAuthHandlers.VerifyFediverseOTPRequest)
}
func (s *webServer) setupAdminAPIRoutes() {
// Current inbound broadcaster
s.router.HandleFunc("/api/admin/status", middleware.RequireAdminAuth(s.handlers.GetAdminStatus))
// Disconnect inbound stream
s.router.HandleFunc("/api/admin/disconnect", middleware.RequireAdminAuth(s.handlers.DisconnectInboundConnection))
// Server config
s.router.HandleFunc("/api/admin/serverconfig", middleware.RequireAdminAuth(s.handlers.GetServerConfig))
// Get viewer count over time
s.router.HandleFunc("/api/admin/viewersOverTime", middleware.RequireAdminAuth(s.handlers.GetViewersOverTime))
// Get active viewers
s.router.HandleFunc("/api/admin/viewers", middleware.RequireAdminAuth(s.handlers.GetActiveViewers))
// Get hardware stats
s.router.HandleFunc("/api/admin/hardwarestats", middleware.RequireAdminAuth(s.handlers.GetHardwareStats))
// Get a a detailed list of currently connected chat clients
s.router.HandleFunc("/api/admin/chat/clients", middleware.RequireAdminAuth(s.handlers.GetConnectedChatClients))
// Get all logs
s.router.HandleFunc("/api/admin/logs", middleware.RequireAdminAuth(s.handlers.GetLogs))
// Get warning/error logs
s.router.HandleFunc("/api/admin/logs/warnings", middleware.RequireAdminAuth(s.handlers.GetWarnings))
// Get all chat messages for the admin, unfiltered.
s.router.HandleFunc("/api/admin/chat/messages", middleware.RequireAdminAuth(s.handlers.GetAdminChatMessages))
// Update chat message visibility
s.router.HandleFunc("/api/admin/chat/messagevisibility", middleware.RequireAdminAuth(s.handlers.UpdateMessageVisibility))
// Enable/disable a user
s.router.HandleFunc("/api/admin/chat/users/setenabled", middleware.RequireAdminAuth(s.handlers.UpdateUserEnabled))
// Ban/unban an IP address
s.router.HandleFunc("/api/admin/chat/users/ipbans/create", middleware.RequireAdminAuth(s.handlers.BanIPAddress))
// Remove an IP address ban
s.router.HandleFunc("/api/admin/chat/users/ipbans/remove", middleware.RequireAdminAuth(s.handlers.UnBanIPAddress))
// Return all the banned IP addresses
s.router.HandleFunc("/api/admin/chat/users/ipbans", middleware.RequireAdminAuth(s.handlers.GetIPAddressBans))
// Get a list of disabled users
s.router.HandleFunc("/api/admin/chat/users/disabled", middleware.RequireAdminAuth(s.handlers.GetDisabledUsers))
// Set moderator status for a user
s.router.HandleFunc("/api/admin/chat/users/setmoderator", middleware.RequireAdminAuth(s.handlers.UpdateUserModerator))
// Get a list of moderator users
s.router.HandleFunc("/api/admin/chat/users/moderators", middleware.RequireAdminAuth(s.handlers.GetModerators))
// return followers
s.router.HandleFunc("/api/admin/followers", middleware.RequireAdminAuth(middleware.HandlePagination(s.handlers.GetFollowers)))
// Get a list of pending follow requests
s.router.HandleFunc("/api/admin/followers/pending", middleware.RequireAdminAuth(s.handlers.GetPendingFollowRequests))
// Get a list of rejected or blocked follows
s.router.HandleFunc("/api/admin/followers/blocked", middleware.RequireAdminAuth(s.handlers.GetBlockedAndRejectedFollowers))
// Set the following state of a follower or follow request.
s.router.HandleFunc("/api/admin/followers/approve", middleware.RequireAdminAuth(s.handlers.ApproveFollower))
// Upload custom emoji
s.router.HandleFunc("/api/admin/emoji/upload", middleware.RequireAdminAuth(s.handlers.UploadCustomEmoji))
// Delete custom emoji
s.router.HandleFunc("/api/admin/emoji/delete", middleware.RequireAdminAuth(s.handlers.DeleteCustomEmoji))
// Update config values
// Change the current streaming key in memory
s.router.HandleFunc("/api/admin/config/adminpass", middleware.RequireAdminAuth(s.handlers.SetAdminPassword))
// Set an array of valid stream keys
s.router.HandleFunc("/api/admin/config/streamkeys", middleware.RequireAdminAuth(s.handlers.SetStreamKeys))
// Change the extra page content in memory
s.router.HandleFunc("/api/admin/config/pagecontent", middleware.RequireAdminAuth(s.handlers.SetExtraPageContent))
// Stream title
s.router.HandleFunc("/api/admin/config/streamtitle", middleware.RequireAdminAuth(s.handlers.SetStreamTitle))
// Server name
s.router.HandleFunc("/api/admin/config/name", middleware.RequireAdminAuth(s.handlers.SetServerName))
// Server summary
s.router.HandleFunc("/api/admin/config/serversummary", middleware.RequireAdminAuth(s.handlers.SetServerSummary))
// Offline message
s.router.HandleFunc("/api/admin/config/offlinemessage", middleware.RequireAdminAuth(s.handlers.SetCustomOfflineMessage))
// Server welcome message
s.router.HandleFunc("/api/admin/config/welcomemessage", middleware.RequireAdminAuth(s.handlers.SetServerWelcomeMessage))
// Disable chat
s.router.HandleFunc("/api/admin/config/chat/disable", middleware.RequireAdminAuth(s.handlers.SetChatDisabled))
// Disable chat user join messages
s.router.HandleFunc("/api/admin/config/chat/joinmessagesenabled", middleware.RequireAdminAuth(s.handlers.SetChatJoinMessagesEnabled))
// Enable/disable chat established user mode
s.router.HandleFunc("/api/admin/config/chat/establishedusermode", middleware.RequireAdminAuth(s.handlers.SetEnableEstablishedChatUserMode))
// Set chat usernames that are not allowed
s.router.HandleFunc("/api/admin/config/chat/forbiddenusernames", middleware.RequireAdminAuth(s.handlers.SetForbiddenUsernameList))
// Set the suggested chat usernames that will be assigned automatically
s.router.HandleFunc("/api/admin/config/chat/suggestedusernames", middleware.RequireAdminAuth(s.handlers.SetSuggestedUsernameList))
// Set video codec
s.router.HandleFunc("/api/admin/config/video/codec", middleware.RequireAdminAuth(s.handlers.SetVideoCodec))
// Set style/color/css values
s.router.HandleFunc("/api/admin/config/appearance", middleware.RequireAdminAuth(s.handlers.SetCustomColorVariableValues))
// Return all webhooks
s.router.HandleFunc("/api/admin/webhooks", middleware.RequireAdminAuth(s.handlers.GetWebhooks))
// Delete a single webhook
s.router.HandleFunc("/api/admin/webhooks/delete", middleware.RequireAdminAuth(s.handlers.DeleteWebhook))
// Create a single webhook
s.router.HandleFunc("/api/admin/webhooks/create", middleware.RequireAdminAuth(s.handlers.CreateWebhook))
// Get all access tokens
s.router.HandleFunc("/api/admin/accesstokens", middleware.RequireAdminAuth(s.handlers.GetExternalAPIUsers))
// Delete a single access token
s.router.HandleFunc("/api/admin/accesstokens/delete", middleware.RequireAdminAuth(s.handlers.DeleteExternalAPIUser))
// Create a single access token
s.router.HandleFunc("/api/admin/accesstokens/create", middleware.RequireAdminAuth(s.handlers.CreateExternalAPIUser))
// Return the auto-update features that are supported for this instance.
s.router.HandleFunc("/api/admin/update/options", middleware.RequireAdminAuth(s.handlers.AutoUpdateOptions))
// Begin the auto update
s.router.HandleFunc("/api/admin/update/start", middleware.RequireAdminAuth(s.handlers.AutoUpdateStart))
// Force quit the service to restart it
s.router.HandleFunc("/api/admin/update/forcequit", middleware.RequireAdminAuth(s.handlers.AutoUpdateForceQuit))
// Logo path
s.router.HandleFunc("/api/admin/config/logo", middleware.RequireAdminAuth(s.handlers.SetLogo))
// Server tags
s.router.HandleFunc("/api/admin/config/tags", middleware.RequireAdminAuth(s.handlers.SetTags))
// ffmpeg
s.router.HandleFunc("/api/admin/config/ffmpegpath", middleware.RequireAdminAuth(s.handlers.SetFfmpegPath))
// Server http port
s.router.HandleFunc("/api/admin/config/webserverport", middleware.RequireAdminAuth(s.handlers.SetWebServerPort))
// Server http listen address
s.router.HandleFunc("/api/admin/config/webserverip", middleware.RequireAdminAuth(s.handlers.SetWebServerIP))
// Server rtmp port
s.router.HandleFunc("/api/admin/config/rtmpserverport", middleware.RequireAdminAuth(s.handlers.SetRTMPServerPort))
// Websocket host override
s.router.HandleFunc("/api/admin/config/sockethostoverride", middleware.RequireAdminAuth(s.handlers.SetSocketHostOverride))
// Custom video serving endpoint
s.router.HandleFunc("/api/admin/config/videoservingendpoint", middleware.RequireAdminAuth(s.handlers.SetVideoServingEndpoint))
// Is server marked as NSFW
s.router.HandleFunc("/api/admin/config/nsfw", middleware.RequireAdminAuth(s.handlers.SetNSFW))
// directory enabled
s.router.HandleFunc("/api/admin/config/directoryenabled", middleware.RequireAdminAuth(s.handlers.SetDirectoryEnabled))
// social handles
s.router.HandleFunc("/api/admin/config/socialhandles", middleware.RequireAdminAuth(s.handlers.SetSocialHandles))
// set the number of video segments and duration per segment in a playlist
s.router.HandleFunc("/api/admin/config/video/streamlatencylevel", middleware.RequireAdminAuth(s.handlers.SetStreamLatencyLevel))
// set an array of video output configurations
s.router.HandleFunc("/api/admin/config/video/streamoutputvariants", middleware.RequireAdminAuth(s.handlers.SetStreamOutputVariants))
// set s3 configuration
s.router.HandleFunc("/api/admin/config/s3", middleware.RequireAdminAuth(s.handlers.SetS3Configuration))
// set server url
s.router.HandleFunc("/api/admin/config/serverurl", middleware.RequireAdminAuth(s.handlers.SetServerURL))
// reset the YP registration
s.router.HandleFunc("/api/admin/yp/reset", middleware.RequireAdminAuth(s.handlers.ResetYPRegistration))
// set external action links
s.router.HandleFunc("/api/admin/config/externalactions", middleware.RequireAdminAuth(s.handlers.SetExternalActions))
// set custom style css
s.router.HandleFunc("/api/admin/config/customstyles", middleware.RequireAdminAuth(s.handlers.SetCustomStyles))
// set custom style javascript
s.router.HandleFunc("/api/admin/config/customjavascript", middleware.RequireAdminAuth(s.handlers.SetCustomJavascript))
// Video playback metrics
s.router.HandleFunc("/api/admin/metrics/video", middleware.RequireAdminAuth(s.handlers.GetVideoPlaybackMetrics))
// Is the viewer count hidden from viewers
s.router.HandleFunc("/api/admin/config/hideviewercount", middleware.RequireAdminAuth(s.handlers.SetHideViewerCount))
// set disabling of search indexing
s.router.HandleFunc("/api/admin/config/disablesearchindexing", middleware.RequireAdminAuth(s.handlers.SetDisableSearchIndexing))
// enable/disable federation features
s.router.HandleFunc("/api/admin/config/federation/enable", middleware.RequireAdminAuth(s.handlers.SetFederationEnabled))
// set if federation activities are private
s.router.HandleFunc("/api/admin/config/federation/private", middleware.RequireAdminAuth(s.handlers.SetFederationActivityPrivate))
// set if fediverse engagement appears in chat
s.router.HandleFunc("/api/admin/config/federation/showengagement", middleware.RequireAdminAuth(s.handlers.SetFederationShowEngagement))
// set local federated username
s.router.HandleFunc("/api/admin/config/federation/username", middleware.RequireAdminAuth(s.handlers.SetFederationUsername))
// set federated go live message
s.router.HandleFunc("/api/admin/config/federation/livemessage", middleware.RequireAdminAuth(s.handlers.SetFederationGoLiveMessage))
// Federation blocked domains
s.router.HandleFunc("/api/admin/config/federation/blockdomains", middleware.RequireAdminAuth(s.handlers.SetFederationBlockDomains))
// send a public message to the Fediverse from the server's user
s.router.HandleFunc("/api/admin/federation/send", middleware.RequireAdminAuth(s.handlers.SendFederatedMessage))
// Return federated activities
s.router.HandleFunc("/api/admin/federation/actions", middleware.RequireAdminAuth(middleware.HandlePagination(s.handlers.GetFederatedActions)))
// Prometheus metrics
s.router.Handle("/api/admin/prometheus", middleware.RequireAdminAuth(func(rw http.ResponseWriter, r *http.Request) {
promhttp.Handler().ServeHTTP(rw, r)
}))
// Configure outbound notification channels.
s.router.HandleFunc("/api/admin/config/notifications/discord", middleware.RequireAdminAuth(s.handlers.SetDiscordNotificationConfiguration))
s.router.HandleFunc("/api/admin/config/notifications/browser", middleware.RequireAdminAuth(s.handlers.SetBrowserNotificationConfiguration))
}
func (s *webServer) setupExternalThirdPartyAPIRoutes() {
// Send a system message to chat
s.router.HandleFunc("/api/integrations/chat/system", middleware.RequireExternalAPIAccessToken(models.ScopeCanSendSystemMessages, s.handlers.SendSystemMessage))
// Send a system message to a single client
s.router.HandleFunc(utils.RestEndpoint("/api/integrations/chat/system/client/{clientId}", middleware.RequireExternalAPIAccessToken(models.ScopeCanSendSystemMessages, s.handlers.SendSystemMessageToConnectedClient)))
// Send a user message to chat *NO LONGER SUPPORTED
s.router.HandleFunc("/api/integrations/chat/user", middleware.RequireExternalAPIAccessToken(models.ScopeCanSendChatMessages, s.handlers.SendUserMessage))
// Send a message to chat as a specific 3rd party bot/integration based on its access token
s.router.HandleFunc("/api/integrations/chat/send", middleware.RequireExternalAPIAccessToken(models.ScopeCanSendChatMessages, s.handlers.SendIntegrationChatMessage))
// Send a user action to chat
s.router.HandleFunc("/api/integrations/chat/action", middleware.RequireExternalAPIAccessToken(models.ScopeCanSendSystemMessages, s.handlers.SendChatAction))
// Hide chat message
s.router.HandleFunc("/api/integrations/chat/messagevisibility", middleware.RequireExternalAPIAccessToken(models.ScopeHasAdminAccess, s.handlers.ExternalUpdateMessageVisibility))
// Stream title
s.router.HandleFunc("/api/integrations/streamtitle", middleware.RequireExternalAPIAccessToken(models.ScopeHasAdminAccess, s.handlers.ExternalSetStreamTitle))
// Get chat history
s.router.HandleFunc("/api/integrations/chat", middleware.RequireExternalAPIAccessToken(models.ScopeHasAdminAccess, s.handlers.ExternalGetChatMessages))
// Connected clients
s.router.HandleFunc("/api/integrations/clients", middleware.RequireExternalAPIAccessToken(models.ScopeHasAdminAccess, s.handlers.ExternalGetConnectedChatClients))
}
func (s *webServer) setupModerationAPIRoutes() {
// Update chat message visibility
s.router.HandleFunc("/api/chat/messagevisibility", middleware.RequireUserModerationScopeAccesstoken(s.handlers.UpdateMessageVisibility))
// Enable/disable a user
s.router.HandleFunc("/api/chat/users/setenabled", middleware.RequireUserModerationScopeAccesstoken(s.handlers.UpdateUserEnabled))
// Get a user's details
s.router.HandleFunc("/api/moderation/chat/user/", middleware.RequireUserModerationScopeAccesstoken(s.handlers.GetUserDetails))
}
// StartRouter will start the federation specific http router.
func (s *webServer) setupActivityPubFederationRoutes() {
// WebFinger
s.router.HandleFunc("/.well-known/webfinger", federation.WebfingerHandler)
// Host Metadata
s.router.HandleFunc("/.well-known/host-meta", federation.HostMetaController)
// Nodeinfo v1
s.router.HandleFunc("/.well-known/nodeinfo", federation.NodeInfoController)
// x-nodeinfo v2
s.router.HandleFunc("/.well-known/x-nodeinfo2", federation.XNodeInfo2Controller)
// Nodeinfo v2
s.router.HandleFunc("/nodeinfo/2.0", federation.NodeInfoV2Controller)
// Instance details
s.router.HandleFunc("/api/v1/instance", federation.InstanceV1Controller)
// Single ActivityPub Actor
s.router.HandleFunc("/federation/user/", middleware.RequireActivityPubOrRedirect(federation.ActorHandler))
// Single AP object
s.router.HandleFunc("/federation/", middleware.RequireActivityPubOrRedirect(federation.ObjectHandler))
}