Exemple #1
0
def sign(data, privkey):
    """
    Sign C{data} with C{privkey}.

    @param data: The data to be signed.
    @type data: str
    @param privkey: The private key to be used to sign.
    @type privkey: OpenPGPKey

    @return: The ascii-armored signed data.
    @rtype: str
    """
    leap_assert_type(privkey, OpenPGPKey)
    leap_assert(privkey.private is True)

    def _sign_cb(gpg):
        result = gpg.sign(data, keyid=privkey.key_id)
        # result.fingerprint - contains the fingerprint of the key used to
        #                      sign.
        if result.fingerprint is None:
            raise SignFailed('Failed to sign with key %s: %s' %
                             (privkey.key_id, result.stderr))
        leap_assert(
            result.fingerprint == privkey.fingerprint,
            'Signature and private key fingerprints mismatch: %s != %s' %
            (result.fingerprint, privkey.fingerprint))
        return result.data

    return _safe_call(_sign_cb, [privkey])
Exemple #2
0
def encrypt_asym(data, pubkey, sign=None):
    """
    Encrypt C{data} using public @{key} and sign with C{sign} key.

    @param data: The data to be encrypted.
    @type data: str
    @param pubkey: The key used to encrypt.
    @type pubkey: OpenPGPKey
    @param sign: The key used for signing.
    @type sign: OpenPGPKey

    @return: The encrypted data.
    @rtype: str
    """
    leap_assert_type(pubkey, OpenPGPKey)
    leap_assert(pubkey.private is False, 'Key is not public.')
    if sign is not None:
        leap_assert_type(sign, OpenPGPKey)
        leap_assert(sign.private is True)

    def _encrypt_cb(gpg):
        result = gpg.encrypt(data,
                             pubkey.fingerprint,
                             sign=sign.key_id if sign else None,
                             symmetric=False)
        # Here we cannot assert for correctness of sig because the sig is in
        # the ciphertext.
        # result.ok    - (bool) indicates if the operation succeeded
        # result.data  - (bool) contains the result of the operation
        if result.ok is False:
            raise EncryptionFailed('Failed to encrypt with key %s: %s' %
                                   (pubkey.key_id, result.stderr))
        return result.data

    return _safe_call(_encrypt_cb, [pubkey, sign])
Exemple #3
0
def encrypt_sym(data, passphrase, sign=None):
    """
    Encrypt C{data} with C{passphrase} and sign with C{sign} private key.

    @param data: The data to be encrypted.
    @type data: str
    @param passphrase: The passphrase used to encrypt C{data}.
    @type passphrase: str
    @param sign: The private key used for signing.
    @type sign: OpenPGPKey

    @return: The encrypted data.
    @rtype: str
    """
    leap_assert_type(passphrase, str)
    if sign is not None:
        leap_assert_type(sign, OpenPGPKey)
        leap_assert(sign.private is True)

    def _encrypt_cb(gpg):
        result = gpg.encrypt(data,
                             None,
                             sign=sign.key_id if sign else None,
                             passphrase=passphrase,
                             symmetric=True)
        # Here we cannot assert for correctness of sig because the sig is in
        # the ciphertext.
        # result.ok    - (bool) indicates if the operation succeeded
        # result.data  - (bool) contains the result of the operation
        if result.ok is False:
            raise EncryptionFailed('Failed to encrypt: %s' % result.stderr)
        return result.data

    return _safe_call(_encrypt_cb, [sign])
Exemple #4
0
    def tearDownEnv(cls):
        """
        Cleanup common facilities used for testing this TestCase:
        - restores the default PATH and HOME variables
        - removes the temporal folder
        """
        if flags.EVENTS_ENABLED:
            events_client.shutdown()
            cls._server.shutdown()

        os.environ["PATH"] = cls.old_path
        os.environ["HOME"] = cls.old_home
        if cls.old_xdg_config is not None:
            os.environ["XDG_CONFIG_HOME"] = cls.old_xdg_config
        # safety check! please do not wipe my home...
        # XXX needs to adapt to non-linuces
        leap_assert(
            cls.tempdir.startswith('/tmp/leap_tests-')
            or (cls.tempdir.startswith('/tmp/')
                and cls.tempdir.startswith(tempfile.gettempdir())
                and 'leap_tests-' in cls.tempdir)
            or cls.tempdir.startswith('/var/folder'),
            "beware! tried to remove a dir which does not "
            "live in temporal folder!")
        shutil.rmtree(cls.tempdir)
    def _gen_key(self):
        """
        Generates the key pair if needed, uploads it to the webapp and
        nickserver
        """
        leap_assert(self._provider_config is not None, "We need a provider configuration!")
        leap_assert(self._soledad is not None, "We need a non-null soledad to generate keys")

        address = make_address(self._user, self._provider_config.get_domain())
        logger.debug("Retrieving key for %s" % (address,))

        try:
            self._keymanager.get_key(address, openpgp.OpenPGPKey, private=True, fetch_remote=False)
            return
        except KeyNotFound:
            logger.debug("Key not found. Generating key for %s" % (address,))

        # generate key
        try:
            self._keymanager.gen_key(openpgp.OpenPGPKey)
        except Exception as exc:
            logger.error("Error while generating key!")
            logger.exception(exc)
            raise

        # send key
        try:
            self._keymanager.send_key(openpgp.OpenPGPKey)
        except Exception as exc:
            logger.error("Error while sending key!")
            logger.exception(exc)
            raise

        logger.debug("Key generated successfully.")
Exemple #6
0
    def __init__(self, keymanager, soledad, imap_account,
                 check_period):

        """
        Initialize LeapIMAP.

        :param keymanager: a keymanager instance
        :type keymanager: keymanager.KeyManager

        :param soledad: a soledad instance
        :type soledad: Soledad

        :param imap_account: the account to fetch periodically
        :type imap_account: SoledadBackedAccount

        :param check_period: the period to fetch new mail, in seconds.
        :type check_period: int
        """

        leap_assert(keymanager, "need a keymanager to initialize")
        leap_assert_type(soledad, Soledad)
        leap_assert(check_period, "need a period to check incoming mail")
        leap_assert_type(check_period, int)

        self._keymanager = keymanager
        self._soledad = soledad
        self.imapAccount = imap_account
        self._inbox = self.imapAccount.getMailbox('inbox')

        self._pkey = self._keymanager.get_all_keys_in_local_db(
            private=True).pop()
        self._loop = None
        self._check_period = check_period

        self._create_soledad_indexes()
    def run_eip_setup_checks(self,
                             provider_config,
                             download_if_needed=False):
        """
        Starts the checks needed for a new eip setup

        :param provider_config: Provider configuration
        :type provider_config: ProviderConfig
        """
        leap_assert(provider_config, "We need a provider config!")
        leap_assert_type(provider_config, ProviderConfig)

        self._provider_config = provider_config
        self._download_if_needed = download_if_needed

        eip_config_ready = None
        eip_certificate_ready = None
        if self._signaler is not None:
            eip_config_ready = self._signaler.eip_config_ready
            eip_certificate_ready = self._signaler.eip_client_certificate_ready

        cb_chain = [
            (self._download_config, eip_config_ready),
            (self._download_client_certificates, eip_certificate_ready)
        ]

        return self.addCallbackChain(cb_chain)
