J’ai eu le besoin de merger plusieurs fichiers base de données de Keepass. Si vous ne connaissez pas cet excellent gestionnaire de mot de passe allez faire un tour ici ! Son pendant Linux/Mac OS X est KeepassX compatible avec la branche 1.x de Keepass.
Ce script (rapidement fait) prend plusieurs fichiers d’export XML Keepass (Menu -> Exporter sous -> XML)
et les regroupent sous un fichier. Il prend l’entrée la plus récente en cas de conflit. Il affichera les conflits en sortie console.
La source est disponible ici pour ceux qui veulent la regarder et je l’ai également compilé ici pour ceux qui veulent faire un merge rapide.
Télécharger KeeMerge
Pour l’exécutable, le mettre dans le même dossier que les exports xml puis le lancer.
Il faut ensuite importer le merge.xml dans Keepass. Créer une nouvelle base puis Menu-> Importer -> XML Keepass 1.x.
from lxml import etree import datetime, glob class Password(object): def init(self, node): date= node.find(“lastmodtime”).text self.lastmodtime= datetime.datetime.strptime(date,"%Y-%m-%dT%H:%M:%S") self.uuid= node.find(“uuid”).text self.username= node.find(“username”).text self.password= node.find(“password”).text self.title= node.find(“title”).text self.node= node def hash(self): return hash(str(self.title)+str(self.lastmodtime)+str(self.uuid)) def eq(self,other): return self.uuid==other.uuid and self.username==other.username and self.password==other.password and self.title==self.title def str(self): s = “%s (%s): [%s|%s] - %s” % (self.title,self.uuid,self.username,self.password,self.lastmodtime) return s def repr(self): s = “%s (%s): [%s|%s] - %s” % (self.title,self.uuid,self.username,self.password,self.lastmodtime) return s def getTree(file): """ Give the root and tree of the XML file """ parser = etree.XMLParser(strip_cdata=False) tree = etree.parse(file, parser) root= tree.getroot() return tree ,root def getpasswords(file): """ Parse and return all the password of an xml exported by Keepass """ tree, root = getTree(file) elements= [] for e in root: elements.append(Password(e)) return elements def main(): # give me your xmls xmls= glob.glob("*.xml") # a dict uniq by the uuid of the node uniquepasswords= dict() # all your passwords are belong to us passwords=[pwd for f in xmls for pwd in getpasswords(f)] # let’s go marco for pwd in passwords: # do I know you ? if pwd.uuid in uniquepasswords: challenger= pwd champion= uniquepasswords[pwd.uuid] # If exact match, skips if challenger != champion: # challenger modified recently ? if challenger.lastmodtime > champion.lastmodtime: print “####” print “%s” % (challenger) print “more recent than” print “%s” % (champion) print “Challenger wins” uniquepasswords[pwd.uuid]= challenger elif challenger.lastmodtime < champion.lastmodtime: print “####” print “%s” % (challenger) print “older than” print “%s” % (champion) print “Garbage” else: # hello you uniquepasswords[pwd.uuid]= pwd # Append xml nodes to root root= etree.Element(“pwlist”) for pwd in uniquepasswords.values(): root.append(pwd.node) # Write to file et = etree.ElementTree(root) et.write(“merge.xml”, pretty_print=True, xml_declaration=True, encoding=‘utf-8’, standalone=‘yes’) if name == “main”: main()