aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFulgen301 <tokmajigeorge@gmail.com>2018-10-16 18:57:01 +0200
committerFulgen301 <tokmajigeorge@gmail.com>2018-10-16 18:57:01 +0200
commit8213c244eaca9a65a51ccb8422b3adb45485ef43 (patch)
treed8f22d6e91aa869e8ab51b5d5bf6de5de2824881
parent28afed69d3f5a04c86aa87ad18e15ec55bdc7a82 (diff)
downloadparry-8213c244eaca9a65a51ccb8422b3adb45485ef43.tar.gz
parry-8213c244eaca9a65a51ccb8422b3adb45485ef43.zip
Subclass HTTPReponse in order to ensure the presence of CORS headers
-rw-r--r--auth.py7
-rw-r--r--cors.py31
-rw-r--r--helpers.py13
-rw-r--r--routes/auth.py6
-rw-r--r--routes/media.py12
-rw-r--r--routes/uploads.py30
6 files changed, 59 insertions, 40 deletions
diff --git a/auth.py b/auth.py
index 1f45844..a6636a3 100644
--- a/auth.py
+++ b/auth.py
@@ -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)
diff --git a/cors.py b/cors.py
new file mode 100644
index 0000000..2826920
--- /dev/null
+++ b/cors.py
@@ -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"
diff --git a/helpers.py b/helpers.py
index f917bd3..4a8df6d 100644
--- a/helpers.py
+++ b/helpers.py
@@ -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: