Beispiel #1
0
 def parse(self):
     """Parse a password-store repository."""
     paths = self.list()
     if not paths:
         raise FormatError('empty password store.')
     for path in paths:
         try:
             entry = self.show(path)
         except PMError as error:  # pragma: no cover
             raise FormatError(error)
         self.data.append(entry)
Beispiel #2
0
 def parse(self):
     """Parse XML based file."""
     self.tree = ElementTree.XML(self.file.read())
     if not self.checkheader(self.header()):
         raise FormatError()
     root = self._getroot(self.tree)
     self._import(root)
Beispiel #3
0
 def parse(self):
     """Parse Generic CSV file."""
     self.file.readline()
     if ',' in self.cols:
         self.fieldnames = self.cols.split(',')
     else:
         raise FormatError("no columns to map to credential attributes.")
     super(GenericCSV, self).parse()
Beispiel #4
0
    def parse(self):
        """Parse Lastpass repository using lpass."""
        uniqueids = self.list(self.root)
        print("PARSE, list:", uniqueids)
        if not uniqueids:
            raise FormatError('empty password store.')

        for uniqueid in uniqueids:
            entry = self.show(uniqueid)
            self.data.append(entry)
Beispiel #5
0
    def parse(self):
        """Parse YAML based file."""
        self.yamls = yaml.safe_load(self.file)
        if not self.checkheader(self.header()):
            raise FormatError()

        keys = self.invkeys()
        for block in self.yamls[self.rootkey]:
            entry = {}
            for key, value in block.items():
                if value:
                    entry[keys.get(key, key)] = value
            self.data.append(entry)
Beispiel #6
0
 def decrypt(self):
     """Import data is GPG encrypted, let's decrypt it."""
     gpgbinary = shutil.which('gpg2') or shutil.which('gpg')
     cmd = [gpgbinary, '--with-colons', '--batch', '--decrypt', self.prefix]
     with Popen(cmd,
                shell=False,
                universal_newlines=False,
                stdin=PIPE,
                stdout=PIPE,
                stderr=PIPE) as process:
         (stdout, stderr) = process.communicate()
         if process.wait():  # pragma: no cover
             raise FormatError("%s %s" % (stderr, stdout))
         return stdout.decode()[:-1]
Beispiel #7
0
    def parse(self):
        """Parse CSV based file."""
        fields = None if self.fieldnames == [] else self.fieldnames
        self.reader = csv.DictReader(self.file,
                                     fieldnames=fields,
                                     delimiter=self.delimiter,
                                     quotechar=self.quotechar)
        if not self.checkheader(self.header(), self.only):
            raise FormatError()

        keys = self.invkeys()
        for row in self.reader:
            entry = dict()
            for col in row:
                entry[keys.get(col, col)] = row.get(col, None)

            self.data.append(entry)
Beispiel #8
0
    def decrypt(self, jsons):
        """Import file is AES GCM encrypted, let's decrypt it.

        Based on the import script from Aegis:
        https://github.com/beemdevelopment/Aegis/blob/master/scripts/decrypt.py
        Format documentation:
        https://github.com/beemdevelopment/Aegis/blob/master/docs/vault.md
        """
        if not CRYPTOGRAPHY:
            raise ImportError(name='cryptography')

        password = getpassword(self.prefix)
        master_key = None
        for slot in jsons['header']['slots']:
            if slot['type'] != 1:
                continue

            kdf = Scrypt(salt=bytes.fromhex(slot['salt']),
                         length=32,
                         n=slot['n'],
                         r=slot['r'],
                         p=slot['p'],
                         backend=default_backend())
            key = kdf.derive(password.encode("utf-8"))

            cipher = AESGCM(key)
            param = slot['key_params']
            try:
                nonce = bytes.fromhex(param['nonce'])
                data = bytes.fromhex(slot['key']) + bytes.fromhex(param['tag'])
                master_key = cipher.decrypt(nonce=nonce,
                                            data=data,
                                            associated_data=None)
            except InvalidTag:  # pragma: no cover
                pass

        if master_key is None:  # pragma: no cover
            raise FormatError("unable to decrypt the master key.")

        cipher = AESGCM(master_key)
        param = jsons['header']['params']
        content = base64.b64decode(jsons['db']) + bytes.fromhex(param['tag'])
        plain = cipher.decrypt(nonce=bytes.fromhex(param['nonce']),
                               data=content,
                               associated_data=None)
        return plain.decode('utf-8')
Beispiel #9
0
    def parse(self):
        """Parse Enpass CSV file."""
        if not self.file.readline().startswith(self.csv_header):
            raise FormatError()
        reader = csv.reader(self.file)
        keys = self.invkeys()
        for row in reader:
            entry = dict()
            entry['title'] = row.pop(0)
            entry['comments'] = row.pop()
            index = 0
            while index + 2 <= len(row):
                key = keys.get(row[index], row[index])
                entry[key] = row[index + 1]
                index += 2

            self.data.append(entry)
Beispiel #10
0
 def parse(self):
     """Parse Lastpass CSV file."""
     super().parse()
     for entry in self.data:
         if 'group' in entry and entry['group'] is None:
             # LastPass will truncate everything after `$` in a
             # secure note entry when exporting as a CSV, including
             # any closing ", leaving the file in a corrupt
             # state. Triggering this is likely a symptom of such a
             # corrupted export.
             #
             # Likewise, it also has problems exporting single
             # quotes in the password field, causing all data prior
             # to the single quote (including the url field, etc.)
             # to be truncated, leading to the parser thinking the
             # path field wasn't included, and incorrectly
             # resulting in a value of None.
             raise FormatError(f'Invalid group in entry:\n{entry}.')
         entry['group'] = entry.get('group', '').replace('\\', os.sep)
Beispiel #11
0
    def parse(self):
        """Parse Clipperz HTML+JSON file."""
        # Extract the json from the html file.
        tree = ElementTree.XML(self.file.read())
        found = tree.find(self.html_header)
        if found is None:
            raise FormatError()

        # Parse JSON data
        keys = self.invkeys()
        for item in json.loads(found.text):
            entry = dict()
            label = item.get('label', ' \ue009').split(' \ue009')
            entry['title'] = label[0]
            if len(label) > 1:
                entry['group'] = label[1]

            fields = item.get('currentVersion', {}).get('fields', {})
            for uid in fields:
                label = fields[uid].get('label', '')
                entry[keys.get(label, label)] = fields[uid].get('value', '')

            entry['comments'] = item.get('data', {}).get('notes', '')
            self.data.append(entry)