restreamer: Cleanup around argument processing

pull/5/head
Mike Lang 6 years ago
parent a1fa60828d
commit 5942091d1a

@ -1,13 +1,13 @@
import errno import errno
import functools
import json import json
import os import os
import dateutil.parser
from flask import Flask, url_for, request, abort from flask import Flask, url_for, request, abort
from gevent.pywsgi import WSGIServer from gevent.pywsgi import WSGIServer
import dateutil.parser
from common import get_best_segments from common import get_best_segments
import generate_hls import generate_hls
@ -41,14 +41,27 @@ def listdir(path, error=True):
return [] return []
def has_path_args(fn):
"""Decorator to wrap routes which take args which are to be used as parts of a filepath.
Disallows hidden folders and path traversal, and converts unicode to bytes.
"""
@functools.wraps(fn)
def _has_path_args(**kwargs):
kwargs = {key: value.encode('utf-8') for key, value in kwargs.items()}
for key, value in kwargs.items():
# Disallowing a leading . prevents both hidden files and path traversal ("..")
if value.startswith('.'):
return "Bad {}: May not start with a period".format(key), 403
return fn(**kwargs)
return _has_path_args
@app.route('/files/<stream>/<variant>') @app.route('/files/<stream>/<variant>')
@has_path_args
def list_hours(stream, variant): def list_hours(stream, variant):
"""Returns a JSON list of hours for the given stream and variant for which """Returns a JSON list of hours for the given stream and variant for which
there may be segments available. Returns empty list on non-existent streams, etc. there may be segments available. Returns empty list on non-existent streams, etc.
""" """
# Check no-one's being sneaky with path traversal or hidden folders
if any(arg.startswith('.') for arg in (stream, variant)):
return "Parts may not start with period", 403
path = os.path.join( path = os.path.join(
app.static_folder, app.static_folder,
stream, stream,
@ -58,13 +71,11 @@ def list_hours(stream, variant):
@app.route('/files/<stream>/<variant>/<hour>') @app.route('/files/<stream>/<variant>/<hour>')
@has_path_args
def list_segments(stream, variant, hour): def list_segments(stream, variant, hour):
"""Returns a JSON list of segment files for a given stream, variant and hour. """Returns a JSON list of segment files for a given stream, variant and hour.
Returns empty list on non-existant streams, etc. Returns empty list on non-existant streams, etc.
""" """
# Check no-one's being sneaky with path traversal or hidden folders
if any(arg.startswith('.') for arg in (stream, variant, hour)):
return "Parts may not start with period", 403
path = os.path.join( path = os.path.join(
app.static_folder, app.static_folder,
stream, stream,
@ -75,15 +86,13 @@ def list_segments(stream, variant, hour):
@app.route('/playlist/<stream>.m3u8') @app.route('/playlist/<stream>.m3u8')
@has_path_args
def generate_master_playlist(stream): def generate_master_playlist(stream):
"""Returns a HLS master playlist for the given stream. """Returns a HLS master playlist for the given stream.
Takes optional params: Takes optional params:
start, end: The time to begin and end the stream at. start, end: The time to begin and end the stream at.
See generate_media_playlist for details. See generate_media_playlist for details.
""" """
# path traversal / hidden folders
if stream.startswith('.'):
return "Stream may not start with period", 403
variants = listdir(os.path.join(app.static_folder, stream)) variants = listdir(os.path.join(app.static_folder, stream))
playlists = { playlists = {
variant: url_for('generate_media_playlist', stream=stream, variant=variant, **request.args) variant: url_for('generate_media_playlist', stream=stream, variant=variant, **request.args)
@ -93,12 +102,8 @@ def generate_master_playlist(stream):
@app.route('/playlist/<stream>/<variant>.m3u8') @app.route('/playlist/<stream>/<variant>.m3u8')
@has_path_args
def generate_media_playlist(stream, variant): def generate_media_playlist(stream, variant):
# path traversal / hidden folders
if stream.startswith('.'):
return "Stream may not start with period", 403
if variant.startswith('.'):
return "Variant may not start with period", 403
#TODO handle no start/end #TODO handle no start/end
#TODO error handling of args #TODO error handling of args
# TODO lots of other stuff # TODO lots of other stuff

Loading…
Cancel
Save