Exemple #8
0
    def authenticate(self, username, password):
        """
        Executes the whole authentication process for a user

        Might raise SRPAuthenticationError

        :param username: username for this session
        :type username: unicode
        :param password: password for this user
        :type password: unicode

        :returns: A defer on a different thread
        :rtype: twisted.internet.defer.Deferred
        """
        leap_assert(self.get_session_id() is None, "Already logged in")

        # User credentials stored for password changing checks
        self._username = username
        self._password = password

        self._reset_session()

        d = threads.deferToThread(self._authentication_preprocessing,
                                  username=username,
                                  password=password)
        d.addCallback(partial(self._start_authentication, username=username))

        d.addCallback(partial(self._process_challenge, username=username))
        d.addCallback(self._extract_data)
        d.addCallback(self._verify_session)
        return d
    def get_vpn_command(kls, eipconfig, providerconfig, socket_host,
                        socket_port="9876", openvpn_verb=1):
        """
        Returns the Windows implementation for the vpn launching command.

        Might raise:
            OpenVPNNotFoundException,
            VPNLauncherException.

        :param eipconfig: eip configuration object
        :type eipconfig: EIPConfig
        :param providerconfig: provider specific configuration
        :type providerconfig: ProviderConfig
        :param socket_host: either socket path (unix) or socket IP
        :type socket_host: str
        :param socket_port: either string "unix" if it's a unix socket,
                            or port otherwise
        :type socket_port: str
        :param openvpn_verb: the openvpn verbosity wanted
        :type openvpn_verb: int

        :return: A VPN command ready to be launched.
        :rtype: list
        """
        leap_assert(socket_port != "unix",
                    "We cannot use unix sockets in windows!")

        # we use `super` in order to send the class to use
        command = super(WindowsVPNLauncher, kls).get_vpn_command(
            eipconfig, providerconfig, socket_host, socket_port, openvpn_verb)

        return command
Exemple #10
0
    def authenticate(self, username, password):
        """
        Executes the whole authentication process for a user

        Might raise SRPAuthenticationError

        :param username: username for this session
        :type username: unicode
        :param password: password for this user
        :type password: unicode

        :returns: A defer on a different thread
        :rtype: twisted.internet.defer.Deferred
        """
        leap_assert(self.get_session_id() is None, "Already logged in")

        # User credentials stored for password changing checks
        self._username = username
        self._password = password

        self._reset_session()

        d = threads.deferToThread(self._authentication_preprocessing,
                                  username=username,
                                  password=password)
        d.addCallback(partial(self._start_authentication, username=username))

        d.addCallback(partial(self._process_challenge, username=username))
        d.addCallback(self._extract_data)
        d.addCallback(self._verify_session)
        return d
Exemple #11
0
    def _mail_handle_imap_events_slot(self, req):
        """
        SLOT
        TRIGGER: _mail_handle_imap_events

        Reacts to an IMAP event

        :param req: Request type
        :type req: leap.common.events.events_pb2.SignalRequest
        """
        ext_status = None

        if req.event == proto.IMAP_SERVICE_STARTED:
            ext_status = self.tr("IMAP has started...")
            self._imap_started = True
            if self._smtp_started and self._imap_started:
                self._set_mail_status(self.tr("ON"), ready=True)
                ext_status = ""
        elif req.event == proto.IMAP_SERVICE_FAILED_TO_START:
            ext_status = self.tr("IMAP failed to start, check the logs.")
            self._set_mail_status(self.tr("Failed"))
        elif req.event == proto.IMAP_UNREAD_MAIL:
            if self._smtp_started and self._imap_started:
                self.ui.lblUnread.setText(
                    self.tr("%s Unread Emails") % (req.content))
                self.ui.lblUnread.setVisible(req.content != "0")
                self._set_mail_status(self.tr("ON"), ready=True)
        else:
            leap_assert(False,  # XXX ???
                        "Don't know how to handle this state: %s"
                        % (req.event))

        if ext_status is not None:
            self._set_long_mail_status(ext_status)
Exemple #12
0
    def __init__(self, account_name, soledad, memstore=None):
        """
        Creates a SoledadAccountIndex that keeps track of the mailboxes
        and subscriptions handled by this account.

        :param acct_name: The name of the account (user id).
        :type acct_name: str

        :param soledad: a Soledad instance.
        :type soledad: Soledad
        :param memstore: a MemoryStore instance.
        :type memstore: MemoryStore
        """
        leap_assert(soledad, "Need a soledad instance to initialize")
        leap_assert_type(soledad, Soledad)

        # XXX SHOULD assert too that the name matches the user/uuid with which
        # soledad has been initialized.

        # XXX ??? why is this parsing mailbox name??? it's account...
        # userid? homogenize.
        self._account_name = self._parse_mailbox_name(account_name)
        self._soledad = soledad
        self._memstore = memstore

        self.__mailboxes = set([])

        self.initialize_db()

        # every user should have the right to an inbox folder
        # at least, so let's make one!
        self._load_mailboxes()

        if not self.mailboxes:
            self.addMailbox(self.INBOX_NAME)
def encrypt_sym(data, key, method=EncryptionMethods.AES_256_CTR):
    """
    Encrypt C{data} with C{key}, using C{method} encryption method.

    @param data: The data to be encrypted.
    @type data: str
    @param key: The key used to encrypt C{data} (must be 256 bits long).
    @type key: str
    @param method: The encryption method to use.
    @type method: str

    @return: A tuple with the initial value and the encrypted data.
    @rtype: (long, str)
    """
    leap_assert_type(key, str)

    # AES-256 in CTR mode
    if method == EncryptionMethods.AES_256_CTR:
        leap_assert(
            len(key) == 32,  # 32 x 8 = 256 bits.
            'Wrong key size: %s bits (must be 256 bits long).' %
            (len(key) * 8))
        iv = random.getrandbits(256)
        ctr = Counter.new(128, initial_value=iv)
        cipher = AES.new(key=key, mode=AES.MODE_CTR, counter=ctr)
        return iv, cipher.encrypt(data)

    # raise if method is unknown
    raise UnknownEncryptionMethod('Unkwnown method: %s' % method)
Exemple #14
0
    def run_provider_select_checks(self, domain, download_if_needed=False):
        """
        Populates the check queue.

        :param domain: domain to check
        :type domain: unicode

        :param download_if_needed: if True, makes the checks do not
                                   overwrite already downloaded data
        :type download_if_needed: bool
        """
        leap_assert(domain and len(domain) > 0, "We need a domain!")

        self._domain = ProviderConfig.sanitize_path_component(domain)
        self._download_if_needed = download_if_needed

        name_resolution = None
        https_connection = None
        down_provider_info = None
        if self._signaler is not None:
            name_resolution = self._signaler.prov_name_resolution
            https_connection = self._signaler.prov_https_connection
            down_provider_info = self._signaler.prov_download_provider_info

        cb_chain = [(self._check_name_resolution, name_resolution),
                    (self._check_https, https_connection),
                    (self._download_provider_info, down_provider_info)]

        return self.addCallbackChain(cb_chain)
