summaryrefslogtreecommitdiff
path: root/service/pixelated/resources
diff options
context:
space:
mode:
authorRoald de Vries <rdevries@thoughtworks.com>2016-12-08 16:59:09 +0100
committerRoald de Vries <rdevries@thoughtworks.com>2016-12-08 16:59:09 +0100
commitfafac3b4128a0993b0de1c6e8ca3062bf1ccc14e (patch)
tree3b9a446e4c82bb8ba94c1cd0adec57c0042dae28 /service/pixelated/resources
parent521bce7eff5cf921156efe74c91a0499ade43619 (diff)
Revert "[#801] Merge branch 'signup'"
This reverts commit d10f607a4d40587510b0dc31b31fe4750bf4a3a3, reversing changes made to c28abba2f5b1186c671ebef508d40ffaae6d5bc5.
Diffstat (limited to 'service/pixelated/resources')
-rw-r--r--service/pixelated/resources/__init__.py10
-rw-r--r--service/pixelated/resources/auth.py32
-rw-r--r--service/pixelated/resources/inbox_resource.py56
-rw-r--r--service/pixelated/resources/login_resource.py32
-rw-r--r--service/pixelated/resources/root_resource.py120
-rw-r--r--service/pixelated/resources/session.py10
6 files changed, 114 insertions, 146 deletions
diff --git a/service/pixelated/resources/__init__.py b/service/pixelated/resources/__init__.py
index 023758de..11611f0b 100644
--- a/service/pixelated/resources/__init__.py
+++ b/service/pixelated/resources/__init__.py
@@ -13,9 +13,8 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-import hashlib
+
import json
-import os
from twisted.web.http import UNAUTHORIZED
from twisted.web.resource import Resource
@@ -27,8 +26,6 @@ from twisted.web.http import INTERNAL_SERVER_ERROR, SERVICE_UNAVAILABLE
log = Logger()
-CSRF_TOKEN_LENGTH = 32
-
class SetEncoder(json.JSONEncoder):
def default(self, obj):
@@ -65,11 +62,6 @@ class BaseResource(Resource):
Resource.__init__(self)
self._services_factory = services_factory
- def _add_csrf_cookie(self, request):
- csrf_token = IPixelatedSession(request.getSession()).get_csrf_token()
- request.addCookie('XSRF-TOKEN', csrf_token)
- log.debug('XSRF-TOKEN added: %s' % csrf_token)
-
def _get_user_id_from_request(self, request):
if self._services_factory.mode.is_single_user:
return None # it doesn't matter
diff --git a/service/pixelated/resources/auth.py b/service/pixelated/resources/auth.py
index 057eb053..adac985f 100644
--- a/service/pixelated/resources/auth.py
+++ b/service/pixelated/resources/auth.py
@@ -64,18 +64,10 @@ class SessionChecker(object):
class PixelatedRealm(object):
implements(portal.IRealm)
- def __init__(self, authenticated_resource, public_resource):
- self._authenticated_resource = authenticated_resource
- self._public_resource = public_resource
-
def requestAvatar(self, avatarId, mind, *interfaces):
- if IResource not in interfaces:
- raise NotImplementedError()
- if avatarId == checkers.ANONYMOUS:
- avatar = self._public_resource
- else:
- avatar = self._authenticated_resource
- return IResource, avatar, lambda: None
+ if IResource in interfaces:
+ return IResource, avatarId, lambda: None
+ raise NotImplementedError()
@implementer(IResource)
@@ -83,9 +75,11 @@ class PixelatedAuthSessionWrapper(object):
isLeaf = False
- def __init__(self, portal, credentialFactories=[]):
+ def __init__(self, portal, root_resource, anonymous_resource, credentialFactories):
self._portal = portal
self._credentialFactories = credentialFactories
+ self._root_resource = root_resource
+ self._anonymous_resource = anonymous_resource
def render(self, request):
raise UnsupportedMethod(())
@@ -99,17 +93,23 @@ class PixelatedAuthSessionWrapper(object):
return util.DeferredResource(self._login(creds, request))
def _login(self, credentials, request):
+ pattern = re.compile("^/sandbox/")
+
def loginSucceeded(args):
interface, avatar, logout = args
- return avatar
+ if avatar == checkers.ANONYMOUS and not pattern.match(request.path):
+ return self._anonymous_resource
+ else:
+ return self._root_resource
def loginFailed(result):
if result.check(error.Unauthorized, error.LoginFailed):
return UnauthorizedResource(self._credentialFactories)
else:
- log.error(
- "PixelatedAuthSessionWrapper.getChildWithDefault encountered "
- "unexpected error: %s" % result)
+ log.err(
+ result,
+ "HTTPAuthSessionWrapper.getChildWithDefault encountered "
+ "unexpected error")
return ErrorPage(500, None, None)
d = self._portal.login(credentials, None, IResource)
diff --git a/service/pixelated/resources/inbox_resource.py b/service/pixelated/resources/inbox_resource.py
deleted file mode 100644
index d0096efe..00000000
--- a/service/pixelated/resources/inbox_resource.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# Copyright (c) 2016 ThoughtWorks, Inc.
-#
-# Pixelated is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pixelated is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-import hashlib
-import os
-import pkg_resources
-from string import Template
-
-import pixelated
-from pixelated.resources import BaseResource
-
-from twisted.logger import Logger
-
-logger = Logger()
-
-
-MODE_STARTUP = 1
-MODE_RUNNING = 2
-
-
-class InboxResource(BaseResource):
- isLeaf = True
-
- def __init__(self, services_factory):
- BaseResource.__init__(self, services_factory)
- with open(pkg_resources.resource_filename('templates', 'index.html')) as f:
- self._html_template = f.read()
- with open(pkg_resources.resource_filename('templates', 'Interstitial.html')) as f:
- self.interstitial = f.read()
- self._mode = MODE_STARTUP
-
- def initialize(self):
- self._mode = MODE_RUNNING
-
- def _is_starting(self):
- return self._mode == MODE_STARTUP
-
- def render_GET(self, request):
- if self._is_starting():
- return self.interstitial
- else:
- account_email = self.mail_service(request).account_email
- response = Template(self._html_template).safe_substitute(account_email=account_email)
- return str(response)
diff --git a/service/pixelated/resources/login_resource.py b/service/pixelated/resources/login_resource.py
index 9bb771df..ed0cb54e 100644
--- a/service/pixelated/resources/login_resource.py
+++ b/service/pixelated/resources/login_resource.py
@@ -15,7 +15,6 @@
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
import os
-import pkg_resources
from xml.sax import SAXParseException
from pixelated.authentication import Authenticator
@@ -35,6 +34,22 @@ from twisted.web.template import Element, XMLFile, renderElement, renderer
log = Logger()
+def _get_startup_folder():
+ path = os.path.dirname(os.path.abspath(__file__))
+ return os.path.join(path, '..', 'assets')
+
+
+def _get_static_folder():
+ static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "web-ui", "app"))
+ # this is a workaround for packaging
+ if not os.path.exists(static_folder):
+ static_folder = os.path.abspath(
+ os.path.join(os.path.abspath(__file__), "..", "..", "..", "..", "web-ui", "app"))
+ if not os.path.exists(static_folder):
+ static_folder = os.path.join('/', 'usr', 'share', 'pixelated-user-agent')
+ return static_folder
+
+
def parse_accept_language(all_headers):
accepted_languages = ['pt-BR', 'en-US']
languages = all_headers.get('accept-language', '').split(';')[0]
@@ -45,7 +60,7 @@ def parse_accept_language(all_headers):
class DisclaimerElement(Element):
- loader = XMLFile(FilePath(pkg_resources.resource_filename('templates', '_login_disclaimer_banner.html')))
+ loader = XMLFile(FilePath(os.path.join(_get_startup_folder(), '_login_disclaimer_banner.html')))
def __init__(self, banner):
super(DisclaimerElement, self).__init__()
@@ -68,7 +83,7 @@ class DisclaimerElement(Element):
class LoginWebSite(Element):
- loader = XMLFile(FilePath(pkg_resources.resource_filename('templates', 'login.html')))
+ loader = XMLFile(FilePath(os.path.join(_get_startup_folder(), 'login.html')))
def __init__(self, error_msg=None, disclaimer_banner_file=None):
super(LoginWebSite, self).__init__()
@@ -82,11 +97,6 @@ class LoginWebSite(Element):
return tag('')
@renderer
- def csrftoken(self, request, tag):
- tag.fillSlots(csrftoken=IPixelatedSession(request.getSession()).get_csrf_token())
- return tag
-
- @renderer
def disclaimer(self, request, tag):
return DisclaimerElement(self.disclaimer_banner_file).render(request)
@@ -96,12 +106,15 @@ class LoginResource(BaseResource):
def __init__(self, services_factory, provider=None, disclaimer_banner=None, authenticator=None):
BaseResource.__init__(self, services_factory)
+ self._static_folder = _get_static_folder()
+ self._startup_folder = _get_startup_folder()
self._disclaimer_banner = disclaimer_banner
self._provider = provider
self._authenticator = authenticator or Authenticator(provider)
self._bootstrap_user_services = BootstrapUserServices(services_factory, provider)
- with open(pkg_resources.resource_filename('templates', 'Interstitial.html')) as f:
+ self.putChild('startup-assets', File(self._startup_folder))
+ with open(os.path.join(self._startup_folder, 'Interstitial.html')) as f:
self.interstitial = f.read()
def getChild(self, path, request):
@@ -114,7 +127,6 @@ class LoginResource(BaseResource):
return NoResource()
def render_GET(self, request):
- request.getSession()
request.setResponseCode(OK)
return self._render_template(request)
diff --git a/service/pixelated/resources/root_resource.py b/service/pixelated/resources/root_resource.py
index 5cc93dbe..8df76c70 100644
--- a/service/pixelated/resources/root_resource.py
+++ b/service/pixelated/resources/root_resource.py
@@ -13,12 +13,12 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+import hashlib
import json
import os
-import pkg_resources
+from string import Template
from pixelated.resources.users import UsersResource
-import pixelated
from pixelated.resources import BaseResource, UnAuthorizedResource, UnavailableResource
from pixelated.resources import IPixelatedSession
from pixelated.resources.attachments_resource import AttachmentsResource
@@ -33,42 +33,43 @@ from pixelated.resources.mail_resource import MailResource
from pixelated.resources.mails_resource import MailsResource
from pixelated.resources.tags_resource import TagsResource
from pixelated.resources.keys_resource import KeysResource
-from pixelated.resources.inbox_resource import InboxResource, MODE_STARTUP, MODE_RUNNING
from twisted.web.resource import NoResource
from twisted.web.static import File
-from twisted.web.util import Redirect
from twisted.logger import Logger
-logger = Logger()
+log = Logger()
-class RootResource(BaseResource):
+CSRF_TOKEN_LENGTH = 32
+
+MODE_STARTUP = 1
+MODE_RUNNING = 2
+
- def __init__(self, services_factory, static_folder, public=False):
+class RootResource(BaseResource):
+ def __init__(self, services_factory):
BaseResource.__init__(self, services_factory)
- self._public = public
- self._static_folder = static_folder
+ self._startup_assets_folder = self._get_startup_folder()
+ self._static_folder = self._get_static_folder()
+ self._html_template = open(os.path.join(self._static_folder, 'index.html')).read()
self._services_factory = services_factory
- with open(pkg_resources.resource_filename('templates', 'Interstitial.html')) as f:
+ self._child_resources = ChildResourcesMap()
+ with open(os.path.join(self._startup_assets_folder, 'Interstitial.html')) as f:
self.interstitial = f.read()
- self._redirect_to_login_resource = Redirect('login')
- self._inbox_resource = InboxResource(services_factory)
self._startup_mode()
def _startup_mode(self):
- self.putChildPublic('static', File(self._static_folder))
+ self.putChild('startup-assets', File(self._startup_assets_folder))
self._mode = MODE_STARTUP
- logger.debug('Root in STARTUP mode. %s' % self)
- def getChildWithDefault(self, path, request):
- self._add_csrf_cookie(request)
+ def getChild(self, path, request):
if path == '':
- return self._redirect_to_login_resource if self._public else self._inbox_resource
+ return self
if self._mode == MODE_STARTUP:
return UnavailableResource()
if self._is_xsrf_valid(request):
- return BaseResource.getChildWithDefault(self, path, request)
+ return self._child_resources.get(path)
return UnAuthorizedResource()
def _is_xsrf_valid(self, request):
@@ -77,7 +78,6 @@ class RootResource(BaseResource):
return True
xsrf_token = request.getCookie('XSRF-TOKEN')
- logger.debug('CSRF token: %s' % xsrf_token)
ajax_request = (request.getHeader('x-requested-with') == 'XMLHttpRequest')
if ajax_request:
@@ -87,32 +87,62 @@ class RootResource(BaseResource):
csrf_input = request.args.get('csrftoken', [None])[0] or json.loads(request.content.read()).get('csrftoken', [None])[0]
return csrf_input and csrf_input == xsrf_token
- def putChildPublic(self, path, resource):
- return BaseResource.putChild(self, path, resource)
+ def initialize(self, provider=None, disclaimer_banner=None, authenticator=None):
+ self._child_resources.add('sandbox', SandboxResource(self._static_folder))
+ self._child_resources.add('assets', File(self._static_folder))
+ self._child_resources.add('keys', KeysResource(self._services_factory))
+ self._child_resources.add(AttachmentsResource.BASE_URL, AttachmentsResource(self._services_factory))
+ self._child_resources.add('contacts', ContactsResource(self._services_factory))
+ self._child_resources.add('features', FeaturesResource(provider))
+ self._child_resources.add('tags', TagsResource(self._services_factory))
+ self._child_resources.add('mails', MailsResource(self._services_factory))
+ self._child_resources.add('mail', MailResource(self._services_factory))
+ self._child_resources.add('feedback', FeedbackResource(self._services_factory))
+ self._child_resources.add('user-settings', UserSettingsResource(self._services_factory))
+ self._child_resources.add('users', UsersResource(self._services_factory))
+ self._child_resources.add(LoginResource.BASE_URL,
+ LoginResource(self._services_factory, provider, disclaimer_banner=disclaimer_banner, authenticator=authenticator))
+ self._child_resources.add(LogoutResource.BASE_URL, LogoutResource(self._services_factory))
- def putChildProtected(self, path, resource):
- return BaseResource.putChild(self, path, UnAuthorizedResource() if self._public else resource)
+ self._mode = MODE_RUNNING
- def putChild(self, path, resource):
- logger.warn('Use either `putChildPublic` or `putChildProtected` on this resource')
- return self.putChildProtected(path, resource) # to be on the safe side
+ def _get_startup_folder(self):
+ path = os.path.dirname(os.path.abspath(__file__))
+ return os.path.join(path, '..', 'assets')
- def initialize(self, provider=None, disclaimer_banner=None, authenticator=None):
- self.putChildPublic('sandbox', SandboxResource(self._static_folder))
- self.putChildProtected('keys', KeysResource(self._services_factory))
- self.putChildProtected(AttachmentsResource.BASE_URL, AttachmentsResource(self._services_factory))
- self.putChildProtected('contacts', ContactsResource(self._services_factory))
- self.putChildProtected('features', FeaturesResource(provider))
- self.putChildProtected('tags', TagsResource(self._services_factory))
- self.putChildProtected('mails', MailsResource(self._services_factory))
- self.putChildProtected('mail', MailResource(self._services_factory))
- self.putChildProtected('feedback', FeedbackResource(self._services_factory))
- self.putChildProtected('user-settings', UserSettingsResource(self._services_factory))
- self.putChildProtected('users', UsersResource(self._services_factory))
- self.putChildPublic(LoginResource.BASE_URL,
- LoginResource(self._services_factory, provider, disclaimer_banner=disclaimer_banner, authenticator=authenticator))
- self.putChildPublic(LogoutResource.BASE_URL, LogoutResource(self._services_factory))
-
- self._inbox_resource.initialize()
- self._mode = MODE_RUNNING
- logger.debug('Root in RUNNING mode. %s' % self)
+ def _get_static_folder(self):
+ static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "web-ui", "app"))
+ # this is a workaround for packaging
+ if not os.path.exists(static_folder):
+ static_folder = os.path.abspath(
+ os.path.join(os.path.abspath(__file__), "..", "..", "..", "..", "web-ui", "app"))
+ if not os.path.exists(static_folder):
+ static_folder = os.path.join('/', 'usr', 'share', 'pixelated-user-agent')
+ return static_folder
+
+ def _is_starting(self):
+ return self._mode == MODE_STARTUP
+
+ def _add_csrf_cookie(self, request):
+ csrf_token = hashlib.sha256(os.urandom(CSRF_TOKEN_LENGTH)).hexdigest()
+ request.addCookie('XSRF-TOKEN', csrf_token)
+
+ def render_GET(self, request):
+ self._add_csrf_cookie(request)
+ if self._is_starting():
+ return self.interstitial
+ else:
+ account_email = self.mail_service(request).account_email
+ response = Template(self._html_template).safe_substitute(account_email=account_email)
+ return str(response)
+
+
+class ChildResourcesMap(object):
+ def __init__(self):
+ self._registry = {}
+
+ def add(self, path, resource):
+ self._registry[path] = resource
+
+ def get(self, path):
+ return self._registry.get(path) or NoResource()
diff --git a/service/pixelated/resources/session.py b/service/pixelated/resources/session.py
index 0e46ad8f..9ade8d29 100644
--- a/service/pixelated/resources/session.py
+++ b/service/pixelated/resources/session.py
@@ -13,15 +13,11 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-import hashlib
-import os
from zope.interface import Interface, Attribute, implements
from twisted.python.components import registerAdapter
from twisted.web.server import Session
-CSRF_TOKEN_LENGTH = 32
-
class IPixelatedSession(Interface):
user_uuid = Attribute('The uuid of the currently logged in user')
@@ -32,7 +28,6 @@ class PixelatedSession(object):
def __init__(self, session):
self.user_uuid = None
- self._csrf_token = None
def is_logged_in(self):
return self.user_uuid is not None
@@ -40,10 +35,5 @@ class PixelatedSession(object):
def expire(self):
self.user_uuid = None
- def get_csrf_token(self):
- if self._csrf_token is None:
- self._csrf_token = hashlib.sha256(os.urandom(CSRF_TOKEN_LENGTH)).hexdigest()
- return self._csrf_token
-
registerAdapter(PixelatedSession, Session, IPixelatedSession)