Compare commits

...

3 commits

Author SHA1 Message Date
6bebb69ffa Fix throbber in single-player views
Fixes #8
2025-02-16 17:14:36 -08:00
4c2c82cfc3 Add access key gating to incoming streams
For the moment this is a singleton. One access key will let you stream
to any app or stream key. It's denoted in the form of appending a GET
parameter to the URL like `?access_key=foobarbaz`

This at least means someone who knows the stream URL (frex to view it)
won't also be able to stream.
2025-02-16 17:06:35 -08:00
c934bedd44 Comment config files a bit more 2025-02-16 13:44:33 -08:00
6 changed files with 35 additions and 4 deletions

View file

@ -45,7 +45,7 @@ def webhook_offline() -> None:
requests.post(config.WEBHOOK_URL, timeout=10, json=data, headers=config.WEBHOOK_HEADERS)
def check_authorized(host, app, stream, source) -> bool:
def check_authorized(host, app, stream, source, access_key) -> bool:
# Are we globally disabled?
if config.DISABLED:
return False
@ -57,7 +57,10 @@ def check_authorized(host, app, stream, source) -> bool:
if f"default:{app}:{stream}" in config.DISABLED_KEYS:
return False
# Finally check the provided vhost app/stream
return f"{host}:{app}:{stream}" not in config.DISABLED_KEYS
if f"{host}:{app}:{stream}" in config.DISABLED_KEYS:
return False
# Check for an access key requirement
return not (config.ACCESS_KEY and access_key != config.ACCESS_KEY)
@cherrypy.tools.register("on_end_request")
@ -124,6 +127,16 @@ class Admission:
_, _, host, app, path = input_json["request"]["url"].split("/")[:5]
stream = path.split("?")[0]
# Tokenize out URL GET parameters
params = {}
if "?" in path:
for pair in path.split("?")[1].split("&"):
if "=" in pair:
k, v = pair.split("=", 1)
params[k] = v
else:
params[pair] = None
# Populate variables for our on_end_request tool into request object
cherrypy.request.update_stream = ("default", app, stream)
@ -136,7 +149,7 @@ class Admission:
ip = input_json["client"]["real_ip"]
# Check if stream is authorized
if not check_authorized(host, app, stream, ip):
if not check_authorized(host, app, stream, ip, params.get("access_key")):
cherrypy.log(f"Unauthorized stream key: {app}/{stream}")
return {"allowed": False}

View file

@ -7,6 +7,8 @@ from pathlib import Path
API_USER = os.getenv("OVENMONITOR_API_USER", "")
API_PASS = os.getenv("OVENMONITOR_API_PASSWORD", "")
ACCESS_KEY = os.getenv("OVENMONITOR_ACCESS_KEY", "")
WEBHOOK_URL = os.getenv("OVENMONITOR_WEBHOOK_URL", "")
WEBHOOK_ONLINE = os.getenv("OVENMONITOR_WEBHOOK_ONLINE", "")
WEBHOOK_OFFLINE = os.getenv("OVENMONITOR_WEBHOOK_OFFLINE", "")

View file

@ -0,0 +1,6 @@
[Service]
# This is an access key you wish to require in all inbound streams. This must
# be provided as a GET parameter "access_key". For example:
# rtmp://example.org/app/stream?access_key=loginkeyhere
Environment="OVENMONITOR_ACCESS_KEY=loginkeyhere"

View file

@ -1,3 +1,5 @@
[Service]
# These are the api user and password configured in your OvenMediaEngine
# Server.xml
Environment="OVENMONITOR_API_USER=apiuser"
Environment="OVENMONITOR_API_PASSWORD=apipassword"

View file

@ -1,7 +1,15 @@
[Service]
# These variables are for a Discord webhook, to do stream online/offline
# announcements.
Environment="OVENMONITOR_WEBHOOK_URL=FULL WEBHOOK URL"
Environment="OVENMONITOR_WEBHOOK_ONLINE=TEXT WHEN STREAM GOES ONLINE"
Environment="OVENMONITOR_WEBHOOK_OFFLINE=TEXT WHEN STREAM GOES OFFLINE"
Environment="OVENMONITOR_WEBHOOK_NAME=NAME TO ASSIGN TO WEBHOOK BOT"
# These variables attempt to set the webhook bot above to use a specific avatar
# for each given announcement, based on the stream key that invokes the hook.
# AVATARPATH will be searched for an image named {app}/{stream}.png and use it.
# Otherwise it will use default.png.
# When going offline, offline.png will be used.
Environment="OVENMONITOR_WEBHOOK_AVATARPATH=/srv/http/example.com/assets/webhook_avatars"
Environment="OVENMONITOR_WEBHOOK_AVATARURL=https://example.com/assets/webhook_avatars"

View file

@ -32,7 +32,7 @@
right: 0;
top: 0;
bottom: 0;
background: url(/assets/errorlogo.gif) no-repeat;
background: url(/assets/errorlogo.gif) 0px/96px no-repeat;
z-index: -1;
}