2017-04-13 22:30:20 +00:00
|
|
|
import click
|
2015-12-12 22:34:08 +00:00
|
|
|
import ipaddress
|
|
|
|
import json
|
2016-03-21 21:42:39 +00:00
|
|
|
import logging
|
2017-04-13 22:30:20 +00:00
|
|
|
import os
|
2015-12-12 22:34:08 +00:00
|
|
|
import types
|
2017-03-26 00:10:09 +00:00
|
|
|
from datetime import date, time, datetime, timedelta
|
2017-12-30 13:57:48 +00:00
|
|
|
from urllib.parse import urlparse
|
2016-03-21 21:42:39 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger("api")
|
|
|
|
|
|
|
|
def csrf_protection(func):
|
|
|
|
"""
|
|
|
|
Protect resource from common CSRF attacks by checking user agent and referrer
|
|
|
|
"""
|
2017-04-13 22:30:20 +00:00
|
|
|
import falcon
|
2016-03-21 21:42:39 +00:00
|
|
|
def wrapped(self, req, resp, *args, **kwargs):
|
|
|
|
# Assume curl and python-requests are used intentionally
|
|
|
|
if req.user_agent.startswith("curl/") or req.user_agent.startswith("python-requests/"):
|
|
|
|
return func(self, req, resp, *args, **kwargs)
|
|
|
|
|
|
|
|
# For everything else assert referrer
|
|
|
|
referrer = req.headers.get("REFERER")
|
2016-09-17 21:00:14 +00:00
|
|
|
|
|
|
|
|
2016-03-21 21:42:39 +00:00
|
|
|
if referrer:
|
|
|
|
scheme, netloc, path, params, query, fragment = urlparse(referrer)
|
2016-09-17 21:00:14 +00:00
|
|
|
if ":" in netloc:
|
|
|
|
host, port = netloc.split(":", 1)
|
|
|
|
else:
|
|
|
|
host, port = netloc, None
|
|
|
|
if host == req.host:
|
2016-03-21 21:42:39 +00:00
|
|
|
return func(self, req, resp, *args, **kwargs)
|
|
|
|
|
|
|
|
# Kaboom!
|
2017-12-30 13:57:48 +00:00
|
|
|
logger.warning("Prevented clickbait from '%s' with user agent '%s'",
|
2016-03-21 21:42:39 +00:00
|
|
|
referrer or "-", req.user_agent)
|
2016-09-17 21:00:14 +00:00
|
|
|
raise falcon.HTTPForbidden("Forbidden",
|
2016-03-21 21:42:39 +00:00
|
|
|
"No suitable UA or referrer provided, cross-site scripting disabled")
|
|
|
|
return wrapped
|
|
|
|
|
2015-12-12 22:34:08 +00:00
|
|
|
|
|
|
|
class MyEncoder(json.JSONEncoder):
|
|
|
|
def default(self, obj):
|
2018-05-02 08:11:01 +00:00
|
|
|
from certidude.user import User
|
2015-12-12 22:34:08 +00:00
|
|
|
if isinstance(obj, ipaddress._IPAddressBase):
|
|
|
|
return str(obj)
|
|
|
|
if isinstance(obj, set):
|
|
|
|
return tuple(obj)
|
|
|
|
if isinstance(obj, datetime):
|
|
|
|
return obj.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
|
|
|
|
if isinstance(obj, date):
|
|
|
|
return obj.strftime("%Y-%m-%d")
|
2017-03-26 00:10:09 +00:00
|
|
|
if isinstance(obj, timedelta):
|
|
|
|
return obj.total_seconds()
|
2015-12-12 22:34:08 +00:00
|
|
|
if isinstance(obj, types.GeneratorType):
|
|
|
|
return tuple(obj)
|
2016-03-27 20:38:14 +00:00
|
|
|
if isinstance(obj, User):
|
|
|
|
return dict(name=obj.name, given_name=obj.given_name,
|
|
|
|
surname=obj.surname, mail=obj.mail)
|
2015-12-12 22:34:08 +00:00
|
|
|
return json.JSONEncoder.default(self, obj)
|
|
|
|
|
|
|
|
|
|
|
|
def serialize(func):
|
|
|
|
"""
|
|
|
|
Falcon response serialization
|
|
|
|
"""
|
2017-04-13 22:30:20 +00:00
|
|
|
import falcon
|
2015-12-12 22:34:08 +00:00
|
|
|
def wrapped(instance, req, resp, **kwargs):
|
2018-01-02 14:49:06 +00:00
|
|
|
retval = func(instance, req, resp, **kwargs)
|
|
|
|
if not resp.body and not resp.location:
|
|
|
|
if not req.client_accepts("application/json"):
|
|
|
|
logger.debug("Client did not accept application/json")
|
|
|
|
raise falcon.HTTPUnsupportedMediaType(
|
|
|
|
"Client did not accept application/json")
|
|
|
|
resp.set_header("Cache-Control", "no-cache, no-store, must-revalidate")
|
|
|
|
resp.set_header("Pragma", "no-cache")
|
|
|
|
resp.set_header("Expires", "0")
|
|
|
|
resp.body = json.dumps(retval, cls=MyEncoder)
|
2015-12-12 22:34:08 +00:00
|
|
|
return wrapped
|
|
|
|
|