keepass2pass.py 2.6 KB

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