[pass] [PATCH] Added alternative converter for keepassx stores.

Boi Sletterink boi at sletterink.nl
Mon Jun 22 14:31:36 CEST 2015


This new converter does not do CamelCase and can slightly more
elegantly handle entries with duplicate names. It will store each entry
with an existing name (after the first) with a -<number> suffix.

This version also exports the original title with the 'title' prefix.
---
 contrib/importers/keepassx2pass-no_camel_case.py |  107 ++++++++++++++++++++++
 1 file changed, 107 insertions(+)
 create mode 100755 contrib/importers/keepassx2pass-no_camel_case.py

diff --git a/contrib/importers/keepassx2pass-no_camel_case.py b/contrib/importers/keepassx2pass-no_camel_case.py
new file mode 100755
index 0000000..8d028b1
--- /dev/null
+++ b/contrib/importers/keepassx2pass-no_camel_case.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2012 Juhamatti Niemelä <iiska at iki.fi>. All Rights Reserved.
+# This file is licensed under the GPLv2+. Please see COPYING for more information.
+
+import sys
+import re
+import os
+
+from subprocess import Popen, PIPE
+from xml.etree import ElementTree
+
+
+def cleanTitle(title):
+    # make the title more command line friendly
+    
+    title = re.sub(" ", "_", title)
+    title = re.sub("'", "", title)
+    title = re.sub("\W", "-", title)
+
+    total_changes = 1
+    while total_changes > 0:
+        total_changes = 0
+        (title, changes) = re.subn("__+", "_", title)
+        total_changes = total_changes + changes
+        (title, changes) = re.subn("(--+|_-|-_)", "-", title)
+        total_changes = total_changes + changes
+
+    title = re.sub("[-_]+$", "", title)
+    title = re.sub("^[-_]+", "", title)
+
+    return title
+
+
+def pass_entry_exists(entry):
+    full_path = os.environ['HOME'] + '/.password-store' + entry + '.gpg'
+    print full_path + "\n"
+
+    try:
+        file = open(full_path);
+    except IOError as e:
+        return False
+
+    return True
+
+
+def path_for(element, path=''):
+    """ Generate path name from elements title and current path """
+    title_text = element.find('title').text
+    if title_text is None:
+        title_text = "unknown"
+    title = cleanTitle(title_text)
+
+    # Check for uniqueness, and make it unique if we have to
+    entry_path = '/'.join([path,title])
+    serial_number = 1
+    while pass_entry_exists(entry_path):
+       serial_number = serial_number + 1
+       entry_path = '/'.join([path, "{0}-{1:d}".format(title, serial_number)])
+
+    return entry_path
+
+
+def password_data(element):
+    """ Return password data and additional info if available from
+    password entry element. """
+    passwd = element.find('password').text
+    ret = passwd + "\n" if passwd else "\n"
+    for field in ['title','username', 'url', 'comment']:
+        fel = element.find(field)
+        children = [unicode(e.text or '') + unicode(e.tail or '') for e in list(fel)]
+        if len(children) > 0:
+            children.insert(0, '')
+        text = (fel.text or '') + "\n".join(children)
+        if len(text) > 0:
+            ret = "%s%s: %s\n" % (ret, fel.tag, text)
+    return ret
+
+
+def import_entry(element, path=''):
+    """ Import new password entry to password-store using pass insert
+    command """
+    print "Importing " + path_for(element, path)
+    proc = Popen(['pass', 'insert', '--multiline', '--force',
+                  path_for(element, path)],
+              stdin=PIPE, stdout=PIPE)
+    proc.communicate(password_data(element).encode('utf8'))
+    proc.wait()
+
+
+def import_group(element, path=''):
+    """ Import all entries and sub-groups from given group """
+    npath = path_for(element, path)
+    for group in element.findall('group'):
+        import_group(group, npath)
+    for entry in element.findall('entry'):
+        import_entry(entry, npath)
+
+
+def main(xml_file):
+    """ Parse given KeepassX XML file and import password groups from it """
+    for group in ElementTree.parse(xml_file).findall('group'):
+        import_group(group)
+
+if __name__ == '__main__':
+    main(sys.argv[1])
-- 
1.7.9.5



More information about the Password-Store mailing list