Exemple #15
0
    def _download_ca_cert(self, *args):
        """
        Downloads the CA cert that is going to be used for the api URL
        """
        # XXX maybe we can skip this step if
        # we have a fresh one.
        leap_assert(
            self._provider_config, "Cannot download the ca cert "
            "without a provider config!")

        logger.debug("Downloading ca cert for %r at %r" %
                     (self._domain, self._provider_config.get_ca_cert_uri()))

        if not self._should_proceed_cert():
            check_and_fix_urw_only(
                self._provider_config.get_ca_cert_path(about_to_download=True))
            return

        res = self._session.get(self._provider_config.get_ca_cert_uri(),
                                verify=self.verify,
                                timeout=REQUEST_TIMEOUT)
        res.raise_for_status()

        cert_path = self._provider_config.get_ca_cert_path(
            about_to_download=True)
        cert_dir = os.path.dirname(cert_path)
        mkdir_p(cert_dir)
        with open(cert_path, "w") as f:
            f.write(res.content)

        check_and_fix_urw_only(cert_path)
Exemple #16
0
    def _put(self, uri, data=None):
        """
        Send a PUT request to C{uri} containing C{data}.

        The request will be sent using the configured CA certificate path to
        verify the server certificate and the configured session id for
        authentication.

        :param uri: The URI of the request.
        :type uri: str
        :param data: The body of the request.
        :type data: dict, str or file

        :return: The response to the request.
        :rtype: requests.Response
        """
        leap_assert(self._ca_cert_path is not None,
                    'We need the CA certificate path!')
        leap_assert(self._token is not None,
                    'We need a token to interact with webapp!')
        res = self._fetcher.put(
            uri,
            data=data,
            verify=self._ca_cert_path,
            headers={'Authorization': 'Token token=%s' % self._token})
        # assert that the response is valid
        res.raise_for_status()
        return res
Exemple #17
0
    def _check_https(self, *args):
        """
        Checks that https is working and that the provided certificate
        checks out
        """
        leap_assert(self._domain, "Cannot check HTTPS without a domain")
        logger.debug("Checking https for %r" % (self._domain))

        # We don't skip this check, since it's basic for the whole
        # system to work.
        # err --- but we can do it after a failure, to diagnose what went
        # wrong. Right now we're just adding connection overhead. -- kali

        verify = self.verify
        if verify:
            verify = self.verify.encode(sys.getfilesystemencoding())

        try:
            uri = "https://{0}".format(self._domain.encode('idna'))
            res = self._session.get(uri,
                                    verify=verify,
                                    timeout=REQUEST_TIMEOUT)
            res.raise_for_status()
        except requests.exceptions.SSLError as exc:
            self._err_msg = self.tr("Provider certificate could "
                                    "not be verified")
            raise
        except Exception as exc:
            # XXX careful!. The error might be also a SSL handshake
            # timeout error, in which case we should retry a couple of times
            # more, for cases where the ssl server gives high latencies.
            self._err_msg = self.tr("Provider does not support HTTPS")
            raise
Exemple #18
0
    def _get(self, uri, data=None):
        """
        Send a GET request to C{uri} containing C{data}.

        :param uri: The URI of the request.
        :type uri: str
        :param data: The body of the request.
        :type data: dict, str or file

        :return: The response to the request.
        :rtype: requests.Response
        """
        leap_assert(self._ca_cert_path is not None,
                    'We need the CA certificate path!')
        res = self._fetcher.get(uri, data=data, verify=self._ca_cert_path)
        # Nickserver now returns 404 for key not found and 500 for
        # other cases (like key too small), so we are skipping this
        # check for the time being
        # res.raise_for_status()

        # Responses are now text/plain, although it's json anyway, but
        # this will fail when it shouldn't
        # leap_assert(
        #     res.headers['content-type'].startswith('application/json'),
        #     'Content-type is not JSON.')
        return res
Exemple #19
0
    def _put(self, uri, data=None):
        """
        Send a PUT request to C{uri} containing C{data}.

        The request will be sent using the configured CA certificate path to
        verify the server certificate and the configured session id for
        authentication.

        :param uri: The URI of the request.
        :type uri: str
        :param data: The body of the request.
        :type data: dict, str or file

        :return: A deferred that will be fired when PUT request finishes
        :rtype: Deferred
        """
        leap_assert(self._token is not None,
                    'We need a token to interact with webapp!')
        if type(data) == dict:
            data = urllib.urlencode(data)
        headers = {'Authorization': [str('Token token=%s' % self._token)]}
        headers['Content-Type'] = ['application/x-www-form-urlencoded']
        try:
            res = yield self._async_client_pinned.request(str(uri),
                                                          'PUT',
                                                          body=str(data),
                                                          headers=headers)
        except Exception as e:
            logger.warning("Error uploading key: %r" % (e, ))
            raise e
        if 'error' in res:
            # FIXME: That's a workaround for 500,
            # we need to implement a readBody to assert response code
            logger.warning("Error uploading key: %r" % (res, ))
            raise Exception(res)
    def _download_client_certificates(self, *args):
        """
        Downloads the EIP client certificate for the given provider
        """
        leap_assert(self._provider_config, "We need a provider configuration!")
        leap_assert(self._eip_config, "We need an eip configuration!")

        logger.debug("Downloading EIP client certificate for %s" %
                     (self._provider_config.get_domain(), ))

        client_cert_path = self._eip_config.\
            get_client_cert_path(self._provider_config,
                                 about_to_download=True)

        # For re-download if something is wrong with the cert
        self._download_if_needed = self._download_if_needed and \
            not leap_certs.should_redownload(client_cert_path)

        if self._download_if_needed and \
                os.path.isfile(client_cert_path):
            check_and_fix_urw_only(client_cert_path)
            return

        download_client_cert(self._provider_config, client_cert_path,
                             self._session)
Exemple #21
0
    def _destroy_keyring(self):
        """
        Securely erase the keyring.
        """
        # TODO: implement some kind of wiping of data or a more
        # secure way that
        # does not write to disk.

        try:
            for secret in [True, False]:
                for key in self._gpg.list_keys(secret=secret):
                    self._gpg.delete_keys(
                        key['fingerprint'],
                        secret=secret)
            leap_assert(len(self._gpg.list_keys()) is 0, 'Keyring not empty!')

        except:
            raise

        finally:
            try:
                homedir = self._gpg.homedir
            except AttributeError:
                homedir = self._gpg.gnupghome
            leap_assert(homedir != os.path.expanduser('~/.gnupg'),
                        "watch out! Tried to remove default gnupg home!")
            # TODO some windows debug ....
            homedir = os.path.normpath(homedir).replace("\\", "/")
            homedir = str(homedir.replace("c:/", "c://"))
            if platform.system() == "Windows":
                self.log.error("BUG! Not erasing folder in Windows")
                return
            shutil.rmtree(homedir)
