Skip to content

Instantly share code, notes, and snippets.

@roman-yepishev
Last active April 6, 2018 06:07
Show Gist options
  • Save roman-yepishev/80737d1f595795073504 to your computer and use it in GitHub Desktop.
Save roman-yepishev/80737d1f595795073504 to your computer and use it in GitHub Desktop.
Converts ZohoVault export to KeePassX .kdb (python 3 only)
#!/usr/bin/python3
"""Convert Zoho Vault Export CSV to KeePass KDB
Usage: zohovault2keepass.py ZohoVault.csv keepass.kdb
You will be prompted for the encryption password.
"""
import csv
import collections
import getpass
import sys
import kppy.database
EXPORT_GROUP = 'Zoho Vault'
ZohoVaultEntry = collections.namedtuple('ZohoVaultEntry', [
'secret_name', 'description', 'secret_url', 'secret_data',
'notes', 'custom_data', 'tags', 'classification', 'favorite',
'chamber_name'
])
class ZohoVaultConverter(object):
"""Zoho Vault Converter"""
def __init__(self):
"""Initialize converter"""
self._database = None
self._group = None
def _prepare_db(self, path, password):
"""Prepare KDB database and group"""
self._database = kppy.database.KPDBv1(
filepath=path, password=password, new=True
)
# This returns boolean, so we need to hunt for the group
self._database.create_group(title=EXPORT_GROUP)
for item in self._database.groups:
if item.title == EXPORT_GROUP:
self._group = item
break
if self._group is None:
raise RuntimeError("Created group is not found")
def convert(self, input_path, output_path, password):
"""Convert CSV-ish data exported from Zoho Vault to KDB"""
self._prepare_db(output_path, password)
entries = []
with open(input_path, 'r', encoding='utf-8') as filehandle:
reader = csv.reader(filehandle)
# fast-forward through the header
next(reader)
for row in [v for v in reader if v]:
entries.append(self._process_row(row))
for entry in entries:
entry["group"] = self._group
self._database.create_entry(**entry)
self._database.save()
self._database.close()
@staticmethod
def _process_row(row):
"""Process Vault Entry"""
if len(row) > 10:
assert row[10] == ''
entry = ZohoVaultEntry(*row[0:10])
secret_data = {}
for line in [v.strip() for v in entry.secret_data.split('\n')
if v != '']:
key, value = line.split(':', 1)
secret_data[key] = value
comment = []
if entry.description.strip() != '':
comment.append(entry.description)
if entry.notes.strip() != '':
comment.append(entry.notes)
if entry.custom_data.strip() != '':
comment.append(entry.custom_data)
return {
"title": entry.secret_name,
"url": entry.secret_url,
"username": secret_data.get("User Name", ''),
"password": secret_data.get("Password", ''),
"comment": '\n'.join(comment)
}
if __name__ == "__main__":
if len(sys.argv) != 3:
print(__doc__)
sys.exit(1)
converter = ZohoVaultConverter()
master_password = getpass.getpass()
converter.convert(
sys.argv[1],
sys.argv[2],
master_password
)
@deltagolf
Copy link

Hi there!
I've tried to use your script but it throws a persisten error all the time.

MacBook-Pro-**********$ python3 zohovault2keepass.py csv_zv.csv zoho-export.kdb
Password: 
Traceback (most recent call last):
  File "zohovault2keepass.py", line 121, in <module>
    master_password
  File "zohovault2keepass.py", line 66, in convert
    entries.append(self._process_row(row))
  File "zohovault2keepass.py", line 103, in _process_row
    "username": secret_data["User Name"],
KeyError: 'User Name'

I've just updated pip3 and python3, running on a Mac. Any ideas?

@roman-yepishev
Copy link
Author

You may not have a user name in one of the fields. Updated the gist to work with missing User Name or Password, however I did not prepare tests for this script, so YMMV.

@deltagolf
Copy link

Yup, that was it. You've nailed it. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment