From 4961c398a5c1e57700fdfa64f260ce44d822f10d Mon Sep 17 00:00:00 2001 From: Markus Pawlata Date: Wed, 5 Dec 2018 01:10:40 +0100 Subject: [PATCH] fixed error in refactoring, changed auth-system to multi token, cleanup after major change --- scanner/CachePath.py | 4 +- scanner/floatapp/endpoints.py | 178 ++++++++++++++++------------------ scanner/floatapp/login.py | 41 ++------ scanner/main.py | 4 +- web/js/010-libphotofloat.js | 2 +- 5 files changed, 99 insertions(+), 130 deletions(-) diff --git a/scanner/CachePath.py b/scanner/CachePath.py index 09ae0d8..1d5aae4 100644 --- a/scanner/CachePath.py +++ b/scanner/CachePath.py @@ -7,13 +7,13 @@ def message(category, text): sep = " " else: sep = "--" - print "%s %s%s[%s]%s%s" % ( + print("%s %s%s[%s]%s%s" % ( datetime.now().isoformat(), max(0, message.level) * " |", sep, category, max(1, (14 - len(category))) * " ", - text) + text)) message.level = -1 diff --git a/scanner/floatapp/endpoints.py b/scanner/floatapp/endpoints.py index 6b80727..e41693a 100644 --- a/scanner/floatapp/endpoints.py +++ b/scanner/floatapp/endpoints.py @@ -3,17 +3,17 @@ from mimetypes import guess_type from random import shuffle from flask import Response, abort, json, jsonify, request -from flask_login import current_user, login_user +from flask_login import current_user, login_user, logout_user from floatapp import app from floatapp.jsonp import jsonp -from floatapp.login import (admin_required, admin_user, is_authenticated, - login_required, photo_user, query_is_admin_user, - query_is_photo_user) +from floatapp.login import (admin_required, admin_user, + query_is_admin_user, load_user) from process import send_process from TreeWalker import TreeWalker cwd = os.path.dirname(os.path.abspath(__file__)) +permission_map = app.config.get('PERMISSION_MAP', []) @app.route("/scan") @@ -23,7 +23,6 @@ def scan_photos(): response = send_process([ "stdbuf", "-oL", - os.path.abspath(os.path.join(cwd, "../venv/bin/python")), os.path.abspath(os.path.join(cwd, "../main.py")), os.path.abspath(app.config["ALBUM_PATH"]), os.path.abspath(app.config["CACHE_PATH"]) @@ -36,20 +35,80 @@ def scan_photos(): @app.route("/auth") def login(): - success = False + if request.args.get('logout'): + logout_user() + if current_user.is_authenticated: - success = True - elif (query_is_photo_user(request.form) or - query_is_photo_user(request.args)): - success = login_user(photo_user, remember=True) + return 'Already logged in.' elif (query_is_admin_user(request.form) or query_is_admin_user(request.args)): - success = login_user(admin_user, remember=True) - if not success: - abort(403) + login_user(admin_user, remember=True) + else: + user_id = (request.form.get('username') or + request.args.get('username', None)) + if user_id: + login_user(load_user(user_id), remember=True) + print "logged in {}".format(user_id) + return 'You are now logged in.' + return "" +@app.route("/albums/") +def albums(path): + if not has_permission(path): + abort(403) + + return accel_redirect( + app.config["ALBUM_ACCEL"], app.config["ALBUM_PATH"], path) + + +@app.route("/cache/") +def cache(path): + if not has_permission(path): + abort(403) + + return accel_redirect( + app.config["CACHE_ACCEL"], app.config["CACHE_PATH"], path) + + +@app.route("/photos") +@jsonp +def photos(): + f = open(os.path.join(app.config["CACHE_PATH"], "all_photos.json"), "r") + photos = json.load(f) + f.close() + photos = [photo for photo in photos if has_permission(photo)] + count = int(request.args.get("count", len(photos))) + random = request.args.get("random") == "true" + if random: + shuffle(photos) + else: + photos.reverse() + response = jsonify(photos=photos[0:count]) + response.cache_control.no_cache = True + return response + + +def accel_redirect(internal, real, relative_name): + real_path = os.path.join(real, relative_name) + internal_path = os.path.join(internal, relative_name) + if not os.path.isfile(real_path): + abort(404) + mimetype = None + types = guess_type(real_path) + if len(types) != 0: + mimetype = types[0] + response = Response(mimetype=mimetype) + response.headers.add("X-Accel-Redirect", internal_path) + response.cache_control.public = True + if mimetype == "application/json": + response.cache_control.max_age = 3600 + else: + response.cache_control.max_age = 29030400 + return response + + def cache_base(path): path = path.replace( '/', '-').replace( @@ -77,84 +136,15 @@ def cache_base(path): return path -auth_list = [] - - -def read_auth_list(): - global auth_list, cwd - f = open(os.path.join(cwd, "auth.txt"), "r") - paths = [] - for path in f: - path = path.strip() - paths.append(path) - paths.append(cache_base(path)) - f.close() - auth_list = paths - - -# TODO: Make this run via inotify -read_auth_list() - - -def check_permissions(path): - if not is_authenticated(): - for auth_path in auth_list: - if path.startswith(auth_path): - abort(403) - - -@app.route("/albums/") -def albums(path): - check_permissions(path) - return accel_redirect( - app.config["ALBUM_ACCEL"], app.config["ALBUM_PATH"], path) - - -@app.route("/cache/") -def cache(path): - check_permissions(path) - return accel_redirect( - app.config["CACHE_ACCEL"], app.config["CACHE_PATH"], path) - - -def accel_redirect(internal, real, relative_name): - real_path = os.path.join(real, relative_name) - internal_path = os.path.join(internal, relative_name) - if not os.path.isfile(real_path): - abort(404) - mimetype = None - types = guess_type(real_path) - if len(types) != 0: - mimetype = types[0] - response = Response(mimetype=mimetype) - response.headers.add("X-Accel-Redirect", internal_path) - response.cache_control.public = True - if mimetype == "application/json": - response.cache_control.max_age = 3600 - else: - response.cache_control.max_age = 29030400 - return response - - -@app.route("/photos") -@jsonp -def photos(): - f = open(os.path.join(app.config["CACHE_PATH"], "all_photos.json"), "r") - photos = json.load(f) - f.close() - if not is_authenticated(): - def allowed(photo): - for auth_path in auth_list: - if photo.startswith(auth_path): - return False - return True - photos = [photo for photo in photos if allowed(photo)] - count = int(request.args.get("count", len(photos))) - random = request.args.get("random") == "true" - if random: - shuffle(photos) - else: - photos.reverse() - response = jsonify(photos=photos[0:count]) - response.cache_control.no_cache = True - return response +def has_permission(path): + for auth_path in permission_map.keys(): + # this is a protected object + if (path.startswith(auth_path) or + path.startswith(cache_base(auth_path))): + if current_user.is_anonymous: + return False + if current_user.id in permission_map.get(auth_path, []): + return True + else: + return False + return True diff --git a/scanner/floatapp/login.py b/scanner/floatapp/login.py index 5b8ab2e..216b720 100644 --- a/scanner/floatapp/login.py +++ b/scanner/floatapp/login.py @@ -9,17 +9,20 @@ class User(UserMixin): self.admin = admin self.id = id -photo_user = User("user") + def __unicode__(self): + return u"{}".format(self.id) + + def __str__(self): + return str(self.id) + admin_user = User("admin", True) @login_manager.user_loader def load_user(id): - if id == "user": - return photo_user - elif id == "admin": + if id == "admin": return admin_user - return None + return User(id) @login_manager.unauthorized_handler @@ -27,17 +30,6 @@ def unauthorized(): return abort(403) -def login_required(fn): - @wraps(fn) - def decorated_view(*args, **kwargs): - if (query_is_admin_user(request.args) or - query_is_photo_user(request.args) or - current_user.is_authenticated): - return fn(*args, **kwargs) - return app.login_manager.unauthorized() - return decorated_view - - def admin_required(fn): @wraps(fn) def decorated_view(*args, **kwargs): @@ -48,21 +40,8 @@ def admin_required(fn): return decorated_view -def query_is_photo_user(query): - username = query.get("username", None) - password = query.get("password", None) - return username == (app.config["PHOTO_USERNAME"] and - password == app.config["PHOTO_PASSWORD"]) - - def query_is_admin_user(query): username = query.get("username", None) password = query.get("password", None) - return username == (app.config["ADMIN_USERNAME"] and - password == app.config["ADMIN_PASSWORD"]) - - -def is_authenticated(): - return (query_is_admin_user(request.args) or - query_is_photo_user(request.args) or - current_user.is_authenticated) + return (username == app.config["ADMIN_USERNAME"] and + password == app.config["ADMIN_PASSWORD"]) diff --git a/scanner/main.py b/scanner/main.py index c235751..785af80 100755 --- a/scanner/main.py +++ b/scanner/main.py @@ -11,11 +11,11 @@ def main(): sys.setdefaultencoding("UTF-8") if len(sys.argv) != 3: - print "usage: %s ALBUM_PATH CACHE_PATH" % sys.argv[0] + print("usage: %s ALBUM_PATH CACHE_PATH" % sys.argv[0]) return try: - os.umask(022) + os.umask(0o22) TreeWalker(sys.argv[1], sys.argv[2]) except KeyboardInterrupt: message("keyboard", "CTRL+C pressed, quitting.") diff --git a/web/js/010-libphotofloat.js b/web/js/010-libphotofloat.js index dc72e6e..9026ea8 100644 --- a/web/js/010-libphotofloat.js +++ b/web/js/010-libphotofloat.js @@ -92,7 +92,7 @@ $.ajax({ type: "GET", dataType: "text", - url: "auth?username=photos&password=" + password, + url: "auth?username=" + password, success: function() { result(true); },