password-store

Simple password manager using gpg and ordinary unix directories
git clone https://git.zx2c4.com/password-store
Log | Files | Refs | README | LICENSE

kwallet2pass.py (3626B)


      1 #!/usr/bin/env python
      2 # -*- coding: utf-8 -*-
      3 #
      4 # Copyright (C) 2012 Juhamatti Niemelä <iiska@iki.fi>. All Rights Reserved.
      5 # Copyright (C) 2014 Diggory Hardy <diggory.hardy@gmail.com>. All Rights Reserved.
      6 # This file is licensed under the GPLv2+. Please see COPYING for more information.
      7 
      8 import sys
      9 import re
     10 
     11 from subprocess import Popen, PIPE
     12 from xml.etree import ElementTree
     13 
     14 HEAD = '/passwords/'
     15 
     16 def insert_data(path,text):
     17     """ Insert data into the password store.
     18     (1) removes HEAD from path
     19     (2) ensures text ends with a new line and encodes in UTF-8
     20     (3) inserts
     21     """
     22     global HEAD
     23     if path.startswith(HEAD):
     24         path = path[len(HEAD):]
     25     
     26     if not text.endswith('\n'):
     27         text = text + '\n'
     28     text = text.encode('utf8')
     29     
     30     #print "Import: " + path + ": " + text
     31     proc = Popen(['pass', 'insert', '--multiline', '--force', path],
     32                  stdin=PIPE, stdout=PIPE)
     33     proc.communicate(text)
     34     proc.wait()
     35 
     36 def space_to_camelcase(value):
     37     output = ""
     38     first_word_passed = False
     39     for word in value.split(" "):
     40         if not word:
     41             output += "_"
     42             continue
     43         if first_word_passed:
     44             output += word.capitalize()
     45         else:
     46             output += word.lower()
     47         first_word_passed = True
     48     return output
     49 
     50 def cleanTitle(title):
     51     # make the title more command line friendly
     52     title = re.sub("(\\|\||\(|\)|/)", "-", title)
     53     title = re.sub("-$", "", title)
     54     title = re.sub("\@", "At", title)
     55     title = re.sub("'", "", title)
     56     return title
     57 
     58 def path_for(element, path=''):
     59     """ Generate path name from elements title and current path """
     60     title = cleanTitle(space_to_camelcase(element.attrib['name']))
     61     return '/'.join([path, title])
     62 
     63 def unexpected(element, path):
     64     print "Unexpected element: " + path + '/' + element.tag + "\tAttributes: " + str(element.attrib)
     65 
     66 def import_map(element, path):
     67     npath = path_for(element, path)
     68     nEntries = 0
     69     text = 'Map'
     70     for child in element:
     71         if child.tag == 'mapentry':
     72             name = child.attrib['name']
     73             text = text + '\n\n' + name + '\n' + child.text
     74             nEntries += 1
     75             for child2 in child:
     76                 unexpected(child, path_for(child, npath))
     77         else:
     78             unexpected(child, npath)
     79     
     80     insert_data(npath, text)
     81     print "Map " + npath + " [" + str(nEntries) + " entries]"
     82 
     83 def import_password(element, path=''):
     84     """ Import new password entry to password-store using pass insert
     85     command """
     86     npath = path_for(element, path)
     87     text = element.text
     88     if text == None:
     89         print "Password " + npath + ": no text"
     90         text = ""
     91     insert_data(npath, text)
     92     for child in element:
     93         unexpected(child, npath)
     94 
     95 def import_folder(element, path=''):
     96     """ Import all entries and folders from given folder """
     97     npath = path_for(element, path)
     98     print "Importing folder " + npath
     99     nPasswords = 0
    100     for child in element:
    101         if child.tag == 'folder':
    102             import_folder(child, npath)
    103         elif child.tag == 'password':
    104             import_password(child, npath)
    105             nPasswords += 1
    106         elif child.tag == 'map':
    107             import_map(child, npath)
    108         else:
    109             unexpected(child, npath)
    110     
    111     if nPasswords > 0:
    112         print "[" + str(nPasswords) + " passwords]"
    113 
    114 def main(xml_file):
    115     """ Parse XML entries from a KWallet """
    116     element = ElementTree.parse(xml_file).getroot()
    117     assert element.tag == 'wallet'
    118     import_folder(element)
    119 
    120 if __name__ == '__main__':
    121     main(sys.argv[1])