Exemple #22
0
    def _check_ca_fingerprint(self, *args):
        """
        Checks the CA cert fingerprint against the one provided in the
        json definition
        """
        leap_assert(self._provider_config, "Cannot check the ca cert "
                    "without a provider config!")

        logger.debug("Checking ca fingerprint for %r and cert %r" %
                     (self._domain, self._provider_config.get_ca_cert_path()))

        if not self._should_proceed_cert():
            return

        parts = self._provider_config.get_ca_cert_fingerprint().split(":")

        error_msg = "Wrong fingerprint format"
        leap_check(len(parts) == 2, error_msg, WrongFingerprint)

        method = parts[0].strip()
        fingerprint = parts[1].strip()
        cert_data = None
        with open(self._provider_config.get_ca_cert_path()) as f:
            cert_data = f.read()

        leap_assert(len(cert_data) > 0, "Could not read certificate data")
        digest = get_digest(cert_data, method)

        error_msg = "Downloaded certificate has a different fingerprint!"
        leap_check(digest == fingerprint, error_msg, WrongFingerprint)
Exemple #23
0
    def request(self, url, method='GET', body=None, headers={},
                callback=readBody):
        """
        Perform an HTTP request, but limit the maximum amount of concurrent
        connections.

        May be passed a callback to be added to the request's deferred
        callback chain. The callback is expected to receive the response of
        the request and may do whatever it wants with the response. By
        default, if no callback is passed, we will use a simple body reader
        which returns a deferred that is fired with the body of the response.

        :param url: The URL for the request.
        :type url: str
        :param method: The HTTP method of the request.
        :type method: str
        :param body: The body of the request, if any.
        :type body: str
        :param headers: The headers of the request.
        :type headers: dict
        :param callback: A callback to be added to the request's deferred
                         callback chain.
        :type callback: callable

        :return: A deferred that fires with the body of the request.
        :rtype: twisted.internet.defer.Deferred
        """
        leap_assert(
            callable(callback),
            message="The callback parameter should be a callable!")
        return self._semaphore.run(self._request, url, method, body, headers,
                                   callback)
Exemple #24
0
    def run_provider_setup_checks(self,
                                  provider_config,
                                  download_if_needed=False):
        """
        Starts the checks needed for a new provider setup.

        :param provider_config: Provider configuration
        :type provider_config: ProviderConfig

        :param download_if_needed: if True, makes the checks do not
                                   overwrite already downloaded data.
        :type download_if_needed: bool
        """
        leap_assert(provider_config, "We need a provider config!")
        leap_assert_type(provider_config, ProviderConfig)

        self._provider_config = provider_config
        self._download_if_needed = download_if_needed

        download_ca_cert = None
        check_ca_fingerprint = None
        check_api_certificate = None
        if self._signaler is not None:
            download_ca_cert = self._signaler.prov_download_ca_cert
            check_ca_fingerprint = self._signaler.prov_check_ca_fingerprint
            check_api_certificate = self._signaler.prov_check_api_certificate

        cb_chain = [(self._download_ca_cert, download_ca_cert),
                    (self._check_ca_fingerprint, check_ca_fingerprint),
                    (self._check_api_certificate, check_api_certificate)]

        return self.addCallbackChain(cb_chain)
Exemple #25
0
    def _init_indexes(self, store):
        """
        Initialize the database indexes.
        """
        leap_assert(store, "Cannot init indexes with null soledad")
        leap_assert_type(self.indexes, dict)

        def _create_index(name, expression):
            return store.create_index(name, *expression)

        def init_idexes(indexes):
            deferreds = []
            db_indexes = dict(indexes)
            # Loop through the indexes we expect to find.
            for name, expression in self.indexes.items():
                if name not in db_indexes:
                    # The index does not yet exist.
                    d = _create_index(name, expression)
                    deferreds.append(d)
                elif expression != db_indexes[name]:
                    # The index exists but the definition is not what expected,
                    # so we delete it and add the proper index expression.
                    d = store.delete_index(name)
                    d.addCallback(lambda _: _create_index(name, *expression))
                    deferreds.append(d)
            return defer.gatherResults(deferreds, consumeErrors=True)

        def store_ready(whatever):
            self.store_ready = True
            return whatever

        self.deferred_indexes = store.list_indexes()
        self.deferred_indexes.addCallback(init_idexes)
        self.deferred_indexes.addCallback(store_ready)
        return self.deferred_indexes
Exemple #26
0
    def _init_indexes(self):
        """
        Initialize the database indexes.
        """
        leap_assert(self._soledad is not None,
                    "Cannot init indexes with null soledad")

        def init_idexes(indexes):
            deferreds = []
            db_indexes = dict(indexes)
            # Loop through the indexes we expect to find.
            for name, expression in INDEXES.items():
                if name not in db_indexes:
                    # The index does not yet exist.
                    d = self._soledad.create_index(name, *expression)
                    deferreds.append(d)
                elif expression != db_indexes[name]:
                    # The index exists but the definition is not what expected,
                    # so we delete it and add the proper index expression.
                    d = self._soledad.delete_index(name)
                    d.addCallback(lambda _: self._soledad.create_index(
                        name, *expression))
                    deferreds.append(d)
            return defer.gatherResults(deferreds, consumeErrors=True)

        self.deferred_indexes = self._soledad.list_indexes()
        self.deferred_indexes.addCallback(init_idexes)
    def _download_client_certificates(self, *args):
        """
        Downloads the EIP client certificate for the given provider
        """
        leap_assert(self._provider_config, "We need a provider configuration!")
        leap_assert(self._eip_config, "We need an eip configuration!")

        logger.debug("Downloading EIP client certificate for %s" %
                     (self._provider_config.get_domain(),))

        client_cert_path = self._eip_config.\
            get_client_cert_path(self._provider_config,
                                 about_to_download=True)

        # For re-download if something is wrong with the cert
        self._download_if_needed = self._download_if_needed and \
            not leap_certs.should_redownload(client_cert_path)

        if self._download_if_needed and \
                os.path.isfile(client_cert_path):
            check_and_fix_urw_only(client_cert_path)
            return

        download_client_cert(
            self._provider_config,
            client_cert_path,
            self._session)
