summaryrefslogtreecommitdiff
path: root/service/pixelated
diff options
context:
space:
mode:
Diffstat (limited to 'service/pixelated')
-rw-r--r--service/pixelated/application.py2
-rw-r--r--service/pixelated/bitmask_libraries/provider.py2
-rw-r--r--service/pixelated/resources/__init__.py10
-rw-r--r--service/pixelated/resources/auth.py31
-rw-r--r--service/pixelated/resources/login_resource.py13
-rw-r--r--service/pixelated/resources/root_resource.py95
6 files changed, 81 insertions, 72 deletions
diff --git a/service/pixelated/application.py b/service/pixelated/application.py
index 46e5ba85..fa6568e6 100644
--- a/service/pixelated/application.py
+++ b/service/pixelated/application.py
@@ -159,7 +159,7 @@ def set_up_protected_resources(root_resource, provider, services_factory, banner
_portal = portal.Portal(realm, [session_checker, AllowAnonymousAccess()])
anonymous_resource = LoginResource(services_factory, provider, disclaimer_banner=banner, authenticator=authenticator)
- protected_resource = PixelatedAuthSessionWrapper(_portal, root_resource, anonymous_resource, [])
+ protected_resource = PixelatedAuthSessionWrapper(_portal, root_resource, anonymous_resource)
root_resource.initialize(provider, disclaimer_banner=banner, authenticator=authenticator)
return protected_resource
diff --git a/service/pixelated/bitmask_libraries/provider.py b/service/pixelated/bitmask_libraries/provider.py
index 96935fbc..bc19f79e 100644
--- a/service/pixelated/bitmask_libraries/provider.py
+++ b/service/pixelated/bitmask_libraries/provider.py
@@ -193,7 +193,7 @@ class LeapProvider(object):
fin.close()
def setup_ca_bundle(self):
- path = os.path.join(leap_config.leap_home, 'providers', self.server_name, 'keys', 'client')
+ path = os.path.dirname(self.provider_api_cert)
if not os.path.isdir(path):
os.makedirs(path, 0700)
self._download_cert(self.provider_api_cert)
diff --git a/service/pixelated/resources/__init__.py b/service/pixelated/resources/__init__.py
index 11611f0b..97346a6f 100644
--- a/service/pixelated/resources/__init__.py
+++ b/service/pixelated/resources/__init__.py
@@ -13,8 +13,9 @@
#
# 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
@@ -26,6 +27,8 @@ from twisted.web.http import INTERNAL_SERVER_ERROR, SERVICE_UNAVAILABLE
log = Logger()
+CSRF_TOKEN_LENGTH = 32
+
class SetEncoder(json.JSONEncoder):
def default(self, obj):
@@ -62,6 +65,11 @@ class BaseResource(Resource):
Resource.__init__(self)
self._services_factory = services_factory
+ def _add_csrf_cookie(self, request):
+ csrf_token = hashlib.sha256(os.urandom(CSRF_TOKEN_LENGTH)).hexdigest()
+ 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 adac985f..a2054f18 100644
--- a/service/pixelated/resources/auth.py
+++ b/service/pixelated/resources/auth.py
@@ -64,10 +64,18 @@ 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 in interfaces:
- return IResource, avatarId, lambda: None
- raise NotImplementedError()
+ 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
@implementer(IResource)
@@ -75,7 +83,7 @@ class PixelatedAuthSessionWrapper(object):
isLeaf = False
- def __init__(self, portal, root_resource, anonymous_resource, credentialFactories):
+ def __init__(self, portal, root_resource, anonymous_resource, credentialFactories=[]):
self._portal = portal
self._credentialFactories = credentialFactories
self._root_resource = root_resource
@@ -93,23 +101,18 @@ 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
- if avatar == checkers.ANONYMOUS and not pattern.match(request.path):
- return self._anonymous_resource
- else:
- return self._root_resource
+ # TODO: make sandbox public
+ return avatar
def loginFailed(result):
if result.check(error.Unauthorized, error.LoginFailed):
return UnauthorizedResource(self._credentialFactories)
else:
- log.err(
- result,
- "HTTPAuthSessionWrapper.getChildWithDefault encountered "
- "unexpected error")
+ log.error(
+ "PixelatedAuthSessionWrapper.getChildWithDefault encountered "
+ "unexpected error: %s" % result)
return ErrorPage(500, None, None)
d = self._portal.login(credentials, None, IResource)
diff --git a/service/pixelated/resources/login_resource.py b/service/pixelated/resources/login_resource.py
index aadc435e..fec4307e 100644
--- a/service/pixelated/resources/login_resource.py
+++ b/service/pixelated/resources/login_resource.py
@@ -39,6 +39,17 @@ def _get_startup_folder():
return os.path.join(path, '..', 'assets')
+def _get_public_folder():
+ static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "web-ui", "public"))
+ # 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", "public"))
+ if not os.path.exists(static_folder):
+ static_folder = os.path.join('/', 'usr', 'share', 'pixelated-user-agent')
+ return static_folder
+
+
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
@@ -107,6 +118,7 @@ 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._public_folder = _get_public_folder()
self._startup_folder = _get_startup_folder()
self._disclaimer_banner = disclaimer_banner
self._provider = provider
@@ -114,6 +126,7 @@ class LoginResource(BaseResource):
self._bootstrap_user_services = BootstrapUserServices(services_factory, provider)
self.putChild('startup-assets', File(self._startup_folder))
+ self.putChild('public-assets', File(self._public_folder))
with open(os.path.join(self._startup_folder, 'Interstitial.html')) as f:
self.interstitial = f.read()
diff --git a/service/pixelated/resources/root_resource.py b/service/pixelated/resources/root_resource.py
index 8df76c70..0788ffb1 100644
--- a/service/pixelated/resources/root_resource.py
+++ b/service/pixelated/resources/root_resource.py
@@ -13,12 +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 json
import os
-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,43 +32,48 @@ 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.logger import Logger
-log = Logger()
+logger = Logger()
-CSRF_TOKEN_LENGTH = 32
+class PublicRootResource(BaseResource):
-MODE_STARTUP = 1
-MODE_RUNNING = 2
+ def __init__(self, services_factory):
+ BaseResource.__init__(self, services_factory)
-class RootResource(BaseResource):
+class RootResource(PublicRootResource):
+
def __init__(self, services_factory):
- BaseResource.__init__(self, services_factory)
+ PublicRootResource.__init__(self, services_factory)
+ self._assets_folder = self._get_assets_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
- self._child_resources = ChildResourcesMap()
with open(os.path.join(self._startup_assets_folder, 'Interstitial.html')) as f:
self.interstitial = f.read()
+ self._inbox_resource = InboxResource(services_factory)
self._startup_mode()
def _startup_mode(self):
+ self.putChild('assets', File(self._assets_folder))
self.putChild('startup-assets', File(self._startup_assets_folder))
self._mode = MODE_STARTUP
+ logger.debug('Root in STARTUP mode. %s' % self)
- def getChild(self, path, request):
+ def getChildWithDefault(self, path, request):
if path == '':
- return self
+ return self._inbox_resource
if self._mode == MODE_STARTUP:
return UnavailableResource()
if self._is_xsrf_valid(request):
- return self._child_resources.get(path)
+ return BaseResource.getChildWithDefault(self, path, request)
return UnAuthorizedResource()
def _is_xsrf_valid(self, request):
@@ -78,7 +82,9 @@ class RootResource(BaseResource):
return True
xsrf_token = request.getCookie('XSRF-TOKEN')
+ logger.debug('CSRF token: %s' % xsrf_token)
+ # TODO: how is comparing the cookie-csrf with the HTTP-header-csrf adding any csrf protection?
ajax_request = (request.getHeader('x-requested-with') == 'XMLHttpRequest')
if ajax_request:
xsrf_header = request.getHeader('x-xsrf-token')
@@ -88,24 +94,30 @@ class RootResource(BaseResource):
return csrf_input and csrf_input == xsrf_token
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))
-
+ self.putChild('sandbox', SandboxResource(self._static_folder))
+ self.putChild('keys', KeysResource(self._services_factory))
+ self.putChild(AttachmentsResource.BASE_URL, AttachmentsResource(self._services_factory))
+ self.putChild('contacts', ContactsResource(self._services_factory))
+ self.putChild('features', FeaturesResource(provider))
+ self.putChild('tags', TagsResource(self._services_factory))
+ self.putChild('mails', MailsResource(self._services_factory))
+ self.putChild('mail', MailResource(self._services_factory))
+ self.putChild('feedback', FeedbackResource(self._services_factory))
+ self.putChild('user-settings', UserSettingsResource(self._services_factory))
+ self.putChild('users', UsersResource(self._services_factory))
+ self.putChild(LoginResource.BASE_URL,
+ LoginResource(self._services_factory, provider, disclaimer_banner=disclaimer_banner, authenticator=authenticator))
+ self.putChild(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_assets_folder(self):
+ pixelated_path = os.path.dirname(os.path.abspath(pixelated.__file__))
+ return os.path.join(pixelated_path, '..', '..', 'web-ui', 'public')
+ # TODO: use the public folder for this
def _get_startup_folder(self):
path = os.path.dirname(os.path.abspath(__file__))
return os.path.join(path, '..', 'assets')
@@ -119,30 +131,3 @@ class RootResource(BaseResource):
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()