ovenemprex/viewer.py
Trysdyn Black bc79be8a96 Add CSRF protection to destructive endpoints
For management endpoints that change server state (restart, ban, etc),
add a referer header check to safeguard against both CSRF and accidental
browser history completion.

Closes #1
2024-12-30 03:18:04 -08:00

55 lines
1.9 KiB
Python

from pathlib import Path
from urllib.parse import urlparse
import cherrypy
from mako.template import Template
import config
import ovenapi
class Viewer:
def __init__(self):
self.webcall_template = Path("template/webcall.mako").read_text(encoding="utf-8")
self.single_template = Path("template/single.mako").read_text(encoding="utf-8")
self.api = ovenapi.OvenAPI(config.API_USER, config.API_PASS)
def app_is_okay(self, app_name):
# If we can't access the API, we can't check if an app exists, just okay it
if not config.is_api_ready():
return True
return self.api.app_exists(app_name)
def _cp_dispatch(self, vpath):
# Extract an app and a page, a la match1/slot1
if len(vpath):
cherrypy.request.params["app"] = vpath.pop(0)
if len(vpath):
cherrypy.request.params["page"] = vpath.pop(0)
# This should leave `/` as our path, triggering index()
return self
@cherrypy.expose
def index(self, **params: dict) -> bytes | str:
if "app" in params and isinstance(params["app"], str):
# Check if the app even exists. If not, fast 404
if not self.app_is_okay(params["app"]):
cherrypy.response.status = 404
return "App not found"
# Get domain for templates
domain = urlparse(cherrypy.request.base).netloc
# Any subpath is presumed to be a single player interface for app/stream
if "page" in params:
return Template(self.single_template).render(
domain=domain, app_name=params["app"], stream_name=params["page"]
)
# No stream key = pass webcall interface
return Template(self.webcall_template).render(domain=domain, app_name=params["app"])
# If we have no subpath at all, return a blank page
return ""