Exemple #28
0
    def send_key(self, ktype):
        """
        Send user's key of type C{ktype} to provider.

        Public key bound to user's is sent to provider, which will sign it and
        replace any prior keys for the same address in its database.

        If C{send_private} is True, then the private key is encrypted with
        C{password} and sent to server in the same request, together with a
        hash string of user's address and password. The encrypted private key
        will be saved in the server in a way it is publicly retrievable
        through the hash string.

        :param ktype: The type of the key.
        :type ktype: KeyType

        @raise KeyNotFound: If the key was not found in local database.
        """
        leap_assert(
            ktype is OpenPGPKey,
            'For now we only know how to send OpenPGP public keys.')
        # prepare the public key bound to address
        pubkey = self.get_key(
            self._address, ktype, private=False, fetch_remote=False)
        data = {
            self.PUBKEY_KEY: pubkey.key_data
        }
        uri = "%s/%s/users/%s.json" % (
            self._api_uri,
            self._api_version,
            self._uid)
        self._put(uri, data)
        signal(proto.KEYMANAGER_DONE_UPLOADING_KEYS, self._address)
    def _mail_handle_keymanager_events_slot(self, req):
        """
        TRIGGERS:
            _mail_handle_keymanager_events

        Reacts to an KeyManager event

        :param req: Request type
        :type req: leap.common.events.events_pb2.SignalRequest
        """
        # We want to ignore this kind of events once everything has
        # started
        if self._started:
            return

        ext_status = ""

        if req.event == proto.KEYMANAGER_LOOKING_FOR_KEY:
            ext_status = self.tr("Initial sync in progress, please wait...")
        elif req.event == proto.KEYMANAGER_KEY_FOUND:
            ext_status = self.tr("Found key! Starting mail...")
        # elif req.event == proto.KEYMANAGER_KEY_NOT_FOUND:
        #     ext_status = self.tr("Key not found!")
        elif req.event == proto.KEYMANAGER_STARTED_KEY_GENERATION:
            ext_status = self.tr(
                "Generating new key, this may take a few minutes.")
        elif req.event == proto.KEYMANAGER_FINISHED_KEY_GENERATION:
            ext_status = self.tr("Finished generating key!")
        elif req.event == proto.KEYMANAGER_DONE_UPLOADING_KEYS:
            ext_status = self.tr("Starting mail...")
        else:
            leap_assert(
                False, "Don't know how to handle this state: %s" % (req.event))

        self._set_mail_status(ext_status, ready=1)
    def __init__(self, handler):
        """
        Initialize the widget with the custom handler.

        :param handler: Custom handler that supports history and signal.
        :type handler: LeapLogHandler.
        """
        QtGui.QDialog.__init__(self)
        leap_assert(handler, "We need a handler for the logger window")
        leap_assert_type(handler, LeapLogHandler)

        # Load UI
        self.ui = Ui_LoggerWindow()
        self.ui.setupUi(self)

        # Make connections
        self.ui.btnSave.clicked.connect(self._save_log_to_file)
        self.ui.btnDebug.toggled.connect(self._load_history),
        self.ui.btnInfo.toggled.connect(self._load_history),
        self.ui.btnWarning.toggled.connect(self._load_history),
        self.ui.btnError.toggled.connect(self._load_history),
        self.ui.btnCritical.toggled.connect(self._load_history)
        self.ui.leFilterBy.textEdited.connect(self._filter_by)
        self.ui.cbCaseInsensitive.stateChanged.connect(self._load_history)

        self._current_filter = ""

        # Load logging history and connect logger with the widget
        self._logging_handler = handler
        self._connect_to_handler()
        self._load_history()
 def name(self):
     """
     Getter for the service name.
     Derived classes should assign it.
     """
     leap_assert(self._service_name is not None)
     return self._service_name
Exemple #32
0
    def __init__(self, account_name, soledad=None):
        """
        Creates a SoledadAccountIndex that keeps track of the mailboxes
        and subscriptions handled by this account.

        :param acct_name: The name of the account (user id).
        :type acct_name: str

        :param soledad: a Soledad instance.
        :param soledad: Soledad
        """
        leap_assert(soledad, "Need a soledad instance to initialize")
        leap_assert_type(soledad, Soledad)

        # XXX SHOULD assert too that the name matches the user/uuid with which
        # soledad has been initialized.

        self._account_name = account_name.upper()
        self._soledad = soledad

        self.initialize_db()

        # every user should have the right to an inbox folder
        # at least, so let's make one!

        if not self.mailboxes:
            self.addMailbox(self.INBOX_NAME)
Exemple #33
0
def decrypt_sym(data, key, method=EncryptionMethods.AES_256_CTR, **kwargs):
    """
    Decrypt C{data} with C{key} using C{method} encryption method.

    :param data: The data to be decrypted.
    :type data: str
    :param key: The key used to decrypt C{data} (must be 256 bits long).
    :type key: str
    :param method: The encryption method to use.
    :type method: str
    :param kwargs: Other parameters specific to each encryption method.
    :type kwargs: dict

    :return: The decrypted data.
    :rtype: str
    """
    leap_assert_type(key, str)

    # AES-256 in CTR mode
    if method == EncryptionMethods.AES_256_CTR:
        # assert params
        leap_assert(
            len(key) == 32,  # 32 x 8 = 256 bits.
            'Wrong key size: %s (must be 256 bits long).' % len(key))
        leap_assert('iv' in kwargs,
                    'AES-256-CTR needs an initial value given as.')
        ctr = Counter.new(64, prefix=binascii.a2b_base64(kwargs['iv']))
        cipher = AES.new(key=key, mode=AES.MODE_CTR, counter=ctr)
        return cipher.decrypt(data)

    # raise if method is unknown
    raise UnknownEncryptionMethod('Unkwnown method: %s' % method)
Exemple #34
0
    def maybe_pkexec(self):
        """
        Checks whether pkexec is available in the system, and
        returns the path if found.

        Might raise:
            NoPkexecAvailable,
            NoPolkitAuthAgentAvailable.

        :returns: a list of the paths where pkexec is to be found
        :rtype: list
        """
        if self._is_pkexec_in_system():
            if not self.is_up():
                self.launch()
                time.sleep(2)
            if self.is_up():
                pkexec_possibilities = which(self.PKEXEC_BIN)
                leap_assert(
                    len(pkexec_possibilities) > 0, "We couldn't find pkexec")
                return pkexec_possibilities
            else:
                logger.warning("No polkit auth agent found. pkexec " +
                               "will use its own auth agent.")
                raise NoPolkitAuthAgentAvailable()
        else:
            logger.warning("System has no pkexec")
            raise NoPkexecAvailable()
Exemple #35
0
    def __init__(self, user_id, store, d=defer.Deferred()):
        """
        Keeps track of the mailboxes and subscriptions handled by this account.

        The account is not ready to be used, since the store needs to be
        initialized and we also need to do some initialization routines.
        You can either pass a deferred to this constructor, or use
        `callWhenReady` method.

        :param user_id: The name of the account (user id, in the form
                        user@provider).
        :type user_id: str

        :param store: a Soledad instance.
        :type store: Soledad

        :param d: a deferred that will be fired with this IMAPAccount instance
                  when the account is ready to be used.
        :type d: defer.Deferred
        """
        leap_assert(store, "Need a store instance to initialize")
        leap_assert_type(store, Soledad)

        # TODO assert too that the name matches the user/uuid with which
        # soledad has been initialized. Although afaik soledad doesn't know
        # about user_id, only the client backend.

        self.user_id = user_id
        self.account = Account(store, ready_cb=lambda: d.callback(self))
