keepassx2pass.py (2711B)
1 #!/usr/bin/env python3 2 # 3 # Copyright (C) 2012 Juhamatti Niemelä <iiska@iki.fi>. All Rights Reserved. 4 # This file is licensed under the GPLv2+. Please see COPYING for more information. 5 # 6 # Usage ./keepassx2pass.py export.xml 7 8 import sys 9 import re 10 11 from subprocess import Popen, PIPE 12 from xml.etree import ElementTree 13 14 def space_to_camelcase(value): 15 output = "" 16 first_word_passed = False 17 for word in value.split(" "): 18 if not word: 19 output += "_" 20 continue 21 if first_word_passed: 22 output += word.capitalize() 23 else: 24 output += word.lower() 25 first_word_passed = True 26 return output 27 28 def cleanTitle(title): 29 # make the title more command line friendly 30 title = re.sub("(\\|\||\(|\)|/)", "-", title) 31 title = re.sub("-$", "", title) 32 title = re.sub("\@", "At", title) 33 title = re.sub("'", "", title) 34 return title 35 36 def path_for(element, path=''): 37 """ Generate path name from elements title and current path """ 38 title_text = element.find('title').text 39 if title_text is None: 40 title_text = '' 41 title = cleanTitle(space_to_camelcase(title_text)) 42 return '/'.join([path, title]) 43 44 def password_data(element): 45 """ Return password data and additional info if available from 46 password entry element. """ 47 passwd = element.find('password').text 48 ret = (passwd + "\n") if passwd else "\n" 49 for field in ['username', 'url', 'comment']: 50 fel = element.find(field) 51 children = [(e.text or '') + (e.tail or '') for e in list(fel)] 52 if len(children) > 0: 53 children.insert(0, '') 54 text = (fel.text or '') + "\n".join(children) 55 if len(text) > 0: 56 ret = "%s%s: %s\n" % (ret, fel.tag, text) 57 return ret 58 59 def import_entry(element, path=''): 60 """ Import new password entry to password-store using pass insert 61 command """ 62 print("Importing " + path_for(element, path)) 63 proc = Popen(['pass', 'insert', '--multiline', '--force', 64 path_for(element, path)], 65 stdin=PIPE, stdout=PIPE) 66 proc.communicate(password_data(element).encode()) 67 proc.wait() 68 69 def import_group(element, path=''): 70 """ Import all entries and sub-groups from given group """ 71 npath = path_for(element, path) 72 for group in element.findall('group'): 73 import_group(group, npath) 74 for entry in element.findall('entry'): 75 import_entry(entry, npath) 76 77 78 def main(xml_file): 79 """ Parse given KeepassX XML file and import password groups from it """ 80 for group in ElementTree.parse(xml_file).findall('group'): 81 import_group(group) 82 83 if __name__ == '__main__': 84 main(sys.argv[1])