diff options
| -rw-r--r-- | auth.py | 7 | ||||
| -rw-r--r-- | cors.py | 31 | ||||
| -rw-r--r-- | helpers.py | 13 | ||||
| -rw-r--r-- | routes/auth.py | 6 | ||||
| -rw-r--r-- | routes/media.py | 12 | ||||
| -rw-r--r-- | routes/uploads.py | 30 |
6 files changed, 59 insertions, 40 deletions
@@ -13,6 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. import os, hashlib, base64, jwt, json +from .cors import * from .database import * from bottle import install, HTTPResponse, route, request, default_app, post from bottle_jwt import JWTProviderPlugin, jwt_auth_required, JWTProvider @@ -23,7 +24,7 @@ def calculateUserHash(username : str, password : str) -> object: class AuthBackend(object): def authenticate_user(self, username, password): if username is None or password is None: - raise HTTPResponse("Username or password missing", 400) + raise ParryHTTPResponse("Username or password missing", 400) session = DBSession() try: user = session.query(User).filter_by(name=username, hash=calculateUserHash(username, password).hexdigest()).one() @@ -69,7 +70,7 @@ def auth_basic(f): try: User.query.filter_by(name=request.forms["username"], hash=calculateUserHash(request.forms["username"], request.forms["password"]).hexdigest()).first() except db.orm.exc.NoResultFound: - return HTTPResponse(status=401) + return ParryHTTPResponse(status=401) del request.forms["password"] return f(*args, **kwargs) @@ -79,4 +80,4 @@ def get_user(session : DBSession): try: return session.query(User).filter_by(name=request.get_user()["name"]).one() except db.orm.exc.NoResultFound: - raise HTTPResponse(status=401) + raise ParryHTTPResponse(status=401) @@ -0,0 +1,31 @@ +# Copyright (c) 2018, George Tokmaji + +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. + +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from bottle import HTTPResponse, route, response, hook + +class ParryHTTPResponse(HTTPResponse): + def __init__(self, body="", status=None, headers=None, **more_headers): + more_headers["Access-Control-Allow-Origin"] = "*" + more_headers["Access-Control-Allow-Methods"] = "GET, POST, HEAD, PUT, PATCH, DELETE" + more_headers["Access-Control-Allow-Headers"] = "*" + super().__init__(body, status, headers, **more_headers) + +@route("<path:path>", method="OPTIONS") +def options(path): + return ParryHTTPResponse(status=204) + +@hook("after_request") +def enable_cors(): + response.headers["Access-Control-Allow-Origin"] = "*" + response.headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, PATCH, HEAD" @@ -16,7 +16,7 @@ import sys import os, re, json, math import requests from bson.objectid import ObjectId -from bottle import install, run, Bottle, static_file, response, hook, JSONPlugin, get, post, error +from bottle import install, run, Bottle, static_file, JSONPlugin, get, post, error import threading class ParryEncoder(json.JSONEncoder): @@ -31,7 +31,7 @@ install(JSONPlugin(json_dumps=lambda s: json.dumps(s, cls=ParryEncoder))) os.chdir(os.path.dirname(__file__)) from .auth import * - + def calculateHashForResource(resource : requests.Response) -> object: hashobj = hashlib.sha1() @@ -53,15 +53,6 @@ def calculateHashForFile(file, hashobj : object = None) -> object: return hashobj -@route("<path:path>", method="OPTIONS") -def options(path): - return HTTPResponse(status=204, headers={"Access-Control-Allow-Origin" : "*", "Access-Control-Allow-Methods" : "GET, POST, HEAD, PUT, PATCH, DELETE", "Access-Control-Allow-Headers" : "*"}) - -@hook("after_request") -def enable_cors(): - response.headers["Access-Control-Allow-Origin"] = "*" - response.headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, PATCH, HEAD" - @error(500) def internal_error(error): if request.json is None: diff --git a/routes/auth.py b/routes/auth.py index d6b6ffd..cdcacf1 100644 --- a/routes/auth.py +++ b/routes/auth.py @@ -21,16 +21,16 @@ def post_auth_new(): username = request_data()["username"] password = request_data()["password"] except KeyError as e: - raise HTTPResponse("Username or password missing", 400) + raise ParryHTTPResponse("Username or password missing", 400) hash = calculateUserHash(username, password).hexdigest() try: session.query(User).filter(User.name == username or User.hash == hash).one() - raise HTTPResponse("User already exists", status=409) + raise ParryHTTPResponse("User already exists", status=409) except db.orm.exc.NoResultFound: session.add(User(name=username, hash=hash)) session.commit() - return HTTPResponse(status=303, headers={"Location" : "/api/auth"}) + return ParryHTTPResponse(status=303, headers={"Location" : "/api/auth"}) @get("/api/auth") @jwt_auth_required diff --git a/routes/media.py b/routes/media.py index 7986960..125284b 100644 --- a/routes/media.py +++ b/routes/media.py @@ -36,10 +36,6 @@ def _delete_file(file): pass except OSError: print("Failed to unlink", file.id, file=sys.stderr) - -@get("/api/media") -def get_media(): - notAllowed() @post("/api/media") @jwt_auth_required @@ -48,7 +44,7 @@ def post_media(): f = _upload_file(next(request.files.values())) session.add(f) session.commit() - return HTTPResponse(f.json(), status=201) + return ParryHTTPResponse(f.json(), status=201) @get("/api/media/<id>") def get_media_id(id): @@ -56,7 +52,7 @@ def get_media_id(id): try: file = session.query(File).filter_by(id=id).one() except db.orm.exc.NoResultFound: - raise HTTPResponse(status=404) + raise ParryHTTPResponse(status=404) response.set_header("Content-Type", file.content_type) response.set_header("Content-Length", file.length) @@ -65,8 +61,8 @@ def get_media_id(id): if request.method == "GET": if file.download_url: #return requests.request(request.method, file.download_url, allow_redirects=True) - return HTTPResponse(status=302, headers={"Location" : file.download_url}) + return ParryHTTPResponse(status=302, headers={"Location" : file.download_url}) else: return static_file(str(file.id), os.path.join(os.getcwd(), "media"), file.content_type, download=file.name if request.params.download else False) - raise HTTPResponse(status=404) + raise ParryHTTPResponse(status=404) diff --git a/routes/uploads.py b/routes/uploads.py index bba927d..332b5a4 100644 --- a/routes/uploads.py +++ b/routes/uploads.py @@ -73,10 +73,10 @@ def post_upload(id=None): if id is not None: entry = session.query(Upload).get(id) if not entry: - raise HTTPResponse(status=404) + raise ParryHTTPResponse(status=404) else: if session.query(Upload).filter_by(title=request_data()["title"]).count(): - raise HTTPResponse("An entry with the specified title already exists", 410) + raise ParryHTTPResponse("An entry with the specified title already exists", 410) entry = Upload() @@ -118,7 +118,7 @@ def post_upload(id=None): except KeyError as e: session.rollback() - raise HTTPResponse(f"Missing form value: {e.args[0]}", 400) + raise ParryHTTPResponse(f"Missing form value: {e.args[0]}", 400) session.commit() return _add_upload(entry, session) @@ -131,7 +131,7 @@ def get_upload(id): if entry is not None: return _add_upload(entry, session) - raise HTTPResponse(status=404) + raise ParryHTTPResponse(status=404) @delete("/api/uploads/<id>") @jwt_auth_required @@ -141,10 +141,10 @@ def delete_upload(id): try: entry = session.query(Upload).filter_by(id=id, author=author).one() except db.orm.exc.NoResultFound: - raise HTTPResponse(status=404) + raise ParryHTTPResponse(status=404) if entry.readonly: - raise HTTPResponse("Resource is read-only", 403) + raise ParryHTTPResponse("Resource is read-only", 403) session.delete(entry) for i in [Comment, Vote]: @@ -158,7 +158,7 @@ def delete_upload(id): #TODO: Dependencies session.commit() session.flush() - return HTTPResponse(status=204) + return ParryHTTPResponse(status=204) @get("/api/uploads/<id>/comments") @@ -166,7 +166,7 @@ def get_comments(id): session = DBSession() upload = session.query(Upload).get(id) if upload is None: - raise HTTPResponse("Invalid upload id", 404) + raise ParryHTTPResponse("Invalid upload id", 404) return { "comments" : [{**(comment.json()), **_vote_dummy} for comment in session.query(Comment).filter_by(upload=upload)] @@ -178,7 +178,7 @@ def post_comments(id): session = DBSession() upload = session.query(Upload).get(id) if upload is None: - raise HTTPResponse("Invalid upload id", 404) + raise ParryHTTPResponse("Invalid upload id", 404) try: @@ -188,7 +188,7 @@ def post_comments(id): upload=upload ) except KeyError as e: - raise HTTPResponse(f"Missing json value: {e.args[0]}", 400) + raise ParryHTTPResponse(f"Missing json value: {e.args[0]}", 400) session.add(comment) session.commit() @@ -201,11 +201,11 @@ def delete_comments(id, comment_id): try: comment = session.query(Comment).filter_by(id=comment_id, author=get_user(session), upload=session.query(Upload).get(id)).one() except db.orm.exc.NoResultFound: - raise HTTPResponse(status=404) + raise ParryHTTPResponse(status=404) session.delete(comment) session.commit() - return HTTPResponse(status=204) + return ParryHTTPResponse(status=204) @get("/api/uploads/<id>/vote") @jwt_auth_required @@ -213,12 +213,12 @@ def get_vote(id): session = DBSession() upload = session.query(Upload).get(id) if upload is None: - raise HTTPResponse("Invalid upload id", 404) + raise ParryHTTPResponse("Invalid upload id", 404) try: return session.query(Vote).filter_by(upload=upload, author=get_user(session)).one().json() except db.orm.exc.NoResultFound: - raise HTTPResponse(status=404) + raise ParryHTTPResponse(status=404) @post("/api/uploads/<id>/vote") @jwt_auth_required @@ -226,7 +226,7 @@ def post_vote(id): session = DBSession() upload = session.query(Upload).get(id) if upload is None: - raise HTTPResponse("Invalid upload id", 404) + raise ParryHTTPResponse("Invalid upload id", 404) author = get_user(session) try: |