Exemple #36
0
    def __init__(self, store, user_id, d=defer.Deferred()):
        """
        Keeps track of the mailboxes and subscriptions handled by this account.

        The account is not ready to be used, since the store needs to be
        initialized and we also need to do some initialization routines.
        You can either pass a deferred to this constructor, or use
        `callWhenReady` method.

        :param store: a Soledad instance.
        :type store: Soledad

        :param user_id: The identifier of the user this account belongs to
                        (user id, in the form user@provider).
        :type user_id: str


        :param d: a deferred that will be fired with this IMAPAccount instance
                  when the account is ready to be used.
        :type d: defer.Deferred
        """
        leap_assert(store, "Need a store instance to initialize")
        leap_assert_type(store, Soledad)

        # TODO assert too that the name matches the user/uuid with which
        # soledad has been initialized. Although afaik soledad doesn't know
        # about user_id, only the client backend.

        self.user_id = user_id
        self.account = Account(store, user_id, ready_cb=lambda: d.callback(self))
    def maybe_pkexec(self):
        """
        Checks whether pkexec is available in the system, and
        returns the path if found.

        Might raise:
            NoPkexecAvailable,
            NoPolkitAuthAgentAvailable.

        :returns: a list of the paths where pkexec is to be found
        :rtype: list
        """
        if self._is_pkexec_in_system():
            if not self.is_up():
                self.launch()
                time.sleep(2)
            if self.is_up():
                pkexec_possibilities = which(self.PKEXEC_BIN)
                leap_assert(len(pkexec_possibilities) > 0,
                            "We couldn't find pkexec")
                return pkexec_possibilities
            else:
                logger.warning("No polkit auth agent found. pkexec " +
                               "will use its own auth agent.")
                raise NoPolkitAuthAgentAvailable()
        else:
            logger.warning("System has no pkexec")
            raise NoPkexecAvailable()
Exemple #38
0
    def __init__(self, account_name, soledad, memstore=None):
        """
        Creates a SoledadAccountIndex that keeps track of the mailboxes
        and subscriptions handled by this account.

        :param acct_name: The name of the account (user id).
        :type acct_name: str

        :param soledad: a Soledad instance.
        :type soledad: Soledad
        :param memstore: a MemoryStore instance.
        :type memstore: MemoryStore
        """
        leap_assert(soledad, "Need a soledad instance to initialize")
        leap_assert_type(soledad, Soledad)

        # XXX SHOULD assert too that the name matches the user/uuid with which
        # soledad has been initialized.

        # XXX ??? why is this parsing mailbox name??? it's account...
        # userid? homogenize.
        self._account_name = self._parse_mailbox_name(account_name)
        self._soledad = soledad
        self._memstore = memstore

        self.__mailboxes = set([])

        self.initialize_db()

        # every user should have the right to an inbox folder
        # at least, so let's make one!
        self._load_mailboxes()

        if not self.mailboxes:
            self.addMailbox(self.INBOX_NAME)
Exemple #39
0
    def _get_key_doc(self, address, private=False):
        """
        Get the document with a key (public, by default) bound to C{address}.

        If C{private} is True, looks for a private key instead of a public.

        :param address: The address bound to the key.
        :type address: str
        :param private: Whether to look for a private key.
        :type private: bool
        :return: The document with the key or None if it does not exist.
        :rtype: leap.soledad.document.SoledadDocument
        """
        doclist = self._soledad.get_from_index(
            TAGS_ADDRESS_PRIVATE_INDEX,
            KEYMANAGER_KEY_TAG,
            address,
            '1' if private else '0')
        if len(doclist) is 0:
            return None
        leap_assert(
            len(doclist) is 1,
            'Found more than one %s key for address!' %
            'private' if private else 'public')
        return doclist.pop()
    def maybe_pkexec(kls):
        """
        Checks whether pkexec is available in the system, and
        returns the path if found.

        Might raise:
            EIPNoPkexecAvailable,
            EIPNoPolkitAuthAgentAvailable.

        :returns: a list of the paths where pkexec is to be found
        :rtype: list
        """
        if _is_pkexec_in_system():
            if not _is_auth_agent_running():
                _try_to_launch_agent()
                time.sleep(0.5)
            if _is_auth_agent_running():
                pkexec_possibilities = which(kls.PKEXEC_BIN)
                leap_assert(len(pkexec_possibilities) > 0,
                            "We couldn't find pkexec")
                return pkexec_possibilities
            else:
                logger.warning("No polkit auth agent found. pkexec " +
                               "will use its own auth agent.")
                raise EIPNoPolkitAuthAgentAvailable()
        else:
            logger.warning("System has no pkexec")
            raise EIPNoPkexecAvailable()
Exemple #41
0
def encrypt_asym(data, key, passphrase=None, sign=None):
    """
    Encrypt C{data} using public @{key} and sign with C{sign} key.

    :param data: The data to be encrypted.
    :type data: str
    :param pubkey: The key used to encrypt.
    :type pubkey: OpenPGPKey
    :param sign: The key used for signing.
    :type sign: OpenPGPKey

    :return: The encrypted data.
    :rtype: str
    """
    leap_assert_type(key, OpenPGPKey)
    leap_assert(key.private is False, 'Key is not public.')
    if sign is not None:
        leap_assert_type(sign, OpenPGPKey)
        leap_assert(sign.private is True)

    # Here we cannot assert for correctness of sig because the sig is in
    # the ciphertext.
    # result.ok    - (bool) indicates if the operation succeeded
    # result.data  - (bool) contains the result of the operation

    return lambda gpg: gpg.encrypt(
        data, key.fingerprint,
        sign=sign.key_id if sign else None,
        passphrase=passphrase, symmetric=False)
Exemple #42
0
    def initialize_db(self):
        """
        Initialize the database.
        """
        leap_assert(self._soledad,
                    "Need a soledad attribute accesible in the instance")
        leap_assert_type(self.INDEXES, dict)

        # Ask the database for currently existing indexes.
        if not self._soledad:
            logger.debug("NO SOLEDAD ON IMAP INITIALIZATION")
            return
        db_indexes = dict()
        if self._soledad is not None:
            db_indexes = dict(self._soledad.list_indexes())
        for name, expression in fields.INDEXES.items():
            if name not in db_indexes:
                # The index does not yet exist.
                self._soledad.create_index(name, *expression)
                continue

            if expression == db_indexes[name]:
                # The index exists and is up to date.
                continue
            # The index exists but the definition is not what expected, so we
            # delete it and add the proper index expression.
            self._soledad.delete_index(name)
            self._soledad.create_index(name, *expression)
