use buckler for security
This commit is contained in:
parent
318517514c
commit
0df4d14bdf
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@ __pycache__/
|
||||||
secret_key
|
secret_key
|
||||||
*.db
|
*.db
|
||||||
*.swp
|
*.swp
|
||||||
|
config.py
|
||||||
|
|
107
buckler_flask.py
Normal file
107
buckler_flask.py
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Session interface middlewares to integrate the flask app with Buckler.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from flask.sessions import SessionInterface, SessionMixin
|
||||||
|
from flask import session, redirect, request
|
||||||
|
|
||||||
|
import config
|
||||||
|
|
||||||
|
class BucklerSessionInterface(SessionInterface):
|
||||||
|
"""
|
||||||
|
Queries the Buckler server for session data to the current user and
|
||||||
|
application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.url = config.buckler['url']
|
||||||
|
self.app_id = config.buckler['app_id']
|
||||||
|
self.app_key = config.buckler['app_key']
|
||||||
|
|
||||||
|
def open_session(self, app, request):
|
||||||
|
"""Called when a request is initiated."""
|
||||||
|
user_id = request.cookies.get('userid')
|
||||||
|
user_sid = request.cookies.get('session')
|
||||||
|
|
||||||
|
params = {
|
||||||
|
'app_id': self.app_id,
|
||||||
|
'app_key': self.app_key,
|
||||||
|
'userid': user_id,
|
||||||
|
'session': user_sid
|
||||||
|
}
|
||||||
|
params = urllib.parse.urlencode(params)
|
||||||
|
req = urllib.request.Request(self.url + f"/get_session?{params}")
|
||||||
|
res = urllib.request.urlopen(req)
|
||||||
|
data = json.loads(res.read())
|
||||||
|
if data.get('error'):
|
||||||
|
return None
|
||||||
|
session = BucklerSession()
|
||||||
|
session.update(data['session_data'])
|
||||||
|
session.meta = data['meta']
|
||||||
|
session.cookies = request.cookies
|
||||||
|
return session
|
||||||
|
|
||||||
|
def save_session(self, app, session, response):
|
||||||
|
"""Called at the end of a request."""
|
||||||
|
if not session.modified:
|
||||||
|
return
|
||||||
|
user_id = session.meta.get('user_id')
|
||||||
|
user_sid = session.meta.get('user_sid')
|
||||||
|
|
||||||
|
params = {
|
||||||
|
'app_id': self.app_id,
|
||||||
|
'app_key': self.app_key,
|
||||||
|
'userid': user_id,
|
||||||
|
'session': user_sid
|
||||||
|
}
|
||||||
|
params = urllib.parse.urlencode(params)
|
||||||
|
data = json.dumps(session)
|
||||||
|
req = urllib.request.Request(
|
||||||
|
self.url + f"/set_session?{params}",
|
||||||
|
data=data.encode('utf8'),
|
||||||
|
method='POST')
|
||||||
|
res = urllib.request.urlopen(req)
|
||||||
|
|
||||||
|
last_used = datetime.fromisoformat(session.meta['last_used'])
|
||||||
|
now = datetime.now(last_used.tzinfo)
|
||||||
|
delta = now - last_used
|
||||||
|
if delta.seconds > 600:
|
||||||
|
response.set_cookie(
|
||||||
|
'userid',
|
||||||
|
session.cookies['userid'],
|
||||||
|
max_age=30*24*60*60,
|
||||||
|
secure=True,
|
||||||
|
httponly=True)
|
||||||
|
response.set_cookie(
|
||||||
|
'session',
|
||||||
|
session.cookies['session'],
|
||||||
|
max_age=30*24*60*60,
|
||||||
|
secure=True,
|
||||||
|
httponly=True)
|
||||||
|
|
||||||
|
|
||||||
|
class BucklerSession(dict, SessionMixin):
|
||||||
|
"""A server side session class based on the Buckler security shield."""
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.modified = False
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
super().__setitem__(key, value)
|
||||||
|
self.modified = True
|
||||||
|
|
||||||
|
|
||||||
|
def require_auth():
|
||||||
|
"""
|
||||||
|
Requires the user to be properly authenticated with Buckler before
|
||||||
|
accessing any views on the application.
|
||||||
|
"""
|
||||||
|
if not hasattr(session, 'meta'):
|
||||||
|
resp = redirect(config.buckler['login_url'])
|
||||||
|
resp.set_cookie('redirect', request.url)
|
||||||
|
return resp
|
11
config.py.template
Executable file
11
config.py.template
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Configuration settings for fileHost.
|
||||||
|
`buckler` specifies settings pertaining to the Buckler server.
|
||||||
|
"""
|
||||||
|
buckler = {
|
||||||
|
'url': "http://127.0.0.1:5400/buckler",
|
||||||
|
'app_id': 1,
|
||||||
|
'app_key': """password""",
|
||||||
|
'login_url': "/buckler/login",
|
||||||
|
}
|
22
fileHost.py
22
fileHost.py
|
@ -23,7 +23,11 @@ from flask_paranoid import Paranoid
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
import buckler_flask
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
app.session_interface = buckler_flask.BucklerSessionInterface()
|
||||||
|
app.before_request(buckler_flask.require_auth)
|
||||||
app.config['MAX_CONTENT_LENGTH'] = 128 * 1024 * 1024
|
app.config['MAX_CONTENT_LENGTH'] = 128 * 1024 * 1024
|
||||||
app.config["UPLOAD_DIR"] = "/var/www/html/up"
|
app.config["UPLOAD_DIR"] = "/var/www/html/up"
|
||||||
app.config["UPLOAD_URL"] = "https://steelbea.me/up/"
|
app.config["UPLOAD_URL"] = "https://steelbea.me/up/"
|
||||||
|
@ -163,7 +167,7 @@ def login_required(url=None):
|
||||||
def actual_decorator(func):
|
def actual_decorator(func):
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
def _nop(*args, **kwargs):
|
def _nop(*args, **kwargs):
|
||||||
username = session.get("username")
|
username = session.meta['username']
|
||||||
if verify_username(username):
|
if verify_username(username):
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
|
@ -186,7 +190,7 @@ def deleteFile():
|
||||||
"""
|
"""
|
||||||
Allows a user to delete a file from the upload directory and the database.
|
Allows a user to delete a file from the upload directory and the database.
|
||||||
"""
|
"""
|
||||||
username = session.get("username")
|
username = session.meta['username']
|
||||||
filename = request.form.get("fname")
|
filename = request.form.get("fname")
|
||||||
|
|
||||||
if not verify_username(username):
|
if not verify_username(username):
|
||||||
|
@ -238,7 +242,7 @@ def logout():
|
||||||
|
|
||||||
|
|
||||||
@app.route("/change_password", methods=["POST", "GET"])
|
@app.route("/change_password", methods=["POST", "GET"])
|
||||||
@login_required()
|
#@login_required()
|
||||||
def change_password():
|
def change_password():
|
||||||
"""
|
"""
|
||||||
Allows the user to change their password.
|
Allows the user to change their password.
|
||||||
|
@ -246,7 +250,7 @@ def change_password():
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
return render_template("change_password.html")
|
return render_template("change_password.html")
|
||||||
|
|
||||||
username = session.get("username")
|
username = session.meta['username']
|
||||||
current_password = request.form.get("current_password")
|
current_password = request.form.get("current_password")
|
||||||
new_password = request.form.get("new_password")
|
new_password = request.form.get("new_password")
|
||||||
new_password_verify = request.form.get("new_password_verify")
|
new_password_verify = request.form.get("new_password_verify")
|
||||||
|
@ -283,12 +287,12 @@ def login():
|
||||||
|
|
||||||
|
|
||||||
@app.route("/manage_uploads", methods=["POST", "GET"])
|
@app.route("/manage_uploads", methods=["POST", "GET"])
|
||||||
@login_required()
|
#@login_required()
|
||||||
def manage_uploads():
|
def manage_uploads():
|
||||||
"""
|
"""
|
||||||
Allows the user to view and/or delete uploads they've made.
|
Allows the user to view and/or delete uploads they've made.
|
||||||
"""
|
"""
|
||||||
username = session.get("username")
|
username = session.meta['username']
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
uploads = db_execute(
|
uploads = db_execute(
|
||||||
"SELECT filename, uploaded_date FROM uploads WHERE uploaded_by = ?",
|
"SELECT filename, uploaded_date FROM uploads WHERE uploaded_by = ?",
|
||||||
|
@ -333,12 +337,12 @@ def gallery(username):
|
||||||
|
|
||||||
|
|
||||||
@app.route("/upload", methods=["POST"])
|
@app.route("/upload", methods=["POST"])
|
||||||
@login_required("login")
|
#@login_required("login")
|
||||||
def upload():
|
def upload():
|
||||||
"""
|
"""
|
||||||
Saves the uploaded files and returns URLs pointing to them.
|
Saves the uploaded files and returns URLs pointing to them.
|
||||||
"""
|
"""
|
||||||
username = session.get("username")
|
username = session.meta['username']
|
||||||
|
|
||||||
if request.form.get("url"):
|
if request.form.get("url"):
|
||||||
try:
|
try:
|
||||||
|
@ -397,7 +401,7 @@ def upload():
|
||||||
|
|
||||||
|
|
||||||
@app.route("/", methods=["GET", "POST"])
|
@app.route("/", methods=["GET", "POST"])
|
||||||
@login_required("login")
|
#@login_required("login")
|
||||||
def index():
|
def index():
|
||||||
"""
|
"""
|
||||||
Saves the uploaded file and returns a URL pointing to it.
|
Saves the uploaded file and returns a URL pointing to it.
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
<title>Let's uploading boys!</title>
|
<title>Let's uploading boys!</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
Hello, {{ session.username }}<br>
|
Hello, {{ session.meta['username'] }}<br>
|
||||||
<a href="{{ url_for('change_password') }}">Change password</a><br>
|
<a href="{{ url_for('change_password') }}">Change password</a><br>
|
||||||
<a href="{{ url_for('logout') }}">Logout</a><br>
|
<a href="{{ url_for('logout') }}">Logout</a><br>
|
||||||
<a href="{{ url_for('manage_uploads') }}">Manage Uploads</a><br>
|
<a href="{{ url_for('manage_uploads') }}">Manage Uploads</a><br>
|
||||||
<a href="{{ url_for('gallery', username=session.username) }}">Public Gallery</a><br>
|
<a href="{{ url_for('gallery', username=session.meta['username']) }}">Public Gallery</a><br>
|
||||||
<form method="post" enctype="multipart/form-data" action="{{ url_for('upload') }}">
|
<form method="post" enctype="multipart/form-data" action="{{ url_for('upload') }}">
|
||||||
<p>Select file to upload:
|
<p>Select file to upload:
|
||||||
<p><input type="file" name="files" multiple><br>
|
<p><input type="file" name="files" multiple><br>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user