diff options
| -rw-r--r-- | __init__.py | 72 | ||||
| -rw-r--r-- | tests/__init__.py | 12 | 
2 files changed, 59 insertions, 25 deletions
| diff --git a/__init__.py b/__init__.py index c9c1bedf..bc8ef5b4 100644 --- a/__init__.py +++ b/__init__.py @@ -12,6 +12,9 @@ import os  import string  import random  import hmac +import configparser +import re +  from leap.soledad.backends import sqlcipher  from leap.soledad.util import GPGWrapper  from leap.soledad.backends.leap_backend import ( @@ -33,34 +36,58 @@ class Soledad(object):      on Soledad server.      """ -    LOCAL_DB_PATH = None -      # other configs      SECRET_LENGTH = 50 -    def __init__(self, user_email, gnupghome=None, initialize=True, -                 prefix=None, secret_path=None, local_db_path=None): +    def __init__(self, user_email, prefix=None, gnupg_home=None, +                 secret_path=None, local_db_path=None, +                 config_file=None, initialize=True):          """          Bootstrap Soledad, initialize cryptographic material and open          underlying U1DB database.          """          self._user_email = user_email -        # paths -        self.PREFIX = prefix or os.environ['HOME'] + '/.config/leap/soledad' -        self.SECRET_PATH = secret_path or self.PREFIX + '/secret.gpg' -        self.LOCAL_DB_PATH = local_db_path or self.PREFIX + '/soledad.u1db' -        if not os.path.isdir(self.PREFIX): -            os.makedirs(self.PREFIX) -        self._gpg = GPGWrapper( -            gnupghome=(gnupghome or self.PREFIX + '/gnupg')) +        self._init_config(prefix, gnupg_home, secret_path, local_db_path, +                          config_file)          if initialize: +            self._init_dirs()              self._init_crypto()              self._init_db() +    def _init_config(self, prefix, gnupg_home, secret_path, local_db_path, +                     config_file): +        # set default config +        self.prefix = prefix or os.environ['HOME'] + '/.config/leap/soledad' +        default_conf = { +            'gnupg_home': gnupg_home or '%s/gnupg', +            'secret_path': secret_path or '%s/secret.gpg', +            'local_db_path': local_db_path or '%s/soledad.u1db', +            'config_file': config_file or '%s/soledad.ini' +        } +        m = re.compile('.*%s.*') +        for key, default_value in default_conf.iteritems(): +            if m.match(default_value): +                val = default_value % self.prefix +            else: +                val = default_value +            setattr(self, key, val) +        # get config from file +        config = configparser.ConfigParser() +        config.read(self.config_file) +        if 'soledad-server' in config: +            for key in default_conf: +                if key in config['soledad-server']: +                    setattr(self, key, config['soledad-server'][key]) + +    def _init_dirs(self): +        if not os.path.isdir(self.prefix): +            os.makedirs(self.prefix) +      def _init_crypto(self):          """          Load/generate OpenPGP keypair and secret for symmetric encryption.          """ +        self._gpg = GPGWrapper(gnupghome=self.gnupg_home)          # load/generate OpenPGP keypair          if not self._has_openpgp_keypair():              self._gen_openpgp_keypair() @@ -75,7 +102,7 @@ class Soledad(object):          # TODO: verify if secret for sqlcipher should be the same as the          # one for symmetric encryption.          self._db = sqlcipher.open( -            self.LOCAL_DB_PATH, +            self.local_db_path,              self._secret,              create=True,              document_factory=LeapDocument, @@ -97,14 +124,14 @@ class Soledad(object):          file.          """          # does the file exist in disk? -        if not os.path.isfile(self.SECRET_PATH): +        if not os.path.isfile(self.secret_path):              return False          # is it asymmetrically encrypted? -        f = open(self.SECRET_PATH, 'r') +        f = open(self.secret_path, 'r')          content = f.read()          if not self.is_encrypted_asym(content):              raise DocumentNotEncrypted( -                "File %s is not encrypted!" % self.SECRET_PATH) +                "File %s is not encrypted!" % self.secret_path)          # can we decrypt it?          fp = self._gpg.encrypted_to(content)['fingerprint']          if fp != self._fingerprint: @@ -116,22 +143,23 @@ class Soledad(object):          Load secret for symmetric encryption from local encrypted file.          """          try: -            with open(self.SECRET_PATH) as f: +            with open(self.secret_path) as f:                  self._secret = str(self._gpg.decrypt(f.read()))          except IOError: -            raise IOError('Failed to open secret file %s.' % self.SECRET_PATH) +            raise IOError('Failed to open secret file %s.' % self.secret_path)      def _gen_secret(self):          """          Generate a secret for symmetric encryption and store in a local          encrypted file.          """ -        self._secret = ''.join(random.choice(string.ascii_uppercase + -                               string.digits) for x in -                               range(self.SECRET_LENGTH)) +        self._secret = ''.join( +            random.choice( +                string.ascii_letters + +                string.digits) for x in range(self.SECRET_LENGTH))          ciphertext = self._gpg.encrypt(self._secret, self._fingerprint,                                         self._fingerprint) -        f = open(self.SECRET_PATH, 'w') +        f = open(self.secret_path, 'w')          f.write(str(ciphertext))          f.close() diff --git a/tests/__init__.py b/tests/__init__.py index d8927e36..394a13d8 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -4,6 +4,7 @@ Tests to make sure Soledad provides U1DB functionality and more.  import u1db  from leap.soledad import Soledad +from leap.soledad.util import GPGWrapper  from leap.soledad.backends.leap_backend import LeapDocument  from leap.testing.basetest import BaseLeapTest @@ -29,13 +30,18 @@ class BaseSoledadTest(BaseLeapTest):                                document_factory=LeapDocument)          self._db2 = u1db.open(self.db2_file, create=True,                                document_factory=LeapDocument) -        # open a soledad instance -        self._soledad = Soledad(self.email, gnupghome=self.gnupg_home, +        # initialize soledad by hand so we can control keys +        self._soledad = Soledad(self.email, gnupg_home=self.gnupg_home,                                  initialize=False,                                  prefix=self.tempdir) +        self._soledad._init_dirs() +        self._soledad._gpg = GPGWrapper(gnupghome=self.gnupg_home)          self._soledad._gpg.import_keys(PUBLIC_KEY)          self._soledad._gpg.import_keys(PRIVATE_KEY) -        self._soledad._init_crypto() +        self._soledad._load_openpgp_keypair() +        if not self._soledad._has_secret(): +            self._soledad._gen_secret() +        self._soledad._load_secret()          self._soledad._init_db()      def tearDown(self): | 
