diff --git a/zerobin/routes.py b/zerobin/routes.py index bdb06a8..c1f8a59 100644 --- a/zerobin/routes.py +++ b/zerobin/routes.py @@ -7,12 +7,21 @@ import sys import _thread as thread -import urllib.parse as urlparse +from urllib.parse import urlparse, parse_qs from datetime import datetime, timedelta import bottle -from bottle import Bottle, static_file, view, request, HTTPResponse, redirect, abort +from bottle import ( + Bottle, + debug, + static_file, + view, + request, + HTTPResponse, + redirect, + abort, +) from beaker.middleware import SessionMiddleware @@ -37,15 +46,9 @@ GLOBAL_CONTEXT = { } -app = SessionMiddleware( - Bottle(), - { - "session.type": "file", - "session.cookie_expires": 300, - "session.data_dir": settings.SESSIONS_DIR, - "session.auto": True, - }, -) +app = Bottle() + +ADMIN_LOGIN_URL = settings.ADMIN_URL + "login/" @app.route("/") @@ -54,61 +57,68 @@ def index(): return GLOBAL_CONTEXT -@app.route("/faq/") +@app.get("/faq/") @view("faq") def faq(): return GLOBAL_CONTEXT -@app.route(settings.ADMIN_URL, method="GET") +@app.get(settings.ADMIN_URL) +@app.post(settings.ADMIN_URL) @view("admin") def admin(): session = request.environ.get("beaker.session") if not session or not session.get("is_authenticated"): - redirect(settings.ADMIN_URL + "/login") + redirect(ADMIN_LOGIN_URL) - return {} + paste_id = request.forms.get("paste", "") + if paste_id: + try: + if "/paste/" in paste_id: + paste_id = urlparse(paste_id).path.split("/path/")[-1] + paste = Paste.load(paste_id) + paste.delete() + except (TypeError, ValueError, FileNotFoundError): + return {"status": "error", "message": f"Cannot find paste '{paste_id}'"} + + return {"status": "ok", "message": "Paste deleted"} + + return {"status": "ok", **GLOBAL_CONTEXT} -@app.route(settings.ADMIN_URL + "/:paste_id", method="DELETE") -@view("admin") -def delete_paste_from_admin(paste_id): - session = request.environ.get("beaker.session") - if not session or not session.get("is_authenticated"): - abort(403, "Sorry, access denied.") - - try: - paste = Paste.load(paste_id) - except (TypeError, ValueError): - return error404(ValueError) - - paste.delete() - - return {"status": "ok", "message": "Paste deleted"} - - -@app.route(settings.ADMIN_URL + "/login") +@app.get(ADMIN_LOGIN_URL) +@app.post(ADMIN_LOGIN_URL) +@view("login") def login(): password = request.forms.get("password") if password: if not check_password(password): - return {"error": "Wrong password"} + return {"status": "error", "message": "Wrong password", **GLOBAL_CONTEXT} session = request.environ.get("beaker.session") session["is_authenticated"] = True session.save() redirect(settings.ADMIN_URL) - else: - return {} + + return {"status": "ok", **GLOBAL_CONTEXT} -@app.route("/paste/create", method="POST") +@app.post(settings.ADMIN_URL + "logout/") +@view("logout") +def logout(): + session = request.environ.get("beaker.session") + session["is_authenticated"] = False + session.save() + redirect("/") + + +@app.post("/paste/create") def create_paste(): try: - body = urlparse.parse_qs(request.body.read(int(settings.MAX_SIZE * 1.1))) + body = parse_qs(request.body.read(int(settings.MAX_SIZE * 1.1))) except ValueError: return {"status": "error", "message": "Wrong data payload."} @@ -158,7 +168,7 @@ def create_paste(): } -@app.route("/paste/:paste_id", method="GET") +@app.get("/paste/:paste_id") @view("paste") def display_paste(paste_id): @@ -191,7 +201,7 @@ def display_paste(paste_id): return {"paste": paste, "keep_alive": keep_alive, **GLOBAL_CONTEXT} -@app.route("/paste/:paste_id", method="DELETE") +@app.delete("/paste/:paste_id") def delete_paste(paste_id): try: @@ -216,7 +226,7 @@ def error404(code): return GLOBAL_CONTEXT -@app.route("/static/") +@app.get("/static/") def server_static(filename): return static_file(filename, root=settings.STATIC_FILES_ROOT) @@ -249,3 +259,14 @@ def get_app(debug=None, settings_file="", compressed_static=None, settings=setti bottle.debug(True) return settings, app + + +app = SessionMiddleware( + app, + { + "session.type": "file", + "session.cookie_expires": 300, + "session.data_dir": settings.SESSIONS_DIR, + "session.auto": True, + }, +) diff --git a/zerobin/utils.py b/zerobin/utils.py index c760f8b..fcd7765 100644 --- a/zerobin/utils.py +++ b/zerobin/utils.py @@ -132,9 +132,9 @@ def ensure_var_env(): """ settings.VAR_DIR.mkdir(exist_ok=True, parents=True) - settings.PASTE_FILES_ROOT = VAR_DIR / "content" + settings.PASTE_FILES_ROOT = settings.VAR_DIR / "content" settings.PASTE_FILES_ROOT.mkdir(exist_ok=True) - settings.SESSIONS_DIR = VAR_DIR / "sessions" + settings.SESSIONS_DIR = settings.VAR_DIR / "sessions" settings.SESSIONS_DIR.mkdir(exist_ok=True) secret_key_file = settings.VAR_DIR / "secret_key" @@ -150,7 +150,7 @@ def ensure_var_env(): settings.ADMIN_PASSWORD_FILE = admin_password_file payload = ("admin" + settings.SECRET_KEY).encode("ascii") - settings.ADMIN_URL = "/admin/" + hashlib.sha256(payload).hexdigest() + settings.ADMIN_URL = "/admin/" + hashlib.sha256(payload).hexdigest() + "/" def hash_password(password): @@ -166,7 +166,7 @@ def hash_password(password): def check_password(password): try: - return settings.ADMIN_PASSWORD_FILE.read_bytes() != hash_password(password) + return settings.ADMIN_PASSWORD_FILE.read_bytes() == hash_password(password) except (FileNotFoundError, AttributeError): return False diff --git a/zerobin/views/admin.tpl b/zerobin/views/admin.tpl index ff5072e..14c1a2f 100644 --- a/zerobin/views/admin.tpl +++ b/zerobin/views/admin.tpl @@ -1,32 +1,25 @@ -%if is_authenticated: - -
- + + %if status == "error": +
+ {{message}} +
+ %end
- -
- - -
- - +
+ + +
+ +
+ - %else: -
- -
- - - %end +
+
+ +
+
- % rebase('base', settings=settings, pastes_count=pastes_count) +% rebase('base', settings=settings, pastes_count=pastes_count) diff --git a/zerobin/views/base.tpl b/zerobin/views/base.tpl index b74578c..f3aa0a7 100644 --- a/zerobin/views/base.tpl +++ b/zerobin/views/base.tpl @@ -35,14 +35,14 @@