Initial commit

This commit is contained in:
2025-03-18 13:52:10 +01:00
commit 69d1383c50
5 changed files with 215 additions and 0 deletions

116
staticshield.py Normal file
View File

@@ -0,0 +1,116 @@
import os
import urllib.request
from logging.config import dictConfig
from flask import Flask, redirect, request, send_from_directory, session
from flask_session import Session
dictConfig({
'version': 1,
'formatters': {'default': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
}},
'handlers': {'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default'
}},
'root': {
#'level': 'INFO',
'level': 'DEBUG',
'handlers': ['wsgi']
}
})
app = Flask(__name__)
app.config.from_prefixed_env()
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_TYPE'] = 'filesystem'
Session(app)
config_vars = ['SERVE_DIR', 'MOTHERSHIP']
for config_var in config_vars:
if config_var not in app.config:
print(f'FLASK_{config_var} env var not set')
os.sys.exit(1)
else:
app.logger.info('Config env %s with value "%s"', config_var, app.config[config_var])
# Base dir of the files we want to serve; Flask will take care not to escape this dir
SERVE_DIR = app.config['SERVE_DIR']
# Mothership server and login-url, which will redirect here with a sessionstart/SEKRIT
MOTHERSHIP = app.config['MOTHERSHIP']
@app.route('/<path:path>', methods=['GET', 'POST'])
def all_routes(path):
"""Intercept all routes and proxy it through a session.
Loosely based on https://stackoverflow.com/a/20648053
:param str path: path of file inside the base SERVE_DIR to be served
"""
app.logger.info('Requested %s', path)
if path.startswith('sessionstart/'):
# We got redirected back from the mothership, lets see if the secret we got is really known
# The path we should have gotten back is of the format:
# /sessionstart/SEKRIT_TOKEN/<the_url_to_redirect_on_here_afterwards>
secret_and_redirect = path.split('sessionstart/')[1]
secret_redirect_split = secret_and_redirect.split('/')
secret = secret_redirect_split[0]
redirect_path = '/'
if len(secret_redirect_split) > 1:
redirect_path = '/'.join(secret_redirect_split[1:])
app.logger.info('starting new session with secret "%s"', secret)
print(f'afterwards, redirecting to "{redirect_path}"')
us = f'{request.host_url}{path}'
print(us)
# Ask the mothership if the secret is known to them, to prevent someone from just making up a URL
# Mothership will invalidate this secret token upon handling this request to prevent replay
try:
app.logger.info('verifying token "%s"', secret)
with urllib.request.urlopen(f'{MOTHERSHIP}/verify/{secret}') as response:
challenge_response = response.read()
print(challenge_response)
# Start session if challenge response was successful
session['id'] = secret
return redirect(redirect_path)
except urllib.error.URLError as e:
app.logger.error('lolwtf, server not found: %s', str(e.reason))
return 'Unable to set up session', 403
except urllib.error.HTTPError as e:
app.logger.error('lolnope, server says no: %s', str(e.reason))
return 'Unable to set up session', 403
# Fallback to disallow
return 'Unable to set up session', 403
# check if the users exist or not
if not session.get('id'):
# Our current URL, to which mothership will redirect back including a sessionstart
original_url = f'{request.host_url}{path}'
callback_url = f'{request.host_url}sessionstart/'
app.logger.info('Redirecting to mothership with %s', original_url)
# No session yet, redirect to mothership
app.logger.debug('%s/%s', MOTHERSHIP, original_url)
return redirect(f'{MOTHERSHIP}/login?redirect={original_url}&callback={callback_url}')
file_path = os.path.join(SERVE_DIR, path)
if os.path.isfile(file_path):
app.logger.info('Serving file %s', str(file_path))
# This takes a base directory and a path, and ensures that the path is contained in the directory, which makes it safe to accept user-provided paths.
return send_from_directory(SERVE_DIR, path)
else:
app.logger.error('File not found: %s', str(file_path))
return 'Sorry, 404'
# if text.startswith('favicon'):
# print('hoi')
# else:
# return redirect(url_for('404_error'))
@app.route('/')
def index():
return redirect('/index.html')