f6fd667c3bc5a0726310fa696743d03d92816a18
[cascardo/ipsilon.git] / ipsilon / util / endpoint.py
1 # Copyright (C) 2015  Ipsilon Contributors see COPYING for license
2
3 import cherrypy
4 from ipsilon.util.log import Log
5 from ipsilon.util.user import UserSession
6 from urllib import unquote
7 try:
8     from urlparse import urlparse
9 except ImportError:
10     # pylint: disable=no-name-in-module, import-error
11     from urllib.parse import urlparse
12
13
14 class Endpoint(Log):
15     def __init__(self, site):
16         self._site = site
17         self.basepath = cherrypy.config.get('base.mount', "")
18         self.user = None
19         self.default_headers = dict()
20         self.auth_protect = False
21
22     def get_url(self):
23         return cherrypy.url(relative=False)
24
25     def instance_base_url(self):
26         url = self.get_url()
27         s = urlparse(unquote(url))
28         return '%s://%s%s' % (s.scheme, s.netloc, self.basepath)
29
30     def _check_referer(self, referer, url):
31         r = urlparse(unquote(referer))
32         u = urlparse(unquote(url))
33         if r.scheme != u.scheme:
34             return False
35         if r.netloc != u.netloc:
36             return False
37         if r.path.startswith(self.basepath):
38             return True
39         return False
40
41     def __call__(self, *args, **kwargs):
42         # pylint: disable=star-args
43         cherrypy.response.headers.update(self.default_headers)
44
45         self.user = UserSession().get_user()
46
47         if self.auth_protect and self.user.is_anonymous:
48             raise cherrypy.HTTPError(401)
49
50         self._debug("method: %s" % cherrypy.request.method)
51         op = getattr(self, cherrypy.request.method, None)
52         if callable(op):
53             # Basic CSRF protection
54             if cherrypy.request.method != 'GET':
55                 url = self.get_url()
56                 if 'referer' not in cherrypy.request.headers:
57                     self._debug("Missing referer in %s request to %s"
58                                 % (cherrypy.request.method, url))
59                     raise cherrypy.HTTPError(403)
60                 referer = cherrypy.request.headers['referer']
61                 if not self._check_referer(referer, url):
62                     self._debug("Wrong referer %s in request to %s"
63                                 % (referer, url))
64                     raise cherrypy.HTTPError(403)
65             return op(*args, **kwargs)
66         else:
67             op = getattr(self, 'root', None)
68             if callable(op):
69                 return op(*args, **kwargs)
70
71         return self.default(*args, **kwargs)
72
73     def default(self, *args, **kwargs):
74         raise cherrypy.NotFound()
75
76     def add_subtree(self, name, page):
77         self.__dict__[name] = page
78
79     def del_subtree(self, name):
80         del self.__dict__[name]
81
82     exposed = True