Exemple #43
0
    def _put(self, uri, data=None):
        """
        Send a PUT request to C{uri} containing C{data}.

        The request will be sent using the configured CA certificate path to
        verify the server certificate and the configured session id for
        authentication.

        :param uri: The URI of the request.
        :type uri: str
        :param data: The body of the request.
        :type data: dict, str or file

        :return: The response to the request.
        :rtype: requests.Response
        """
        leap_assert(
            self._ca_cert_path is not None,
            'We need the CA certificate path!')
        leap_assert(
            self._session_id is not None,
            'We need a session_id to interact with webapp!')
        res = self._fetcher.put(
            uri, data=data, verify=self._ca_cert_path,
            cookies={'_session_id': self._session_id})
        # assert that the response is valid
        res.raise_for_status()
        return res
    def run_provider_setup_checks(self,
                                  provider_config,
                                  download_if_needed=False):
        """
        Starts the checks needed for a new provider setup.

        :param provider_config: Provider configuration
        :type provider_config: ProviderConfig

        :param download_if_needed: if True, makes the checks do not
                                   overwrite already downloaded data.
        :type download_if_needed: bool
        """
        leap_assert(provider_config, "We need a provider config!")
        leap_assert_type(provider_config, ProviderConfig)

        self._provider_config = provider_config
        self._download_if_needed = download_if_needed

        cb_chain = [
            (self._download_ca_cert, self._signaler.prov_download_ca_cert),
            (self._check_ca_fingerprint,
             self._signaler.prov_check_ca_fingerprint),
            (self._check_api_certificate,
             self._signaler.prov_check_api_certificate)
        ]

        return self.addCallbackChain(cb_chain)
Exemple #45
0
def build_key_from_dict(kClass, address, kdict):
    """
    Build an C{kClass} key bound to C{address} based on info in C{kdict}.

    :param address: The address bound to the key.
    :type address: str
    :param kdict: Dictionary with key data.
    :type kdict: dict
    :return: An instance of the key.
    :rtype: C{kClass}
    """
    leap_assert(
        address == kdict[KEY_ADDRESS_KEY],
        'Wrong address in key data.')
    return kClass(
        address,
        key_id=kdict[KEY_ID_KEY],
        fingerprint=kdict[KEY_FINGERPRINT_KEY],
        key_data=kdict[KEY_DATA_KEY],
        private=kdict[KEY_PRIVATE_KEY],
        length=kdict[KEY_LENGTH_KEY],
        expiry_date=kdict[KEY_EXPIRY_DATE_KEY],
        first_seen_at=kdict[KEY_FIRST_SEEN_AT_KEY],
        last_audited_at=kdict[KEY_LAST_AUDITED_AT_KEY],
        validation=kdict[KEY_VALIDATION_KEY],  # TODO: verify for validation.
    )
Exemple #46
0
    def addMailbox(self, name, creation_ts=None):
        """
        Add a mailbox to the account.

        :param name: the name of the mailbox
        :type name: str

        :param creation_ts: an optional creation timestamp to be used as
                            mailbox id. A timestamp will be used if no
                            one is provided.
        :type creation_ts: int

        :returns: a Deferred that will contain the document if successful.
        :rtype: defer.Deferred
        """
        name = normalize_mailbox(name)

        # FIXME --- return failure instead of AssertionError
        # See AccountTestCase...
        leap_assert(name, "Need a mailbox name to create a mailbox")

        def check_it_does_not_exist(mailboxes):
            if name in mailboxes:
                raise imap4.MailboxCollision, repr(name)
            return mailboxes

        d = self.account.list_all_mailbox_names()
        d.addCallback(check_it_does_not_exist)
        d.addCallback(lambda _: self.account.add_mailbox(
            name, creation_ts=creation_ts))
        d.addCallback(lambda _: self.account.get_collection_by_mailbox(name))
        d.addCallback(self._return_mailbox_from_collection)
        return d
 def name(self):
     """
     Name of the connection
     """
     con_name = self._connection_name
     leap_assert(con_name is not None)
     return con_name
Exemple #48
0
    def addMailbox(self, name, creation_ts=None):
        """
        Add a mailbox to the account.

        :param name: the name of the mailbox
        :type name: str

        :param creation_ts: an optional creation timestamp to be used as
                            mailbox id. A timestamp will be used if no
                            one is provided.
        :type creation_ts: int

        :returns: a Deferred that will contain the document if successful.
        :rtype: defer.Deferred
        """
        name = normalize_mailbox(name)

        # FIXME --- return failure instead of AssertionError
        # See AccountTestCase...
        leap_assert(name, "Need a mailbox name to create a mailbox")

        def check_it_does_not_exist(mailboxes):
            if name in mailboxes:
                raise imap4.MailboxCollision, repr(name)
            return mailboxes

        d = self.account.list_all_mailbox_names()
        d.addCallback(check_it_does_not_exist)
        d.addCallback(lambda _: self.account.add_mailbox(
            name, creation_ts=creation_ts))
        d.addCallback(lambda _: self.account.get_collection_by_mailbox(name))
        d.addCallback(self._return_mailbox_from_collection)
        return d
Exemple #49
0
    def _init_indexes(self):
        """
        Initialize the database indexes.
        """
        leap_assert(self._soledad is not None, "Cannot init indexes with null soledad")

        def init_idexes(indexes):
            deferreds = []
            db_indexes = dict(indexes)
            # Loop through the indexes we expect to find.
            for name, expression in INDEXES.items():
                if name not in db_indexes:
                    # The index does not yet exist.
                    d = self._soledad.create_index(name, *expression)
                    deferreds.append(d)
                elif expression != db_indexes[name]:
                    # The index exists but the definition is not what expected,
                    # so we delete it and add the proper index expression.
                    d = self._soledad.delete_index(name)
                    d.addCallback(lambda _: self._soledad.create_index(name, *expression))
                    deferreds.append(d)
            return defer.gatherResults(deferreds, consumeErrors=True)

        self.deferred_indexes = self._soledad.list_indexes()
        self.deferred_indexes.addCallback(init_idexes)
Exemple #50
0
def encrypt_sym(data, key, method=EncryptionMethods.AES_256_CTR):
    """
    Encrypt C{data} with C{key}, using C{method} encryption method.

    :param data: The data to be encrypted.
    :type data: str
    :param key: The key used to encrypt C{data} (must be 256 bits long).
    :type key: str
    :param method: The encryption method to use.
    :type method: str

    :return: A tuple with the initial value and the encrypted data.
    :rtype: (long, str)
    """
    leap_assert_type(key, str)

    # AES-256 in CTR mode
    if method == EncryptionMethods.AES_256_CTR:
        leap_assert(
            len(key) == 32,  # 32 x 8 = 256 bits.
            'Wrong key size: %s bits (must be 256 bits long).' %
            (len(key) * 8))
        iv = os.urandom(8)
        ctr = Counter.new(64, prefix=iv)
        cipher = AES.new(key=key, mode=AES.MODE_CTR, counter=ctr)
        return binascii.b2a_base64(iv), cipher.encrypt(data)

    # raise if method is unknown
    raise UnknownEncryptionMethod('Unkwnown method: %s' % method)
    def _check_https(self, *args):
        """
        Checks that https is working and that the provided certificate
        checks out
        """
        leap_assert(self._domain, "Cannot check HTTPS without a domain")
        logger.debug("Checking https for %r" % (self._domain))

        # We don't skip this check, since it's basic for the whole
        # system to work.
        # err --- but we can do it after a failure, to diagnose what went
        # wrong. Right now we're just adding connection overhead. -- kali

        verify = self.verify
        if verify:
            verify = self.verify.encode(sys.getfilesystemencoding())

        try:
            uri = "https://{0}".format(self._domain.encode('idna'))
            res = self._session.get(uri, verify=verify,
                                    timeout=REQUEST_TIMEOUT)
            res.raise_for_status()
        except requests.exceptions.SSLError as exc:
            logger.exception(exc)
            self._err_msg = self.tr("Provider certificate could "
                                    "not be verified")
            raise
        except Exception as exc:
            # XXX careful!. The error might be also a SSL handshake
            # timeout error, in which case we should retry a couple of times
            # more, for cases where the ssl server gives high latencies.
            logger.exception(exc)
            self._err_msg = self.tr("Provider does not support HTTPS")
            raise
