summaryrefslogtreecommitdiff
path: root/service/pixelated/bitmask_libraries
diff options
context:
space:
mode:
Diffstat (limited to 'service/pixelated/bitmask_libraries')
-rw-r--r--service/pixelated/bitmask_libraries/certs.py104
-rw-r--r--service/pixelated/bitmask_libraries/config.py48
-rw-r--r--service/pixelated/bitmask_libraries/nicknym.py10
-rw-r--r--service/pixelated/bitmask_libraries/provider.py14
-rw-r--r--service/pixelated/bitmask_libraries/session.py56
-rw-r--r--service/pixelated/bitmask_libraries/smtp.py19
-rw-r--r--service/pixelated/bitmask_libraries/soledad.py14
7 files changed, 72 insertions, 193 deletions
diff --git a/service/pixelated/bitmask_libraries/certs.py b/service/pixelated/bitmask_libraries/certs.py
index a321e00e..9d543672 100644
--- a/service/pixelated/bitmask_libraries/certs.py
+++ b/service/pixelated/bitmask_libraries/certs.py
@@ -14,108 +14,42 @@
# 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 requests
-import json
-from leap.common import ca_bundle
-from .config import AUTO_DETECT_CA_BUNDLE
-LEAP_CERT = None
-LEAP_FINGERPRINT = None
-PACKAGED_CERTS_HOME = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "certificates"))
-
-
-def which_api_CA_bundle(provider):
- return str(LeapCertificate(provider).api_ca_bundle())
-
-
-def which_bootstrap_cert_fingerprint():
- return LEAP_FINGERPRINT
-
-
-def which_bootstrap_CA_bundle(provider):
- if LEAP_CERT is not None:
- return LEAP_CERT
- return str(LeapCertificate(provider).auto_detect_bootstrap_ca_bundle())
-
-
-def refresh_ca_bundle(provider):
- LeapCertificate(provider).refresh_ca_bundle()
+class LeapCertificate(object):
+ LEAP_CERT = None
+ LEAP_FINGERPRINT = None
-class LeapCertificate(object):
def __init__(self, provider):
self._config = provider.config
self._server_name = provider.server_name
self._provider = provider
- def auto_detect_bootstrap_ca_bundle(self):
- if self._config.bootstrap_ca_cert_bundle == AUTO_DETECT_CA_BUNDLE:
- local_cert = self._local_bootstrap_server_cert()
- if local_cert:
- return local_cert
- else:
- return ca_bundle.where()
+ @staticmethod
+ def set_cert_and_fingerprint(cert_file=None, cert_fingerprint=None):
+ if cert_fingerprint is None:
+ LeapCertificate.LEAP_CERT = str(cert_file) if cert_file else True
+ LeapCertificate.LEAP_FINGERPRINT = None
else:
- return self._config.bootstrap_ca_cert_bundle
-
- def api_ca_bundle(self):
- if self._provider.config.ca_cert_bundle:
- return self._provider.config.ca_cert_bundle
-
- cert_file = self._api_cert_file()
-
- if not os.path.isfile(cert_file):
- self._download_server_cert(cert_file)
+ LeapCertificate.LEAP_FINGERPRINT = cert_fingerprint
+ LeapCertificate.LEAP_CERT = False
- return cert_file
+ @property
+ def provider_web_cert(self):
+ return self.LEAP_CERT
- def refresh_ca_bundle(self):
- cert_file = self._api_cert_file()
- self._download_server_cert(cert_file)
+ @property
+ def provider_api_cert(self):
+ return str(os.path.join(self._provider.config.leap_home, 'providers', self._server_name, 'keys', 'client', 'api.pem'))
- def _api_cert_file(self):
- certs_root = self._api_certs_root_path()
- return os.path.join(certs_root, 'api.pem')
-
- def _api_certs_root_path(self):
+ def setup_ca_bundle(self):
path = os.path.join(self._provider.config.leap_home, 'providers', self._server_name, 'keys', 'client')
if not os.path.isdir(path):
os.makedirs(path, 0700)
- return path
-
- def _local_bootstrap_server_cert(self):
- cert_file = self._bootstrap_certs_cert_file()
- if os.path.isfile(cert_file):
- return cert_file
-
- cert_file = os.path.join(PACKAGED_CERTS_HOME, '%s.ca.crt' % self._server_name)
- if os.path.exists(cert_file):
- return cert_file
-
- # else download the file
- cert_file = self._bootstrap_certs_cert_file()
- response = requests.get('https://%s/provider.json' % self._server_name)
- provider_data = json.loads(response.content)
- ca_cert_uri = str(provider_data['ca_cert_uri'])
-
- response = requests.get(ca_cert_uri)
- with open(cert_file, 'w') as file:
- file.write(response.content)
-
- return cert_file
-
- def _bootstrap_certs_cert_file(self):
- path = os.path.join(self._provider.config.leap_home, 'providers', self._server_name)
- if not os.path.isdir(path):
- os.makedirs(path, 0700)
+ self._download_cert(self.provider_api_cert)
- file_path = os.path.join(path, '%s.ca.crt' % self._server_name)
-
- return file_path
-
- def _download_server_cert(self, cert_file_name):
+ def _download_cert(self, cert_file_name):
cert = self._provider.fetch_valid_certificate()
-
with open(cert_file_name, 'w') as file:
file.write(cert)
diff --git a/service/pixelated/bitmask_libraries/config.py b/service/pixelated/bitmask_libraries/config.py
index 8c862d0a..efb43411 100644
--- a/service/pixelated/bitmask_libraries/config.py
+++ b/service/pixelated/bitmask_libraries/config.py
@@ -13,10 +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/>.
-from distutils.spawn import find_executable
import os
-from os.path import expanduser
+from distutils.spawn import find_executable
def discover_gpg_binary():
@@ -30,54 +29,19 @@ def discover_gpg_binary():
return path
-DEFAULT_LEAP_HOME = os.path.join(expanduser("~"), '.leap')
-
SYSTEM_CA_BUNDLE = True
-AUTO_DETECT_CA_BUNDLE = None
class LeapConfig(object):
- """
- LEAP client configuration
- """
-
- def __init__(self, leap_home=DEFAULT_LEAP_HOME, bootstrap_ca_cert_bundle=AUTO_DETECT_CA_BUNDLE,
- ca_cert_bundle=AUTO_DETECT_CA_BUNDLE, verify_ssl=True,
+ def __init__(self,
+ leap_home=None,
fetch_interval_in_s=30,
- timeout_in_s=15, start_background_jobs=False, gpg_binary=discover_gpg_binary()):
- """
- Constructor.
-
- :param server_name: The LEAP server name, e.g. demo.leap.se
- :type server_name: str
-
- :param user_name: The LEAP account user name, normally the first part of your email, e.g. foobar for foobar@demo.leap.se
- :type user_name: str
-
- :param user_password: The LEAP account password
- :type user_password: str
-
- :param db_passphrase: The passphrase used to encrypt the local soledad database
- :type db_passphrase: str
-
- :param verify_ssl: Set to false to disable strict SSL certificate validation
- :type verify_ssl: bool
-
- :param fetch_interval_in_s: Polling interval for fetching incoming mail from LEAP server
- :type fetch_interval_in_s: int
-
- :param timeout_in_s: Timeout for network operations, e.g. HTTP calls
- :type timeout_in_s: int
-
- :param gpg_binary: Path to the GPG binary (must not be a symlink)
- :type gpg_binary: str
+ timeout_in_s=15,
+ start_background_jobs=False,
+ gpg_binary=discover_gpg_binary()):
- """
self.leap_home = leap_home
- self.bootstrap_ca_cert_bundle = bootstrap_ca_cert_bundle
- self.ca_cert_bundle = ca_cert_bundle
- self.verify_ssl = verify_ssl
self.timeout_in_s = timeout_in_s
self.start_background_jobs = start_background_jobs
self.gpg_binary = gpg_binary
diff --git a/service/pixelated/bitmask_libraries/nicknym.py b/service/pixelated/bitmask_libraries/nicknym.py
index bee90897..220d75e5 100644
--- a/service/pixelated/bitmask_libraries/nicknym.py
+++ b/service/pixelated/bitmask_libraries/nicknym.py
@@ -14,16 +14,16 @@
# 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 import KeyManager, openpgp, KeyNotFound
-from .certs import which_api_CA_bundle
+from .certs import LeapCertificate
class NickNym(object):
- def __init__(self, provider, config, soledad_session, username, token, uuid):
+ def __init__(self, provider, config, soledad_session, email_address, token, uuid):
nicknym_url = _discover_nicknym_server(provider)
- self._email = '%s@%s' % (username, provider.domain)
- self.keymanager = KeyManager('%s@%s' % (username, provider.domain), nicknym_url,
+ self._email = email_address
+ self.keymanager = KeyManager(self._email, nicknym_url,
soledad_session.soledad,
- token, which_api_CA_bundle(provider), provider.api_uri,
+ token, LeapCertificate(provider).provider_api_cert, provider.api_uri,
provider.api_version,
uuid, config.gpg_binary)
diff --git a/service/pixelated/bitmask_libraries/provider.py b/service/pixelated/bitmask_libraries/provider.py
index 1564c974..315ea7f1 100644
--- a/service/pixelated/bitmask_libraries/provider.py
+++ b/service/pixelated/bitmask_libraries/provider.py
@@ -17,7 +17,7 @@ import json
from leap.common.certs import get_digest
import requests
-from .certs import which_bootstrap_CA_bundle, which_api_CA_bundle, which_bootstrap_cert_fingerprint
+from .certs import LeapCertificate
from pixelated.support.tls_adapter import EnforceTLSv1Adapter
@@ -26,7 +26,6 @@ class LeapProvider(object):
self.server_name = server_name
self.config = config
self.local_ca_crt = '%s/ca.crt' % self.config.leap_home
-
self.provider_json = self.fetch_provider_json()
@property
@@ -99,8 +98,8 @@ class LeapProvider(object):
def _validated_get(self, url):
session = requests.session()
try:
- session.mount('https://', EnforceTLSv1Adapter(assert_fingerprint=which_bootstrap_cert_fingerprint()))
- response = session.get(url, verify=which_bootstrap_CA_bundle(self), timeout=self.config.timeout_in_s)
+ session.mount('https://', EnforceTLSv1Adapter(assert_fingerprint=LeapCertificate.LEAP_FINGERPRINT))
+ response = session.get(url, verify=LeapCertificate(self).provider_web_cert, timeout=self.config.timeout_in_s)
response.raise_for_status()
return response
finally:
@@ -115,16 +114,19 @@ class LeapProvider(object):
def fetch_soledad_json(self):
service_url = "%s/%s/config/soledad-service.json" % (
self.api_uri, self.api_version)
- response = requests.get(service_url, verify=which_api_CA_bundle(self), timeout=self.config.timeout_in_s)
+ response = requests.get(service_url, verify=LeapCertificate(self).provider_api_cert, timeout=self.config.timeout_in_s)
response.raise_for_status()
return json.loads(response.content)
def fetch_smtp_json(self):
service_url = '%s/%s/config/smtp-service.json' % (
self.api_uri, self.api_version)
- response = requests.get(service_url, verify=which_api_CA_bundle(self), timeout=self.config.timeout_in_s)
+ response = requests.get(service_url, verify=LeapCertificate(self).provider_api_cert, timeout=self.config.timeout_in_s)
response.raise_for_status()
return json.loads(response.content)
def _provider_base_url(self):
return 'https://%s' % self.server_name
+
+ def address_for(self, username):
+ return '%s@%s' % (username, self.domain)
diff --git a/service/pixelated/bitmask_libraries/session.py b/service/pixelated/bitmask_libraries/session.py
index 12cbd91b..a9cb15f2 100644
--- a/service/pixelated/bitmask_libraries/session.py
+++ b/service/pixelated/bitmask_libraries/session.py
@@ -22,29 +22,16 @@ from leap.mail.imap.fetch import LeapIncomingMail
from leap.mail.imap.account import SoledadBackedAccount
from leap.mail.imap.memorystore import MemoryStore
from leap.mail.imap.soledadstore import SoledadStore
-from pixelated.bitmask_libraries.config import LeapConfig
-from pixelated.bitmask_libraries.provider import LeapProvider
-from pixelated.bitmask_libraries.certs import refresh_ca_bundle
from twisted.internet import reactor
from .nicknym import NickNym
from leap.auth import SRPAuth
from .soledad import SoledadSessionFactory
from .smtp import LeapSmtp
-from .config import DEFAULT_LEAP_HOME
SESSIONS = {}
-def open_leap_session(username, password, server_name, leap_home=DEFAULT_LEAP_HOME):
- config = LeapConfig(leap_home=leap_home)
- provider = LeapProvider(server_name, config)
- refresh_ca_bundle(provider)
- session = LeapSessionFactory(provider).create(username, password)
-
- return session
-
-
class LeapSession(object):
"""
A LEAP session.
@@ -52,9 +39,13 @@ class LeapSession(object):
Properties:
- - ``leap_config`` the configuration for this session (LeapClientConfig).
+ - ``smtp`` the smtp gateway instance (LeapSmtp).
+
+ - ``config`` the configuration for this session (LeapClientConfig).
+
+ - ``provider`` the responsible for interacting with provider.json (LeapProvider).
- - ``srp_session`` the secure remote password session to authenticate with LEAP. See http://en.wikipedia.org/wiki/Secure_Remote_Password_protocol (LeapSecureRemotePassword)
+ - ``user_auth`` the secure remote password session data after authenticating with LEAP. See http://en.wikipedia.org/wiki/Secure_Remote_Password_protocol (SRPSession)
- ``soledad_session`` the soledad session. See https://leap.se/soledad (LeapSecureRemotePassword)
@@ -66,13 +57,6 @@ class LeapSession(object):
"""
def __init__(self, provider, user_auth, soledad_session, nicknym, soledad_account, incoming_mail_fetcher, smtp):
- """
- Constructor.
-
- :param leap_config: The config for this LEAP session
- :type leap_config: LeapConfig
-
- """
self.smtp = smtp
self.config = provider.config
self.provider = provider
@@ -81,22 +65,25 @@ class LeapSession(object):
self.nicknym = nicknym
self.account = soledad_account
self.incoming_mail_fetcher = incoming_mail_fetcher
+ self.soledad_session.soledad.sync(defer_decryption=False)
+ self.nicknym.generate_openpgp_key()
if self.config.start_background_jobs:
self.start_background_jobs()
def account_email(self):
- domain = self.provider.domain
name = self.user_auth.username
- return '%s@%s' % (name, domain)
+ return self.provider.address_for(name)
def close(self):
self.stop_background_jobs()
def start_background_jobs(self):
+ self.smtp.ensure_running()
reactor.callFromThread(self.incoming_mail_fetcher.start_loop)
def stop_background_jobs(self):
+ self.smtp.stop()
reactor.callFromThread(self.incoming_mail_fetcher.stop)
def sync(self):
@@ -127,16 +114,15 @@ class LeapSessionFactory(object):
srp_auth = SRPAuth(self._provider.api_uri, self._provider.local_ca_crt)
auth = srp_auth.authenticate(username, password)
+ account_email = self._provider.address_for(username)
soledad = SoledadSessionFactory.create(self._provider, auth.token, auth.uuid, password)
- nicknym = self._create_nicknym(auth.username, auth.token, auth.uuid, soledad)
+ nicknym = self._create_nicknym(account_email, auth.token, auth.uuid, soledad)
account = self._create_account(auth.uuid, soledad)
- incoming_mail_fetcher = self._create_incoming_mail_fetcher(nicknym, soledad, account, auth.username)
+ incoming_mail_fetcher = self._create_incoming_mail_fetcher(nicknym, soledad, account, account_email)
- smtp = LeapSmtp(self._provider, auth.username, auth.session_id, nicknym.keymanager)
-
- smtp.ensure_running()
+ smtp = LeapSmtp(self._provider, auth, nicknym.keymanager)
return LeapSession(self._provider, auth, soledad, nicknym, account, incoming_mail_fetcher, smtp)
@@ -163,17 +149,13 @@ class LeapSessionFactory(object):
else:
raise
- def _create_nicknym(self, username, token, uuid, soledad_session):
- return NickNym(self._provider, self._config, soledad_session, username, token, uuid)
+ def _create_nicknym(self, email_address, token, uuid, soledad_session):
+ return NickNym(self._provider, self._config, soledad_session, email_address, token, uuid)
def _create_account(self, uuid, soledad_session):
memstore = MemoryStore(permanent_store=SoledadStore(soledad_session.soledad))
return SoledadBackedAccount(uuid, soledad_session.soledad, memstore)
- def _create_incoming_mail_fetcher(self, nicknym, soledad_session, account, username):
+ def _create_incoming_mail_fetcher(self, nicknym, soledad_session, account, email_address):
return LeapIncomingMail(nicknym.keymanager, soledad_session.soledad, account,
- self._config.fetch_interval_in_s, self._account_email(username))
-
- def _account_email(self, username):
- domain = self._provider.domain
- return '%s@%s' % (username, domain)
+ self._config.fetch_interval_in_s, email_address)
diff --git a/service/pixelated/bitmask_libraries/smtp.py b/service/pixelated/bitmask_libraries/smtp.py
index c22601d2..31e56995 100644
--- a/service/pixelated/bitmask_libraries/smtp.py
+++ b/service/pixelated/bitmask_libraries/smtp.py
@@ -17,8 +17,8 @@ import logging
import os
import requests
import random
-from .certs import which_api_CA_bundle
from leap.mail.smtp import setup_smtp_gateway
+from pixelated.bitmask_libraries.certs import LeapCertificate
logger = logging.getLogger(__name__)
@@ -26,11 +26,12 @@ logger = logging.getLogger(__name__)
class LeapSmtp(object):
- def __init__(self, provider, username, session_id, keymanager=None):
+ def __init__(self, provider, auth, keymanager=None):
self.local_smtp_port_number = random.randrange(12000, 16000)
self._provider = provider
- self.username = username
- self.session_id = session_id
+ self.username = auth.username
+ self.session_id = auth.session_id
+ self.user_token = auth.token
self._keymanager = keymanager
self._remote_hostname, self._remote_port = self._discover_remote_smtp_server()
self._local_smtp_service_socket = None
@@ -58,8 +59,14 @@ class LeapSmtp(object):
cert_url = '%s/%s/cert' % (self._provider.api_uri, self._provider.api_version)
cookies = {"_session_id": self.session_id}
-
- response = requests.get(cert_url, verify=which_api_CA_bundle(self._provider), cookies=cookies, timeout=self._provider.config.timeout_in_s)
+ headers = {}
+ headers["Authorization"] = 'Token token="{0}"'.format(self.user_token)
+ response = requests.get(
+ cert_url,
+ verify=LeapCertificate(self._provider).provider_api_cert,
+ cookies=cookies,
+ timeout=self._provider.config.timeout_in_s,
+ headers=headers)
response.raise_for_status()
client_cert = response.content
diff --git a/service/pixelated/bitmask_libraries/soledad.py b/service/pixelated/bitmask_libraries/soledad.py
index f3fca95a..f0cd9f2f 100644
--- a/service/pixelated/bitmask_libraries/soledad.py
+++ b/service/pixelated/bitmask_libraries/soledad.py
@@ -16,11 +16,9 @@
import errno
import os
-from leap.keymanager import KeyManager
from leap.soledad.client import Soledad
from leap.soledad.common.crypto import WrongMac, UnknownMacMethod
-from .certs import which_api_CA_bundle
-
+from pixelated.bitmask_libraries.certs import LeapCertificate
SOLEDAD_TIMEOUT = 120
SOLEDAD_CERT = '/tmp/ca.crt'
@@ -36,14 +34,6 @@ class SoledadWrongPassphraseException(Exception):
super(SoledadWrongPassphraseException, self).__init__(*args, **kwargs)
-class LeapKeyManager(object):
- def __init__(self, soledad, leap_session, nicknym_url):
- provider = leap_session.provider
- self.keymanager = KeyManager(leap_session.account_email(), nicknym_url, soledad,
- leap_session.session_id, leap_session.leap_home + '/ca.crt', provider.api_uri, leap_session.api_version,
- leap_session.uuid, leap_session.leap_config.gpg_binary)
-
-
class SoledadSessionFactory(object):
@classmethod
def create(cls, provider, user_token, user_uuid, encryption_passphrase):
@@ -68,7 +58,7 @@ class SoledadSession(object):
local_db = self._local_db_path()
return Soledad(self.user_uuid, unicode(encryption_passphrase), secrets,
- local_db, server_url, which_api_CA_bundle(self.provider), self.user_token, defer_encryption=False)
+ local_db, server_url, LeapCertificate(self.provider).provider_api_cert, self.user_token, defer_encryption=False)
except (WrongMac, UnknownMacMethod), e:
raise SoledadWrongPassphraseException(e)