diff options
| author | drebs <drebs@leap.se> | 2013-06-17 17:32:32 -0300 | 
|---|---|---|
| committer | drebs <drebs@leap.se> | 2013-07-22 14:46:35 -0300 | 
| commit | ee6a3fe8b310ea5fed1e7bf625a84e9d663d35bc (patch) | |
| tree | 152ea1d74302cf0d8f04251bdfab0f6279164238 /src | |
| parent | bb081d2fb5f578411c1f29cda588bbcdab0ddc6b (diff) | |
Adapt IMAP to latest Soledad api.
* Also fix some tests that where not up-to-date with code.
Diffstat (limited to 'src')
| -rw-r--r-- | src/leap/mail/imap/fetch.py | 4 | ||||
| -rw-r--r-- | src/leap/mail/imap/server.py | 83 | ||||
| -rw-r--r-- | src/leap/mail/imap/tests/__init__.py | 81 | ||||
| -rw-r--r-- | src/leap/mail/imap/tests/test_imap.py | 79 | 
4 files changed, 155 insertions, 92 deletions
| diff --git a/src/leap/mail/imap/fetch.py b/src/leap/mail/imap/fetch.py index df5d046..48a45e6 100644 --- a/src/leap/mail/imap/fetch.py +++ b/src/leap/mail/imap/fetch.py @@ -104,8 +104,8 @@ class LeapIncomingMail(object):          """          Process a successfully decrypted message. -        :param doc: a LeapDocument instance containing the incoming message -        :type doc: LeapDocument +        :param doc: a SoledadDocument instance containing the incoming message +        :type doc: SoledadDocument          :param data: the json-encoded, decrypted content of the incoming                       message diff --git a/src/leap/mail/imap/server.py b/src/leap/mail/imap/server.py index 2b66ba6..813d850 100644 --- a/src/leap/mail/imap/server.py +++ b/src/leap/mail/imap/server.py @@ -37,7 +37,7 @@ from twisted.python import log  from leap.common.check import leap_assert, leap_assert_type  from leap.soledad import Soledad -from leap.soledad.backends.sqlcipher import SQLCipherDatabase +from leap.soledad.sqlcipher import SQLCipherDatabase  logger = logging.getLogger(__name__) @@ -81,7 +81,7 @@ class WithMsgFields(object):      INBOX_VAL = "inbox" -    # Flags for LeapDocument for indexing. +    # Flags for SoledadDocument for indexing.      SEEN_KEY = "seen"      RECENT_KEY = "recent" @@ -233,7 +233,7 @@ class SoledadBackedAccount(WithMsgFields, IndexedDB):          :param name: the name of the mailbox          :type name: str -        :rtype: LeapDocument +        :rtype: SoledadDocument          """          name = name.upper()          doc = self._soledad.get_from_index( @@ -580,9 +580,9 @@ class LeapMessage(WithMsgFields):          """          Initializes a LeapMessage. -        :param doc: A LeapDocument containing the internal +        :param doc: A SoledadDocument containing the internal                      representation of the message -        :type doc: LeapDocument +        :type doc: SoledadDocument          """          self._doc = doc @@ -620,13 +620,13 @@ class LeapMessage(WithMsgFields):          """          Sets the flags for this message -        Returns a LeapDocument that needs to be updated by the caller. +        Returns a SoledadDocument that needs to be updated by the caller.          :param flags: the flags to update in the message.          :type flags: sequence of str -        :return: a LeapDocument instance -        :rtype: LeapDocument +        :return: a SoledadDocument instance +        :rtype: SoledadDocument          """          log.msg('setting flags')          doc = self._doc @@ -639,13 +639,13 @@ class LeapMessage(WithMsgFields):          """          Adds flags to this message. -        Returns a LeapDocument that needs to be updated by the caller. +        Returns a SoledadDocument that needs to be updated by the caller.          :param flags: the flags to add to the message.          :type flags: sequence of str -        :return: a LeapDocument instance -        :rtype: LeapDocument +        :return: a SoledadDocument instance +        :rtype: SoledadDocument          """          oldflags = self.getFlags()          return self.setFlags(list(set(flags + oldflags))) @@ -654,13 +654,13 @@ class LeapMessage(WithMsgFields):          """          Remove flags from this message. -        Returns a LeapDocument that needs to be updated by the caller. +        Returns a SoledadDocument that needs to be updated by the caller.          :param flags: the flags to be removed from the message.          :type flags: sequence of str -        :return: a LeapDocument instance -        :rtype: LeapDocument +        :return: a SoledadDocument instance +        :rtype: SoledadDocument          """          oldflags = self.getFlags()          return self.setFlags(list(set(oldflags) - set(flags))) @@ -751,6 +751,7 @@ class LeapMessage(WithMsgFields):          :rtype: dict          """          headers = self._get_headers() +        names = map(lambda s: s.upper(), names)          if negate:              cond = lambda key: key.upper() not in names          else: @@ -771,6 +772,21 @@ class LeapMessage(WithMsgFields):      def getSubPart(part):          return None +    # +    # accessors +    # + +    def __getitem__(self, key): +        """ +        Return the content of the message document. + +        @param key: The key +        @type key: str + +        @return: The content value indexed by C{key} or None +        @rtype: str +        """ +        return self._doc.content.get(key, None)  class MessageCollection(WithMsgFields, IndexedDB):      """ @@ -828,7 +844,7 @@ class MessageCollection(WithMsgFields, IndexedDB):          self.mbox = mbox.upper()          self._soledad = soledad -        #self.db = db +        self.initialize_db()          self._parser = Parser()      def _get_empty_msg(self): @@ -887,11 +903,18 @@ class MessageCollection(WithMsgFields, IndexedDB):          # XXX get lower case for keys?          content[self.HEADERS_KEY] = headers -        content[self.SUBJECT_KEY] = headers[self.SUBJECT_FIELD] +        # set subject based on message headers and eventually replace by +        # subject given as param +        if self.SUBJECT_FIELD in headers: +            content[self.SUBJECT_KEY] = headers[self.SUBJECT_FIELD] +        if subject is not None: +            content[self.SUBJECT_KEY] = subject          content[self.RAW_KEY] = stringify(raw) -        if not date: +        if not date and self.DATE_FIELD in headers:              content[self.DATE_KEY] = headers[self.DATE_FIELD] +        else: +            content[self.DATE_KEY] = date          # ...should get a sanity check here.          content[self.UID_KEY] = uid @@ -903,7 +926,7 @@ class MessageCollection(WithMsgFields, IndexedDB):          Removes a message.          :param msg: a u1db doc containing the message -        :type msg: LeapDocument +        :type msg: SoledadDocument          """          self._soledad.delete_doc(msg) @@ -916,9 +939,9 @@ class MessageCollection(WithMsgFields, IndexedDB):          :param uid: the message uid to query by          :type uid: int -        :return: A LeapDocument instance matching the query, +        :return: A SoledadDocument instance matching the query,                   or None if not found. -        :rtype: LeapDocument +        :rtype: SoledadDocument          """          docs = self._soledad.get_from_index(              SoledadBackedAccount.TYPE_MBOX_UID_IDX, @@ -946,7 +969,7 @@ class MessageCollection(WithMsgFields, IndexedDB):          If you want acess to the content, use __iter__ instead          :return: a list of u1db documents -        :rtype: list of LeapDocument +        :rtype: list of SoledadDocument          """          # XXX this should return LeapMessage instances          return self._soledad.get_from_index( @@ -1117,8 +1140,8 @@ class SoledadMailbox(WithMsgFields):          """          Returns mailbox document. -        :return: A LeapDocument containing this mailbox. -        :rtype: LeapDocument +        :return: A SoledadDocument containing this mailbox. +        :rtype: SoledadDocument          """          query = self._soledad.get_from_index(              SoledadBackedAccount.TYPE_MBOX_IDX, @@ -1133,15 +1156,15 @@ class SoledadMailbox(WithMsgFields):          :returns: tuple of flags for this mailbox          :rtype: tuple of str          """ -        return map(str, self.INIT_FLAGS) +        #return map(str, self.INIT_FLAGS)          # XXX CHECK against thunderbird XXX -        #mbox = self._get_mbox() -        #if not mbox: -            #return None -        #flags = mbox.content.get(self.FLAGS_KEY, []) -        #return map(str, flags) +        mbox = self._get_mbox() +        if not mbox: +            return None +        flags = mbox.content.get(self.FLAGS_KEY, []) +        return map(str, flags)      def setFlags(self, flags):          """ @@ -1442,7 +1465,7 @@ class SoledadMailbox(WithMsgFields):          """          docs = self.messages.get_all()          for doc in docs: -            self.messages.db.delete_doc(doc) +            self.messages._soledad.delete_doc(doc)      def _update(self, doc):          """ diff --git a/src/leap/mail/imap/tests/__init__.py b/src/leap/mail/imap/tests/__init__.py index 315d649..fdeda76 100644 --- a/src/leap/mail/imap/tests/__init__.py +++ b/src/leap/mail/imap/tests/__init__.py @@ -17,13 +17,13 @@ def run():      """xxx fill me in"""      pass +import os  import u1db  from leap.common.testing.basetest import BaseLeapTest  from leap.soledad import Soledad -from leap.soledad.util import GPGWrapper -from leap.soledad.backends.leap_backend import LeapDocument +from leap.soledad.document import SoledadDocument  #----------------------------------------------------------------------------- @@ -38,30 +38,65 @@ class BaseSoledadIMAPTest(BaseLeapTest):      """      def setUp(self): -        # config info -        self.gnupg_home = "%s/gnupg" % self.tempdir -        self.db1_file = "%s/db1.u1db" % self.tempdir -        self.db2_file = "%s/db2.u1db" % self.tempdir -        self.email = 'leap@leap.se'          # open test dbs +        self.db1_file = os.path.join( +            self.tempdir, "db1.u1db") +        self.db2_file = os.path.join( +            self.tempdir, "db2.u1db") +          self._db1 = u1db.open(self.db1_file, create=True, -                              document_factory=LeapDocument) +                              document_factory=SoledadDocument)          self._db2 = u1db.open(self.db2_file, create=True, -                              document_factory=LeapDocument) - -        # initialize soledad by hand so we can control keys -        self._soledad = Soledad(self.email, gnupg_home=self.gnupg_home, -                                bootstrap=False, -                                prefix=self.tempdir) -        self._soledad._init_dirs() -        self._soledad._gpg = GPGWrapper(gnupghome=self.gnupg_home) - -        if not self._soledad._has_privkey(): -            self._soledad._set_privkey(PRIVATE_KEY) -        if not self._soledad._has_symkey(): -            self._soledad._gen_symkey() -        self._soledad._load_symkey() -        self._soledad._init_db() +                              document_factory=SoledadDocument) + +        # soledad config info +        self.email = 'leap@leap.se' +        secrets_path = os.path.join( +            self.tempdir, Soledad.STORAGE_SECRETS_FILE_NAME) +        local_db_path = os.path.join( +            self.tempdir, Soledad.LOCAL_DATABASE_FILE_NAME) +        server_url = '' +        cert_file = None + +        self._soledad = self._soledad_instance( +            self.email, '123', +            secrets_path=secrets_path, +            local_db_path=local_db_path, +            server_url=server_url, +            cert_file=cert_file) + +    def _soledad_instance(self, uuid, passphrase, secrets_path, local_db_path, +                          server_url, cert_file): +        """ +        Return a Soledad instance for tests. +        """ +        # mock key fetching and storing so Soledad doesn't fail when trying to +        # reach the server. +        Soledad._fetch_keys_from_shared_db = Mock(return_value=None) +        Soledad._assert_keys_in_shared_db = Mock(return_value=None) + +        # instantiate soledad +        def _put_doc_side_effect(doc): +            self._doc_put = doc + +        class MockSharedDB(object): + +            get_doc = Mock(return_value=None) +            put_doc = Mock(side_effect=_put_doc_side_effect) + +            def __call__(self): +                return self + +        Soledad._shared_db = MockSharedDB() + +        return Soledad( +            uuid, +            passphrase, +            secrets_path=secrets_path, +            local_db_path=local_db_path, +            server_url=server_url, +            cert_file=cert_file, +        )      def tearDown(self):          self._db1.close() diff --git a/src/leap/mail/imap/tests/test_imap.py b/src/leap/mail/imap/tests/test_imap.py index 6b6c24e..8804fe0 100644 --- a/src/leap/mail/imap/tests/test_imap.py +++ b/src/leap/mail/imap/tests/test_imap.py @@ -31,24 +31,18 @@ try:  except ImportError:      from StringIO import StringIO -#import codecs -#import locale  import os  import types  import tempfile  import shutil -#from zope.interface import implements +from mock import Mock + -#from twisted.mail.imap4 import MessageSet  from twisted.mail import imap4  from twisted.protocols import loopback  from twisted.internet import defer -#from twisted.internet import error -#from twisted.internet import reactor -#from twisted.internet import interfaces -#from twisted.internet.task import Clock  from twisted.trial import unittest  from twisted.python import util, log  from twisted.python import failure @@ -59,8 +53,6 @@ import twisted.cred.checkers  import twisted.cred.credentials  import twisted.cred.portal -#from twisted.test.proto_helpers import StringTransport, StringTransportWithDisconnection -  #import u1db @@ -68,8 +60,6 @@ from leap.common.testing.basetest import BaseLeapTest  from leap.mail.imap.server import SoledadMailbox  from leap.mail.imap.server import SoledadBackedAccount  from leap.mail.imap.server import MessageCollection -#from leap.mail.imap.tests import PUBLIC_KEY -#from leap.mail.imap.tests import PRIVATE_KEY  from leap.soledad import Soledad  from leap.soledad import SoledadCrypto @@ -107,19 +97,23 @@ def initialize_soledad(email, gnupg_home, tempdir):      server_url = "http://provider"      cert_file = "" +    class MockSharedDB(object): + +        get_doc = Mock(return_value=None) +        put_doc = Mock() + +        def __call__(self): +            return self + +    Soledad._shared_db = MockSharedDB() +      _soledad = Soledad( -        uuid,  # user's uuid, obtained through signal events -        passphrase,  # how to get this? -        secret_path,  # how to get this? -        local_db_path,  # how to get this? -        server_url,  # can be None for now -        cert_file, -        bootstrap=False) -    _soledad._init_dirs() -    _soledad._crypto = SoledadCrypto(_soledad) -    _soledad._shared_db = None -    _soledad._init_keys() -    _soledad._init_db() +        uuid, +        passphrase, +        secret_path, +        local_db_path, +        server_url, +        cert_file)      return _soledad @@ -253,9 +247,9 @@ class IMAP4HelperMixin(BaseLeapTest):          #cls.db2_file = "%s/db2.u1db" % cls.tempdir          # open test dbs          #cls._db1 = u1db.open(cls.db1_file, create=True, -                              #document_factory=LeapDocument) +                              #document_factory=SoledadDocument)          #cls._db2 = u1db.open(cls.db2_file, create=True, -                              #document_factory=LeapDocument) +                              #document_factory=SoledadDocument)          # initialize soledad by hand so we can control keys          cls._soledad = initialize_soledad( @@ -401,12 +395,21 @@ class MessageCollectionTestCase(IMAP4HelperMixin, unittest.TestCase):          """          Test empty message and collection          """ -        em = self.messages.get_empty_msg() -        self.assertEqual(em, -                         {"subject": "", "seen": False, -                          "flags": [], "mailbox": "inbox", -                          "mbox-uid": 1, -                          "raw": ""}) +        em = self.messages._get_empty_msg() +        self.assertEqual( +            em, +            { +                "date": '', +                "flags": [], +                "headers": {}, +                "mbox": "inbox", +                "raw": "", +                "recent": True, +                "seen": False, +                "subject": "", +                "type": "msg", +                "uid": 1, +            })          self.assertEqual(self.messages.count(), 0)      def testFilterByMailbox(self): @@ -419,13 +422,13 @@ class MessageCollectionTestCase(IMAP4HelperMixin, unittest.TestCase):          mc.add_msg('', subject="test3")          self.assertEqual(self.messages.count(), 3) -        newmsg = mc.get_empty_msg() +        newmsg = mc._get_empty_msg()          newmsg['mailbox'] = "mailbox/foo"          newmsg['subject'] = "test another mailbox" -        mc.db.create_doc(newmsg) +        mc._soledad.create_doc(newmsg)          self.assertEqual(mc.count(), 3) -        self.assertEqual(len(mc.db.get_from_index(mc.MAILBOX_INDEX, "*")), -                         4) +        self.assertEqual( +            len(mc._soledad.get_from_index(mc.TYPE_IDX, "*")), 4)  class LeapIMAP4ServerTestCase(IMAP4HelperMixin, unittest.TestCase): @@ -561,10 +564,13 @@ class LeapIMAP4ServerTestCase(IMAP4HelperMixin, unittest.TestCase):          """          Try deleting a mailbox with sub-folders, and \NoSelect flag set.          An exception is expected + +        Obs: this test will fail if SoledadMailbox returns hardcoded flags.          """          SimpleLEAPServer.theAccount.addMailbox('delete')          to_delete = SimpleLEAPServer.theAccount.getMailbox('delete')          to_delete.setFlags((r'\Noselect',)) +        to_delete.getFlags()          SimpleLEAPServer.theAccount.addMailbox('delete/me')          def login(): @@ -1180,7 +1186,6 @@ class LeapIMAP4ServerTestCase(IMAP4HelperMixin, unittest.TestCase):          """          name = 'mailbox-close'          self.server.theAccount.addMailbox(name) -        #import ipdb; ipdb.set_trace()          m = SimpleLEAPServer.theAccount.getMailbox(name)          m.messages.add_msg('', subject="Message 1", | 
