Last active
April 6, 2018 06:07
-
-
Save roman-yepishev/80737d1f595795073504 to your computer and use it in GitHub Desktop.
Converts ZohoVault export to KeePassX .kdb (python 3 only)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 | |
) |
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.
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
Hi there!
I've tried to use your script but it throws a persisten error all the time.
I've just updated pip3 and python3, running on a Mac. Any ideas?