diff options
author | Kali Kaneko <kali@leap.se> | 2017-07-25 11:40:11 -0400 |
---|---|---|
committer | Kali Kaneko <kali@leap.se> | 2017-07-25 11:40:29 -0400 |
commit | 91e4481c450eb7eb928debc1cb7fa59bdb63dd7b (patch) | |
tree | 8fd7e6e77b6df669c33d96b7edad6db3cbe14dfe /service/pixelated/config | |
parent | e4f755309d4cf5cfb6b0bcc62ed73d6070956ab5 (diff) |
[pkg] packaging and path changes
- move all the pixelated python package under src/
- move the pixelated_www package under the leap namespace
- allow to set globally the static folder
- add hours and minutes to the timestamp in package version, to allow
for several releases a day.
Diffstat (limited to 'service/pixelated/config')
-rw-r--r-- | service/pixelated/config/__init__.py | 0 | ||||
-rw-r--r-- | service/pixelated/config/arguments.py | 78 | ||||
-rw-r--r-- | service/pixelated/config/credentials.py | 45 | ||||
-rw-r--r-- | service/pixelated/config/leap.py | 114 | ||||
-rw-r--r-- | service/pixelated/config/leap_config.py | 42 | ||||
-rw-r--r-- | service/pixelated/config/logger.py | 55 | ||||
-rw-r--r-- | service/pixelated/config/services.py | 158 | ||||
-rw-r--r-- | service/pixelated/config/sessions.py | 311 | ||||
-rw-r--r-- | service/pixelated/config/site.py | 47 |
9 files changed, 0 insertions, 850 deletions
diff --git a/service/pixelated/config/__init__.py b/service/pixelated/config/__init__.py deleted file mode 100644 index e69de29b..00000000 --- a/service/pixelated/config/__init__.py +++ /dev/null diff --git a/service/pixelated/config/arguments.py b/service/pixelated/config/arguments.py deleted file mode 100644 index 01152a34..00000000 --- a/service/pixelated/config/arguments.py +++ /dev/null @@ -1,78 +0,0 @@ -# -# Copyright (c) 2014 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 os -import argparse - - -def parse_user_agent_args(): - parser = argparse.ArgumentParser(description='Pixelated user agent.') - - parser_add_default_arguments(parser) - - parser.add_argument('--host', default='127.0.0.1', help='the host to run the user agent on') - parser.add_argument('--port', type=int, default=3333, help='the port to run the user agent on') - parser.add_argument('-sk', '--sslkey', metavar='<server.key>', default=None, help='use specified file as web server\'s SSL key (when using the user-agent in server-mode)') - parser.add_argument('-sc', '--sslcert', metavar='<server.crt>', default=None, help='use specified file as web server\'s SSL certificate (when using the user-agent in server-mode)') - parser.add_argument('--multi-user', help='Run user agent in multi user mode', action='store_false', default=True, dest='single_user') - parser.add_argument('-p', '--provider', help='specify a provider for mutli-user mode', metavar='<provider host>', default=None, dest='provider') - parser.add_argument('--banner', help='banner file to show on login screen') - parser.add_argument('--manhole', help='Run an interactive Python shell on port 8008', action='store_true', default=False, dest='manhole') - - args = parser.parse_args() - - return args - - -def parse_maintenance_args(): - parser = argparse.ArgumentParser(description='Pixelated maintenance') - parser_add_default_arguments(parser) - subparsers = parser.add_subparsers(help='commands', dest='command') - subparsers.add_parser('reset', help='reset account command') - mails_parser = subparsers.add_parser('load-mails', help='load mails into account') - mails_parser.add_argument('file', nargs='+', help='file(s) with mail data') - - markov_mails_parser = subparsers.add_parser('markov-generate', help='generate mails using markov chains') - markov_mails_parser.add_argument('--seed', default=None, help='Specify a seed to always generate the same output') - markov_mails_parser.add_argument('-l', '--limit', metavar='count', default='5', help='limit number of generated mails', dest='limit') - markov_mails_parser.add_argument('file', nargs='+', help='file(s) with mail data') - - subparsers.add_parser('dump-soledad', help='dump the soledad database') - subparsers.add_parser('sync', help='sync the soledad database') - subparsers.add_parser('repair', help='repair database if possible') - subparsers.add_parser('integrity-check', help='run integrity check on database') - - return parser.parse_args() - - -def parse_register_args(): - parser = argparse.ArgumentParser(description='Pixelated register') - parser.add_argument('provider', metavar='provider', action='store') - parser.add_argument('username', metavar='username', action='store') - parser.add_argument('-p', '--password', metavar='password', action='store', default=None, help='used just to register account automatically by scripts') - parser.add_argument('-lc', '--leap-provider-cert', metavar='<leap-provider.crt>', default=None, help='use specified file for LEAP provider cert authority certificate (url https://<LEAP-provider-domain>/ca.crt)') - parser.add_argument('-lf', '--leap-provider-cert-fingerprint', metavar='<leap provider certificate fingerprint>', default=None, help='use specified fingerprint to validate connection with LEAP provider', dest='leap_provider_cert_fingerprint') - parser.add_argument('--leap-home', help='The folder where the user agent stores its data. Defaults to ~/.leap', dest='leap_home', default=os.path.join(os.path.expanduser("~"), '.leap')) - parser.add_argument('--invite-code', help='invite code to register a user, if required', dest='invite_code', default=None) - return parser.parse_args() - - -def parser_add_default_arguments(parser): - parser.add_argument('--debug', action='store_true', help='DEBUG mode.') - parser.add_argument('-c', '--config', dest='credentials_file', metavar='<credentials_file>', default=None, help='use specified file for credentials (for test purposes only)') - parser.add_argument('--leap-home', help='The folder where the user agent stores its data. Defaults to ~/.leap', dest='leap_home', default=os.path.join(os.path.expanduser("~"), '.leap')) - parser.add_argument('-lc', '--leap-provider-cert', metavar='<leap-provider.crt>', default=None, help='use specified file for LEAP provider cert authority certificate (url https://<LEAP-provider-domain>/ca.crt)') - parser.add_argument('-lf', '--leap-provider-cert-fingerprint', metavar='<leap provider certificate fingerprint>', default=None, help='use specified fingerprint to validate connection with LEAP provider', dest='leap_provider_cert_fingerprint') diff --git a/service/pixelated/config/credentials.py b/service/pixelated/config/credentials.py deleted file mode 100644 index 89901b3f..00000000 --- a/service/pixelated/config/credentials.py +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (c) 2015 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 os -import getpass -import json -import sys -import ConfigParser - - -def read(credentials_file): - if credentials_file: - return read_from_file(credentials_file) - return prompt_for_credentials() - - -def prompt_for_credentials(): - provider = raw_input('Which provider do you want to connect to:\n') - username = raw_input('What\'s your username registered on the provider:\n') - password = getpass.getpass('Type your password:\n') - return provider, username, password - - -def read_from_file(credentials_file): - config_parser = ConfigParser.ConfigParser() - credentials_file_path = os.path.abspath(os.path.expanduser(credentials_file)) - config_parser.read(credentials_file_path) - provider, user, password = \ - config_parser.get('pixelated', 'leap_server_name'), \ - config_parser.get('pixelated', 'leap_username'), \ - config_parser.get('pixelated', 'leap_password') - return provider, user, password diff --git a/service/pixelated/config/leap.py b/service/pixelated/config/leap.py deleted file mode 100644 index 2b3a242a..00000000 --- a/service/pixelated/config/leap.py +++ /dev/null @@ -1,114 +0,0 @@ -# -# Copyright (c) 2015 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 __future__ import absolute_import - -from leap.common.events import (server as events_server) -from pixelated.adapter.welcome_mail import add_welcome_mail -from pixelated.authentication import Authenticator -from pixelated.bitmask_libraries.certs import LeapCertificate -from pixelated.bitmask_libraries.provider import LeapProvider -from pixelated.config import credentials -from pixelated.config import leap_config -from pixelated.config.sessions import LeapSessionFactory -from twisted.internet import defer -from twisted.logger import Logger - -log = Logger() - - -def initialize_leap_provider(provider_hostname, provider_cert, provider_fingerprint, leap_home): - LeapCertificate.set_cert_and_fingerprint(provider_cert, - provider_fingerprint) - leap_config.set_leap_home(leap_home) - provider = LeapProvider(provider_hostname) - provider.setup_ca() - provider.download_settings() - return provider - - -@defer.inlineCallbacks -def initialize_leap_multi_user(provider_hostname, - leap_provider_cert, - leap_provider_cert_fingerprint, - credentials_file, - leap_home): - - config, provider = initialize_leap_provider(provider_hostname, leap_provider_cert, leap_provider_cert_fingerprint, leap_home) - - defer.returnValue((config, provider)) - - -@defer.inlineCallbacks -def create_leap_session(provider, username, password, auth=None): - leap_session = yield LeapSessionFactory(provider).create(username, password, auth) - defer.returnValue(leap_session) - - -@defer.inlineCallbacks -def initialize_leap_single_user(leap_provider_cert, - leap_provider_cert_fingerprint, - credentials_file, - leap_home): - - init_monkeypatches() - events_server.ensure_server() - - provider, username, password = credentials.read(credentials_file) - - provider = initialize_leap_provider(provider, leap_provider_cert, leap_provider_cert_fingerprint, leap_home) - - auth = yield Authenticator(provider).authenticate(username, password) - - leap_session = yield create_leap_session(provider, username, password, auth) - - defer.returnValue(leap_session) - - -def init_monkeypatches(): - import pixelated.extensions.requests_urllib3 - - -class BootstrapUserServices(object): - - def __init__(self, services_factory, provider): - self._services_factory = services_factory - self._provider = provider - - @defer.inlineCallbacks - def setup(self, user_auth, password, language='pt-BR'): - leap_session = None - try: - leap_session = yield create_leap_session(self._provider, user_auth.username, password, user_auth) - yield self._setup_user_services(leap_session) - yield self._add_welcome_email(leap_session, language) - except Exception as e: - log.warn('{0}: {1}. Closing session for user: {2}'.format(e.__class__.__name__, e, user_auth.username)) - if leap_session: - leap_session.close() - raise - - @defer.inlineCallbacks - def _setup_user_services(self, leap_session): - user_id = leap_session.user_auth.uuid - if not self._services_factory.has_session(user_id): - yield self._services_factory.create_services_from(leap_session) - self._services_factory.map_email(leap_session.user_auth.username, user_id) - - @defer.inlineCallbacks - def _add_welcome_email(self, leap_session, language): - if leap_session.fresh_account: - yield add_welcome_mail(leap_session.mail_store, language) diff --git a/service/pixelated/config/leap_config.py b/service/pixelated/config/leap_config.py deleted file mode 100644 index 7319d82b..00000000 --- a/service/pixelated/config/leap_config.py +++ /dev/null @@ -1,42 +0,0 @@ -# -# Copyright (c) 2014 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 os -from distutils.spawn import find_executable - - -def discover_gpg_binary(): - path = find_executable('gpg') - if path is None: - raise Exception('Did not find a gpg executable!') - - if os.path.islink(path): - path = os.path.realpath(path) - - return path - - -SYSTEM_CA_BUNDLE = True -leap_home = os.path.expanduser('~/.leap/') -gpg_binary = discover_gpg_binary() - - -def set_leap_home(new_home): - leap_home = new_home - - -def set_gpg_binary(new_binary): - gpg_binary = binary diff --git a/service/pixelated/config/logger.py b/service/pixelated/config/logger.py deleted file mode 100644 index bc4ab8d4..00000000 --- a/service/pixelated/config/logger.py +++ /dev/null @@ -1,55 +0,0 @@ -# -# Copyright (c) 2014 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 logging -import os -import sys -import time -from twisted.logger import globalLogBeginner, FileLogObserver - - -class PrivateKeyFilter(logging.Filter): - - def filter(self, record): - if '-----BEGIN PGP PRIVATE KEY BLOCK-----' in record.msg: - record.msg = '*** private key removed by %s.%s ***' % (type(self).__module__, type(self).__name__) - return True - - -def init(debug=False): - debug_enabled = debug or os.environ.get('DEBUG', False) - logging_level = logging.DEBUG if debug_enabled else logging.INFO - - logging.basicConfig(level=logging_level, - format='%(asctime)s [%(name)s] %(levelname)s %(message)s', - datefmt='%Y-%m-%d %H:%M:%S', - filemode='a') - - logging.getLogger('gnupg').setLevel(logging.WARN) - logging.getLogger('gnupg').addFilter(PrivateKeyFilter()) - - def formatter(event): - try: - event['log_time'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(event['log_time'])) - event['log_level'] = event['log_level'].name.upper() - event['log_format'] = str(event['log_format']) + '\n' if event.get('log_format') else '' - logstring = u'{log_time} [{log_namespace}] {log_level} ' + event['log_format'] - return logstring.format(**event) - except Exception as e: - return "Error while formatting log event: {!r}\nOriginal event: {!r}\n".format(e, event) - - observers = [FileLogObserver(sys.stdout, formatter)] - globalLogBeginner.beginLoggingTo(observers) diff --git a/service/pixelated/config/services.py b/service/pixelated/config/services.py deleted file mode 100644 index 48c1a528..00000000 --- a/service/pixelated/config/services.py +++ /dev/null @@ -1,158 +0,0 @@ -# -# Copyright (c) 2015 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 os - -from twisted.internet import defer, reactor -from twisted.logger import Logger - -from pixelated.adapter.mailstore.leap_attachment_store import LeapAttachmentStore -from pixelated.adapter.mailstore.searchable_mailstore import SearchableMailStore -from pixelated.adapter.services.mail_service import MailService -from pixelated.adapter.model.mail import InputMail -from pixelated.adapter.services.mail_sender import MailSender -from pixelated.adapter.search import SearchEngine -from pixelated.adapter.services.draft_service import DraftService -from pixelated.adapter.listeners.mailbox_indexer_listener import listen_all_mailboxes -from pixelated.adapter.search.index_storage_key import SearchIndexStorageKey -from pixelated.adapter.services.feedback_service import FeedbackService -from pixelated.config import leap_config - -logger = Logger() - - -class Services(object): - - def __init__(self, leap_session): - self._leap_home = leap_config.leap_home - self._pixelated_home = os.path.join(self._leap_home, 'pixelated') - self._leap_session = leap_session - - @defer.inlineCallbacks - def setup(self): - search_index_storage_key = self._setup_search_index_storage_key(self._leap_session.soledad) - yield self._setup_search_engine(self._leap_session.user_auth.uuid, search_index_storage_key) - - self._wrap_mail_store_with_indexing_mail_store(self._leap_session) - - yield listen_all_mailboxes(self._leap_session.account, self.search_engine, self._leap_session.mail_store) - - self.mail_service = self._setup_mail_service(self.search_engine) - - self.keymanager = self._leap_session.keymanager - self.draft_service = self._setup_draft_service(self._leap_session.mail_store) - self.feedback_service = self._setup_feedback_service() - yield self._index_all_mails() - - def close(self): - self._leap_session.close() - - def _wrap_mail_store_with_indexing_mail_store(self, leap_session): - leap_session.mail_store = SearchableMailStore(leap_session.mail_store, self.search_engine) - - @defer.inlineCallbacks - def _index_all_mails(self): - all_mails = yield self.mail_service.all_mails() - self.search_engine.index_mails(all_mails) - - @defer.inlineCallbacks - def _setup_search_engine(self, namespace, search_index_storage_key): - key_unicode = yield search_index_storage_key.get_or_create_key() - key = str(key_unicode) - logger.debug('The key len is: %s' % len(key)) - user_id = self._leap_session.user_auth.uuid - user_folder = os.path.join(self._pixelated_home, user_id) - search_engine = SearchEngine(key, user_home=user_folder) - self.search_engine = search_engine - - def _setup_mail_service(self, search_engine): - pixelated_mail_sender = MailSender(self._leap_session.smtp_config, self._leap_session.keymanager.keymanager) - - return MailService( - pixelated_mail_sender, - self._leap_session.mail_store, - search_engine, - self._leap_session.account_email(), - LeapAttachmentStore(self._leap_session.soledad)) - - def _setup_draft_service(self, mail_store): - return DraftService(mail_store) - - def _setup_search_index_storage_key(self, soledad): - return SearchIndexStorageKey(soledad) - - def _setup_feedback_service(self): - return FeedbackService(self._leap_session) - - -class ServicesFactory(object): - - def __init__(self, mode): - self._services_by_user = {} - self.mode = mode - self._map_email = {} - - def map_email(self, username, user_id): - self._map_email[username] = user_id - - def has_session(self, user_id): - return user_id in self._services_by_user - - def services(self, user_id): - return self._services_by_user[user_id] - - def destroy_session(self, user_id, using_email=False): - if using_email: - username = user_id.split('@')[0] - user_id = self._map_email.get(username, None) - - if user_id is not None and self.has_session(user_id): - _services = self._services_by_user[user_id] - _services.close() - del self._services_by_user[user_id] - - def add_session(self, user_id, services): - self._services_by_user[user_id] = services - - def online_sessions(self): - return len(self._services_by_user.keys()) - - @defer.inlineCallbacks - def create_services_from(self, leap_session): - _services = Services(leap_session) - yield _services.setup() - self._services_by_user[leap_session.user_auth.uuid] = _services - - -class SingleUserServicesFactory(object): - def __init__(self, mode): - self._services = None - self.mode = mode - - def add_session(self, user_id, services): - self._services = services - - def services(self, user_id): - return self._services - - def has_session(self, user_id): - return True - - def destroy_session(self, user_id, using_email=False): - reactor.stop() - - def online_sessions(self): - return 1 diff --git a/service/pixelated/config/sessions.py b/service/pixelated/config/sessions.py deleted file mode 100644 index 594b8e35..00000000 --- a/service/pixelated/config/sessions.py +++ /dev/null @@ -1,311 +0,0 @@ -# -# Copyright (c) 2015 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 __future__ import absolute_import - -import os -import errno -import requests - -from twisted.internet import defer, threads, reactor -from twisted.logger import Logger - -from leap.soledad.common.crypto import WrongMacError, UnknownMacMethodError -from leap.soledad.client import Soledad -from leap.bitmask.mail.incoming.service import IncomingMail -from leap.bitmask.mail.mail import Account -import leap.common.certs as leap_certs -from leap.common.events import ( - register, unregister, - catalog as events -) - -from pixelated.bitmask_libraries.keymanager import Keymanager -from pixelated.adapter.mailstore import LeapMailStore -from pixelated.config import leap_config -from pixelated.bitmask_libraries.smtp import LeapSMTPConfig - -logger = Logger() - - -class LeapSessionFactory(object): - def __init__(self, provider): - self._provider = provider - - @defer.inlineCallbacks - def create(self, username, password, auth): - key = SessionCache.session_key(self._provider, username) - session = SessionCache.lookup_session(key) - if not session: - session = yield self._create_new_session(username, password, auth) - yield session.first_required_sync() - SessionCache.remember_session(key, session) - defer.returnValue(session) - - @defer.inlineCallbacks - def _create_new_session(self, username, password, auth): - account_email = self._provider.address_for(username) - - self._create_database_dir(auth.uuid) - - api_cert = self._provider.provider_api_cert - - soledad = yield self.setup_soledad(auth.token, auth.uuid, password, api_cert) - - mail_store = LeapMailStore(soledad) - - keymanager = yield self.setup_keymanager(self._provider, soledad, account_email, auth.token, auth.uuid) - - smtp_client_cert = self._download_smtp_cert(auth) - smtp_host, smtp_port = self._provider.smtp_info() - smtp_config = LeapSMTPConfig(account_email, smtp_client_cert, smtp_host, smtp_port) - - leap_session = LeapSession(self._provider, auth, mail_store, soledad, keymanager, smtp_config) - - defer.returnValue(leap_session) - - @defer.inlineCallbacks - def setup_soledad(self, - user_token, - user_uuid, - password, - api_cert): - secrets = self._secrets_path(user_uuid) - local_db = self._local_db_path(user_uuid) - server_url = self._provider.discover_soledad_server(user_uuid) - try: - soledad = yield threads.deferToThread(Soledad, - user_uuid.encode('utf-8'), - passphrase=unicode(password, 'utf-8'), - secrets_path=secrets, - local_db_path=local_db, - server_url=server_url, - cert_file=api_cert, - shared_db=None, - auth_token=user_token) - defer.returnValue(soledad) - except (WrongMacError, UnknownMacMethodError), e: - raise SoledadWrongPassphraseException(e) - - @defer.inlineCallbacks - def setup_keymanager(self, provider, soledad, account_email, token, uuid): - keymanager = yield threads.deferToThread(Keymanager, - provider, - soledad, - account_email, - token, - uuid) - defer.returnValue(keymanager) - - def _download_smtp_cert(self, auth): - cert = SmtpClientCertificate(self._provider, auth, self._user_path(auth.uuid)) - return cert.cert_path() - - def _user_path(self, user_uuid): - return os.path.join(leap_config.leap_home, user_uuid) - - def _soledad_path(self, user_uuid): - return os.path.join(leap_config.leap_home, user_uuid, 'soledad') - - def _secrets_path(self, user_uuid): - return os.path.join(self._soledad_path(user_uuid), 'secrets') - - def _local_db_path(self, user_uuid): - return os.path.join(self._soledad_path(user_uuid), 'soledad.db') - - def _create_database_dir(self, user_uuid): - try: - os.makedirs(self._soledad_path(user_uuid)) - except OSError as exc: - if exc.errno == errno.EEXIST and os.path.isdir(self._soledad_path(user_uuid)): - pass - else: - raise - - -class LeapSession(object): - - def __init__(self, provider, user_auth, mail_store, soledad, keymanager, smtp_config): - self.smtp_config = smtp_config - self.provider = provider - self.user_auth = user_auth - self.mail_store = mail_store - self.soledad = soledad - self.keymanager = keymanager - self.fresh_account = False - self.incoming_mail_fetcher = None - self.account = None - self._has_been_initially_synced = False - self._is_closed = False - register(events.KEYMANAGER_FINISHED_KEY_GENERATION, self._set_fresh_account, uid=self.account_email(), replace=True) - - @defer.inlineCallbacks - def first_required_sync(self): - yield self.sync() - yield self.finish_bootstrap() - - @defer.inlineCallbacks - def finish_bootstrap(self): - yield self.keymanager.generate_openpgp_key() - yield self._create_account(self.soledad, self.user_auth.uuid) - self.incoming_mail_fetcher = yield self._create_incoming_mail_fetcher( - self.keymanager, - self.soledad, - self.account, - self.account_email()) - reactor.callFromThread(self.incoming_mail_fetcher.startService) - - def _create_account(self, soledad, user_id): - self.account = Account(soledad, user_id) - return self.account.deferred_initialization - - def _set_fresh_account(self, event, email_address): - logger.debug('Key for email %s has been generated' % email_address) - if email_address == self.account_email(): - self.fresh_account = True - - def account_email(self): - name = self.user_auth.username - return self.provider.address_for(name) - - def close(self): - self.stop_background_jobs() - unregister(events.KEYMANAGER_FINISHED_KEY_GENERATION, uid=self.account_email()) - self.soledad.close() - self._close_account() - self.remove_from_cache() - self._is_closed = True - - @property - def is_closed(self): - return self._is_closed - - def _close_account(self): - if self.account: - self.account.end_session() - - def remove_from_cache(self): - key = SessionCache.session_key(self.provider, self.user_auth.username) - SessionCache.remove_session(key) - - @defer.inlineCallbacks - def _create_incoming_mail_fetcher(self, keymanager, soledad, account, user_mail): - inbox = yield account.callWhenReady(lambda _: account.get_collection_by_mailbox('INBOX')) - defer.returnValue(IncomingMail(keymanager.keymanager, - soledad, - inbox, - user_mail)) - - def stop_background_jobs(self): - if self.incoming_mail_fetcher: - reactor.callFromThread(self.incoming_mail_fetcher.stopService) - self.incoming_mail_fetcher = None - - def sync(self): - try: - return self.soledad.sync() - except Exception as e: - logger.error(e) - raise - - -class SessionCache(object): - - sessions = {} - - @staticmethod - def lookup_session(key): - session = SessionCache.sessions.get(key, None) - if session is not None and session.is_closed: - SessionCache.remove_session(key) - return None - return session - - @staticmethod - def remember_session(key, session): - SessionCache.sessions[key] = session - - @staticmethod - def remove_session(key): - if key in SessionCache.sessions: - del SessionCache.sessions[key] - - @staticmethod - def session_key(provider, username): - return hash((provider, username)) - - -class SmtpClientCertificate(object): - def __init__(self, provider, auth, user_path): - self._provider = provider - self._auth = auth - self._user_path = user_path - - def cert_path(self): - if not self._is_cert_already_downloaded() or self._should_redownload(): - self._download_smtp_cert() - - return self._smtp_client_cert_path() - - def _is_cert_already_downloaded(self): - return os.path.exists(self._smtp_client_cert_path()) - - def _should_redownload(self): - return leap_certs.should_redownload(self._smtp_client_cert_path()) - - def _download_smtp_cert(self): - cert_path = self._smtp_client_cert_path() - - if not os.path.exists(os.path.dirname(cert_path)): - os.makedirs(os.path.dirname(cert_path)) - - self.download_to(cert_path) - - def _smtp_client_cert_path(self): - return os.path.join( - self._user_path, - "providers", - self._provider.domain, - "keys", "client", "smtp.pem") - - def download(self): - cert_url = '%s/%s/smtp_cert' % (self._provider.api_uri, self._provider.api_version) - headers = {} - headers["Authorization"] = 'Token token="{0}"'.format(self._auth.token) - params = {'address': self._auth.username} - response = requests.post( - cert_url, - params=params, - data=params, - verify=self._provider.provider_api_cert, - timeout=15, - headers=headers) - response.raise_for_status() - - client_cert = response.content - - return client_cert - - def download_to(self, target_file): - client_cert = self.download() - - with open(target_file, 'w') as f: - f.write(client_cert) - - -class SoledadWrongPassphraseException(Exception): - def __init__(self, *args, **kwargs): - super(SoledadWrongPassphraseException, self).__init__(*args, **kwargs) diff --git a/service/pixelated/config/site.py b/service/pixelated/config/site.py deleted file mode 100644 index 96554584..00000000 --- a/service/pixelated/config/site.py +++ /dev/null @@ -1,47 +0,0 @@ -# -# Copyright (c) 2015 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.server import Site, Request - - -class AddSecurityHeadersRequest(Request): - CSP_HEADER_VALUES = "default-src 'self'; style-src 'self' 'unsafe-inline'" - - def process(self): - self.setHeader('Content-Security-Policy', self.CSP_HEADER_VALUES) - self.setHeader('X-Content-Security-Policy', self.CSP_HEADER_VALUES) - self.setHeader('X-Webkit-CSP', self.CSP_HEADER_VALUES) - self.setHeader('X-Frame-Options', 'SAMEORIGIN') - self.setHeader('X-XSS-Protection', '1; mode=block') - self.setHeader('X-Content-Type-Options', 'nosniff') - - if self.isSecure(): - self.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains') - - Request.process(self) - - -class PixelatedSite(Site): - - requestFactory = AddSecurityHeadersRequest - - @classmethod - def enable_csp_requests(cls): - cls.requestFactory = AddSecurityHeadersRequest - - @classmethod - def disable_csp_requests(cls): - cls.requestFactory = Site.requestFactory |