Exemple #52
0
 def name(self):
     """
     Name of the connection
     """
     con_name = self._connection_name
     leap_assert(con_name is not None)
     return con_name
    def run_provider_select_checks(self, domain, download_if_needed=False):
        """
        Populates the check queue.

        :param domain: domain to check
        :type domain: unicode

        :param download_if_needed: if True, makes the checks do not
                                   overwrite already downloaded data
        :type download_if_needed: bool
        """
        leap_assert(domain and len(domain) > 0, "We need a domain!")

        self._domain = ProviderConfig.sanitize_path_component(domain)
        self._download_if_needed = download_if_needed

        cb_chain = [
            (self._check_name_resolution,
             self._signaler.prov_name_resolution),
            (self._check_https, self._signaler.prov_https_connection),
            (self._download_provider_info,
             self._signaler.prov_download_provider_info)
        ]

        return self.addCallbackChain(cb_chain)
    def _download_config(self, *args):
        """
        Downloads the SMTP config for the given provider
        """

        leap_assert(self._provider_config,
                    "We need a provider configuration!")

        logger.debug("Downloading SMTP config for %s" %
                     (self._provider_config.get_domain(),))

        headers = {}
        mtime = get_mtime(os.path.join(self._smtp_config
                                       .get_path_prefix(),
                                       "leap",
                                       "providers",
                                       self._provider_config.get_domain(),
                                       "smtp-service.json"))

        if self._download_if_needed and mtime:
            headers['if-modified-since'] = mtime

        api_version = self._provider_config.get_api_version()

        # there is some confusion with this uri,
        config_uri = "%s/%s/config/smtp-service.json" % (
            self._provider_config.get_api_uri(), api_version)

        logger.debug('Downloading SMTP config from: %s' % config_uri)

        srp_auth = SRPAuth(self._provider_config)
        session_id = srp_auth.get_session_id()
        cookies = None
        if session_id:
            cookies = {"_session_id": session_id}

        res = self._session.get(config_uri,
                                verify=self._provider_config
                                .get_ca_cert_path(),
                                headers=headers,
                                cookies=cookies)
        res.raise_for_status()

        self._smtp_config.set_api_version(api_version)

        # Not modified
        if res.status_code == 304:
            logger.debug("SMTP definition has not been modified")
            self._smtp_config.load(os.path.join(
                "leap", "providers",
                self._provider_config.get_domain(),
                "smtp-service.json"))
        else:
            smtp_definition, mtime = get_content(res)

            self._smtp_config.load(data=smtp_definition, mtime=mtime)
            self._smtp_config.save(["leap",
                                    "providers",
                                    self._provider_config.get_domain(),
                                    "smtp-service.json"])
    def _download_ca_cert(self, *args):
        """
        Downloads the CA cert that is going to be used for the api URL
        """
        # XXX maybe we can skip this step if
        # we have a fresh one.
        leap_assert(self._provider_config, "Cannot download the ca cert "
                    "without a provider config!")

        logger.debug("Downloading ca cert for %r at %r" %
                     (self._domain, self._provider_config.get_ca_cert_uri()))

        if not self._should_proceed_cert():
            check_and_fix_urw_only(
                self._provider_config
                .get_ca_cert_path(about_to_download=True))
            return

        res = self._session.get(self._provider_config.get_ca_cert_uri(),
                                verify=self.verify,
                                timeout=REQUEST_TIMEOUT)
        res.raise_for_status()

        cert_path = self._provider_config.get_ca_cert_path(
            about_to_download=True)
        cert_dir = os.path.dirname(cert_path)
        mkdir_p(cert_dir)
        with open(cert_path, "w") as f:
            f.write(res.content)

        check_and_fix_urw_only(cert_path)
Exemple #56
0
    def initialize_db(self):
        """
        Initialize the database.
        """
        leap_assert(self._soledad,
                    "Need a soledad attribute accesible in the instance")
        leap_assert_type(self.INDEXES, dict)

        # Ask the database for currently existing indexes.
        if not self._soledad:
            logger.debug("NO SOLEDAD ON IMAP INITIALIZATION")
            return
        db_indexes = dict()
        if self._soledad is not None:
            db_indexes = dict(self._soledad.list_indexes())
        for name, expression in SoledadBackedAccount.INDEXES.items():
            if name not in db_indexes:
                # The index does not yet exist.
                self._soledad.create_index(name, *expression)
                continue

            if expression == db_indexes[name]:
                # The index exists and is up to date.
                continue
            # The index exists but the definition is not what expected, so we
            # delete it and add the proper index expression.
            self._soledad.delete_index(name)
            self._soledad.create_index(name, *expression)
    def _check_ca_fingerprint(self, *args):
        """
        Checks the CA cert fingerprint against the one provided in the
        json definition
        """
        leap_assert(self._provider_config, "Cannot check the ca cert "
                    "without a provider config!")

        logger.debug("Checking ca fingerprint for %r and cert %r" %
                     (self._domain,
                      self._provider_config.get_ca_cert_path()))

        if not self._should_proceed_cert():
            return

        parts = self._provider_config.get_ca_cert_fingerprint().split(":")

        error_msg = "Wrong fingerprint format"
        leap_check(len(parts) == 2, error_msg, WrongFingerprint)

        method = parts[0].strip()
        fingerprint = parts[1].strip()
        cert_data = None
        with open(self._provider_config.get_ca_cert_path()) as f:
            cert_data = f.read()

        leap_assert(len(cert_data) > 0, "Could not read certificate data")
        digest = get_digest(cert_data, method)

        error_msg = "Downloaded certificate has a different fingerprint!"
        leap_check(digest == fingerprint, error_msg, WrongFingerprint)
 def srpauth(self):
     if flags.OFFLINE is True:
         return None
     if self._srpauth is None:
         leap_assert(self._provider_config is not None,
                     "We need a provider config")
         self._srpauth = SRPAuth(self._provider_config)
     return self._srpauth
Exemple #59
0
 def build_key(doc):
     if doc is None:
         raise errors.KeyNotFound(address)
     leap_assert(address in doc.content[KEY_ADDRESS_KEY],
                 'Wrong address in key data.')
     key = build_key_from_dict(OpenPGPKey, doc.content)
     key._gpgbinary = self._gpgbinary
     return key