From 4ccfb51d4c8d0fe331c6d9f8d805131ef3f02e52 Mon Sep 17 00:00:00 2001 From: Ted Date: Thu, 26 Dec 2019 10:55:55 -0500 Subject: [PATCH 1/4] import from json files, include folders, and work with latest enpass --- enpass-to-keepass.py | 62 +++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/enpass-to-keepass.py b/enpass-to-keepass.py index d9490b4..d63885e 100755 --- a/enpass-to-keepass.py +++ b/enpass-to-keepass.py @@ -6,32 +6,28 @@ License: Public Domain Author: Joseph Paul + +Updated by: deltreey 2019-12-26 """ import argparse import csv +import json ALLOWED_FIELDS = ['url', 'username', 'password'] -HEADERS = ['title', 'url', 'username', 'password', 'notes'] -MAP_FIELDNAMES = { - 'login': 'username', - 'benutzername': 'username', - 'login kennwort': 'password', - 'kennwort': 'password', - 'email': 'username', - 'e-mail': 'username', -} +HEADERS = ['title', 'url', 'username', 'password', 'group', 'notes'] extra_keys = set([]) def main(args): results = [] - reader = csv.reader(args.input_file) - - reader.__next__() # skip titles row + with open('export.json') as json_file: + data = json.load(json_file) + folders = data['folders'] + items = data['items'] - for row in reader: - results.append(processRow(row)) + for item in items: + results.append(processItem(item, folders)) if (len(results) == 0): print('No rows to write (empty input file?)') @@ -47,33 +43,29 @@ def main(args): writer.writerows(results) -def processRow(row): - notes = row.pop() +def processItem(item, folders): + print('Reading item: ' + item['title']) result = { - 'title': row.pop(0), - 'notes': notes + '\n\n' if len(notes) else '' + 'title': item['title'], + 'notes': item['subtitle'] + '\n\n\n' } - for (key, value) in makePairs(row): - if key in result or key not in ALLOWED_FIELDS: - result['notes'] += "%s: %s\n" % (key, value) - extra_keys.add(key) - else: - result[key] = value - - return result + if item.get('folders'): + for folder in folders: + if folder['uuid'] == item['folders'][0]: + result['group'] = folder['title'] + break + for field in item.get('fields', []): + if field['label'] in result or field['label'].lower() not in ALLOWED_FIELDS: + result['notes'] += "%s\n%s\n\n" % (field['label'], field['value']) + extra_keys.add(field['label']) + else: + result[field['label'].lower()] = field['value'] -def makePairs(row): - return [(sanitizeKey(row[i]), row[i+1]) for i in range(0, len(row), 2)] - -def sanitizeKey(key): - key = key.strip().lower() - - if key in MAP_FIELDNAMES: - return MAP_FIELDNAMES[key] + result['notes'] += "NOTES\n\n" + item['note'] - return key + return result if __name__ == '__main__': parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawTextHelpFormatter) From e5d3ccc6204a365e57ae769d367a62f8670428f5 Mon Sep 17 00:00:00 2001 From: Ted Date: Thu, 26 Dec 2019 10:57:55 -0500 Subject: [PATCH 2/4] update readme --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0fc567f..832d1f8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # enpass-to-keepass Convert an Enpass csv export so it can be imported to a KeePass database using KeePassXC +## Updates +This now imports from a JSON export from enpass, and includes folders from enpass as groups. Since enpass now uses folders as "labels" and can have multiple, this chooses the first item in the list as the group + ## Background Read this blog article for some background on this tool: [https://jsph.pl/migrating-from-enpass-to-keepass/](https://jsph.pl/migrating-from-enpass-to-keepass/) @@ -17,7 +20,7 @@ License: Public Domain Author: Joseph Paul positional arguments: - input_file Path to Enpass csv export file + input_file Path to Enpass json export file output_file Path to output file (csv) optional arguments: From 1f88b126b1702f48f1d53a085633c510486aca34 Mon Sep 17 00:00:00 2001 From: Ted Date: Thu, 26 Dec 2019 17:05:49 -0500 Subject: [PATCH 3/4] website instead of URL, and substitute email for username when no username exists --- enpass-to-keepass.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/enpass-to-keepass.py b/enpass-to-keepass.py index d63885e..8a5c546 100755 --- a/enpass-to-keepass.py +++ b/enpass-to-keepass.py @@ -6,16 +6,14 @@ License: Public Domain Author: Joseph Paul - -Updated by: deltreey 2019-12-26 """ import argparse import csv import json -ALLOWED_FIELDS = ['url', 'username', 'password'] -HEADERS = ['title', 'url', 'username', 'password', 'group', 'notes'] +ALLOWED_FIELDS = ['website', 'username', 'password'] +HEADERS = ['title', 'website', 'username', 'password', 'group', 'notes'] extra_keys = set([]) @@ -56,14 +54,27 @@ def processItem(item, folders): result['group'] = folder['title'] break + email = '' + username = '' + for field in item.get('fields', []): if field['label'] in result or field['label'].lower() not in ALLOWED_FIELDS: + if field['label'].lower() == 'email': + email = field['value'] + continue + result['notes'] += "%s\n%s\n\n" % (field['label'], field['value']) extra_keys.add(field['label']) else: result[field['label'].lower()] = field['value'] + if field['label'].lower() == 'username': + username = field['value'] result['notes'] += "NOTES\n\n" + item['note'] + if not username and email: + result['username'] = email + else: + result['notes'] += "Email\n" + email return result From 33d5bd20c7041e544ea9a6e0d0fc94ec0a3557b9 Mon Sep 17 00:00:00 2001 From: Ted Date: Thu, 26 Dec 2019 17:37:52 -0500 Subject: [PATCH 4/4] e-DASH-mail --- enpass-to-keepass.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/enpass-to-keepass.py b/enpass-to-keepass.py index 8a5c546..bbd8914 100755 --- a/enpass-to-keepass.py +++ b/enpass-to-keepass.py @@ -59,7 +59,7 @@ def processItem(item, folders): for field in item.get('fields', []): if field['label'] in result or field['label'].lower() not in ALLOWED_FIELDS: - if field['label'].lower() == 'email': + if field['label'].lower() == 'e-mail': email = field['value'] continue @@ -74,7 +74,7 @@ def processItem(item, folders): if not username and email: result['username'] = email else: - result['notes'] += "Email\n" + email + result['notes'] += "E-mail\n" + email return result