summaryrefslogtreecommitdiff
path: root/service/pixelated
diff options
context:
space:
mode:
Diffstat (limited to 'service/pixelated')
-rw-r--r--service/pixelated/adapter/mailstore/leap_mailstore.py1
-rw-r--r--service/pixelated/adapter/mailstore/maintenance/__init__.py49
-rw-r--r--service/pixelated/adapter/search/__init__.py3
-rw-r--r--service/pixelated/resources/keys_resource.py2
-rw-r--r--service/pixelated/resources/logout_resource.py19
-rw-r--r--service/pixelated/resources/root_resource.py2
-rw-r--r--service/pixelated/resources/sandbox_resource.py34
7 files changed, 81 insertions, 29 deletions
diff --git a/service/pixelated/adapter/mailstore/leap_mailstore.py b/service/pixelated/adapter/mailstore/leap_mailstore.py
index 975bcc5c..cd4cb5b8 100644
--- a/service/pixelated/adapter/mailstore/leap_mailstore.py
+++ b/service/pixelated/adapter/mailstore/leap_mailstore.py
@@ -27,6 +27,7 @@ from pixelated.adapter.mailstore.mailstore import MailStore, underscore_uuid
from pixelated.adapter.model.mail import Mail, InputMail
from pixelated.support import log_time_deferred
from pixelated.support.functional import to_unicode
+from pixelated.support import date
MIME_PGP_KEY = 'application/pgp-keys'
diff --git a/service/pixelated/adapter/mailstore/maintenance/__init__.py b/service/pixelated/adapter/mailstore/maintenance/__init__.py
index edc442c2..9b6d6023 100644
--- a/service/pixelated/adapter/mailstore/maintenance/__init__.py
+++ b/service/pixelated/adapter/mailstore/maintenance/__init__.py
@@ -13,7 +13,7 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-from leap.keymanager.keys import KEY_TYPE_KEY, KEY_PRIVATE_KEY, KEY_ID_KEY, KEY_ADDRESS_KEY
+from leap.keymanager.keys import KEY_TYPE_KEY, KEY_PRIVATE_KEY, KEY_FINGERPRINT_KEY, KEY_ADDRESS_KEY
from leap.keymanager.openpgp import OpenPGPKey
from twisted.internet import defer
@@ -44,8 +44,8 @@ def _is_public_key(doc):
return _is_key_doc(doc) and not doc.content.get(KEY_PRIVATE_KEY, False)
-def _key_id(doc):
- return doc.content.get(KEY_ID_KEY, None)
+def _key_fingerprint(doc):
+ return doc.content.get(KEY_FINGERPRINT_KEY, None)
def _address(doc):
@@ -60,40 +60,41 @@ class SoledadMaintenance(object):
def repair(self):
_, docs = yield self._soledad.get_all_docs()
- private_key_ids = self._key_ids_with_private_key(docs)
+ private_key_fingerprints = self._key_fingerprints_with_private_key(docs)
for doc in docs:
- if _is_key_doc(doc) and _key_id(doc) not in private_key_ids:
- logger.warn('Deleting doc %s for key %s of <%s>' % (doc.doc_id, _key_id(doc), _address(doc)))
+ if _is_key_doc(doc) and _key_fingerprint(doc) not in private_key_fingerprints:
+ logger.warn('Deleting doc %s for key %s of <%s>' % (doc.doc_id, _key_fingerprint(doc), _address(doc)))
yield self._soledad.delete_doc(doc)
- yield self._repair_missing_active_docs(docs, private_key_ids)
+ yield self._repair_missing_active_docs(docs, private_key_fingerprints)
@defer.inlineCallbacks
- def _repair_missing_active_docs(self, docs, private_key_ids):
- missing = self._missing_active_docs(docs, private_key_ids)
- for key_id in missing:
- emails = self._emails_for_key_id(docs, key_id)
+ def _repair_missing_active_docs(self, docs, private_key_fingerprints):
+ missing = self._missing_active_docs(docs, private_key_fingerprints)
+ for fingerprint in missing:
+ emails = self._emails_for_key_fingerprint(docs, fingerprint)
for email in emails:
- logger.warn('Re-creating active doc for key %s, email %s' % (key_id, email))
- yield self._soledad.create_doc_from_json(OpenPGPKey(email, key_id=key_id, private=False).get_active_json(email))
+ logger.warn('Re-creating active doc for key %s, email %s' % (fingerprint, email))
+ yield self._soledad.create_doc_from_json(OpenPGPKey(email, fingerprint=fingerprint, private=False).get_active_json())
- def _key_ids_with_private_key(self, docs):
- return [doc.content[KEY_ID_KEY] for doc in docs if _is_private_key_doc(doc)]
+ def _key_fingerprints_with_private_key(self, docs):
+ return [doc.content[KEY_FINGERPRINT_KEY] for doc in docs if _is_private_key_doc(doc)]
- def _missing_active_docs(self, docs, private_key_ids):
- active_doc_ids = self._active_docs_for_key_id(docs)
+ def _missing_active_docs(self, docs, private_key_fingerprints):
+ active_doc_ids = self._active_docs_for_key_fingerprint(docs)
- return set([private_key_id for private_key_id in private_key_ids if private_key_id not in active_doc_ids])
+ return set([private_key_fingerprint for private_key_fingerprint in private_key_fingerprints if private_key_fingerprint not in active_doc_ids])
- def _emails_for_key_id(self, docs, key_id):
+ def _emails_for_key_fingerprint(self, docs, fingerprint):
for doc in docs:
- if _is_private_key_doc(doc) and _key_id(doc) == key_id:
+ if _is_private_key_doc(doc) and _key_fingerprint(doc) == fingerprint:
email = _address(doc)
+ if email is None:
+ return []
if isinstance(email, list):
return email
- else:
- return [email]
+ return [email]
- def _active_docs_for_key_id(self, docs):
- return [doc.content[KEY_ID_KEY] for doc in docs if _is_active_key_doc(doc) and _is_public_key(doc)]
+ def _active_docs_for_key_fingerprint(self, docs):
+ return [doc.content[KEY_FINGERPRINT_KEY] for doc in docs if _is_active_key_doc(doc) and _is_public_key(doc)]
diff --git a/service/pixelated/adapter/search/__init__.py b/service/pixelated/adapter/search/__init__.py
index e137b392..3ec6532b 100644
--- a/service/pixelated/adapter/search/__init__.py
+++ b/service/pixelated/adapter/search/__init__.py
@@ -30,6 +30,7 @@ from whoosh.writing import AsyncWriter
from whoosh import sorting
from pixelated.support.functional import unique, to_unicode
import traceback
+from pixelated.support import date
class SearchEngine(object):
@@ -128,7 +129,7 @@ class SearchEngine(object):
index_data = {
'sender': self._empty_string_to_none(header.get('from', '')),
'subject': self._empty_string_to_none(header.get('subject', '')),
- 'date': self._format_utc_integer(header.get('date', '')),
+ 'date': self._format_utc_integer(header.get('date', date.mail_date_now())),
'to': self._format_recipient(header, 'to'),
'cc': self._format_recipient(header, 'cc'),
'bcc': self._format_recipient(header, 'bcc'),
diff --git a/service/pixelated/resources/keys_resource.py b/service/pixelated/resources/keys_resource.py
index d6f469fe..9075ab9e 100644
--- a/service/pixelated/resources/keys_resource.py
+++ b/service/pixelated/resources/keys_resource.py
@@ -17,7 +17,7 @@ class KeysResource(BaseResource):
if key.private:
respond_json_deferred(None, request, status_code=401)
else:
- respond_json_deferred(key.get_json(), request)
+ respond_json_deferred(key.get_active_json(), request)
def key_not_found(_):
respond_json_deferred(None, request, status_code=404)
diff --git a/service/pixelated/resources/logout_resource.py b/service/pixelated/resources/logout_resource.py
index 344ad2e9..01092b05 100644
--- a/service/pixelated/resources/logout_resource.py
+++ b/service/pixelated/resources/logout_resource.py
@@ -1,5 +1,8 @@
+from twisted.web.server import NOT_DONE_YET
+
from pixelated.resources import BaseResource
from twisted.web import util
+from twisted.internet import defer
from pixelated.resources.login_resource import LoginResource
@@ -8,9 +11,19 @@ class LogoutResource(BaseResource):
BASE_URL = "logout"
isLeaf = True
- def render_POST(self, request):
+ @defer.inlineCallbacks
+ def _execute_logout(self, request):
session = self.get_session(request)
- self._services_factory.log_out_user(session.user_uuid)
+ yield self._services_factory.log_out_user(session.user_uuid)
session.expire()
- return util.redirectTo("/%s" % LoginResource.BASE_URL, request)
+ def render_POST(self, request):
+ def _redirect_to_login(_):
+ content = util.redirectTo("/%s" % LoginResource.BASE_URL, request)
+ request.write(content)
+ request.finish()
+
+ d = self._execute_logout(request)
+ d.addCallback(_redirect_to_login)
+
+ return NOT_DONE_YET
diff --git a/service/pixelated/resources/root_resource.py b/service/pixelated/resources/root_resource.py
index 86435d89..109dc08e 100644
--- a/service/pixelated/resources/root_resource.py
+++ b/service/pixelated/resources/root_resource.py
@@ -20,6 +20,7 @@ from string import Template
from pixelated.resources import BaseResource, UnAuthorizedResource
from pixelated.resources.attachments_resource import AttachmentsResource
+from pixelated.resources.sandbox_resource import SandboxResource
from pixelated.resources.contacts_resource import ContactsResource
from pixelated.resources.features_resource import FeaturesResource
from pixelated.resources.feedback_resource import FeedbackResource
@@ -75,6 +76,7 @@ class RootResource(BaseResource):
return csrf_input and csrf_input == xsrf_token
def initialize(self, portal=None, disclaimer_banner=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))
diff --git a/service/pixelated/resources/sandbox_resource.py b/service/pixelated/resources/sandbox_resource.py
new file mode 100644
index 00000000..28e8c9be
--- /dev/null
+++ b/service/pixelated/resources/sandbox_resource.py
@@ -0,0 +1,34 @@
+#
+# 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/>.
+
+from twisted.web.static import File
+
+
+class SandboxResource(File):
+ CSP_HEADER_VALUES = "sandbox allow-popups allow-scripts;" \
+ "default-src 'self';" \
+ "style-src *;" \
+ "script-src *;" \
+ "font-src *;" \
+ "img-src *;" \
+ "object-src 'none';" \
+ "connect-src 'none';"
+
+ def render_GET(self, request):
+ request.setHeader('Content-Security-Policy', self.CSP_HEADER_VALUES)
+ request.setHeader('X-Content-Security-Policy', self.CSP_HEADER_VALUES)
+ request.setHeader('X-Webkit-CSP', self.CSP_HEADER_VALUES)
+ return super(SandboxResource, self).render_GET(request)