diff options
Diffstat (limited to 'service/pixelated')
-rw-r--r-- | service/pixelated/adapter/mailstore/leap_mailstore.py | 1 | ||||
-rw-r--r-- | service/pixelated/adapter/mailstore/maintenance/__init__.py | 49 | ||||
-rw-r--r-- | service/pixelated/adapter/search/__init__.py | 3 | ||||
-rw-r--r-- | service/pixelated/resources/keys_resource.py | 2 | ||||
-rw-r--r-- | service/pixelated/resources/logout_resource.py | 19 | ||||
-rw-r--r-- | service/pixelated/resources/root_resource.py | 2 | ||||
-rw-r--r-- | service/pixelated/resources/sandbox_resource.py | 34 |
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) |