#!/usr/bin/python import optparse import logging import os import sys import time from xml.etree import ElementTree progname = os.path.basename(sys.argv[0]) version = "0.1" parser = optparse.OptionParser(usage="%prog input") logging.basicConfig(level=logging.INFO, format=progname + ": %(levelname)s: %(message)s") parser.add_option("-i", "--ignore-stripped", action="store_true", dest="ignore_stripped", help="ignore the stripped ids") (options, args) = parser.parse_args() class FatalError(Exception): pass def error(msg): logging.error(msg) raise FatalError stripped_ids = {} from_type_to_icon = { "creditcard": 9, "cryptokey": 29, "door": 52, "folder": 48, "generic": 0, "phone": 68, "website": 1 } try: if len(args) != 1: error("requires one argument") old_filename = args[0] old_doc = ElementTree.ElementTree(file=old_filename) old_root = old_doc.getroot() new_root = ElementTree.Element("database") new_doc = ElementTree.ElementTree(new_root) def parse_folder(old_element, new_parent, group_depth): description = None desc_append = "" for item in old_element.findall("*"): if item.tag == "entry": if item.get("type") == "folder": element = ElementTree.SubElement(new_parent, "group") ElementTree.SubElement(element, "icon").text = "48" element.tail = "\n" parse_folder(item, element, group_depth + 1) else: if group_depth == 0: fake_group = ElementTree.SubElement(new_parent, "group") ElementTree.SubElement(fake_group, "icon").text = "48" ElementTree.SubElement(fake_group, "title").text = "Misc" fake_group.tail = "\n" new_parent = fake_group group_depth += 1 element = ElementTree.SubElement(new_parent, "entry") ElementTree.SubElement(element, "icon").text = str(from_type_to_icon[item.get("type")]) element.tail = "\n" parse_folder(item, element, group_depth) else: element = new_parent if item.tag == "name": ElementTree.SubElement(element, "title").text = item.text elif item.tag == "updated": lastmod_time = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(int(item.text))) ElementTree.SubElement(element, "lastmod").text = lastmod_time ElementTree.SubElement(element, "lastaccess").text = lastmod_time ElementTree.SubElement(element, "creation").text = lastmod_time elif item.tag == "field": id = item.get("id") if id == "generic-username": ElementTree.SubElement(element, "username").text = item.text elif id == "generic-password": ElementTree.SubElement(element, "password").text = item.text elif id in ("generic-hostname", "generic-url"): ElementTree.SubElement(element, "url").text = item.text elif id == "creditcard-cardnumber": desc_append += "Card Number: " + item.text + "\n" elif id == "creditcard-expirydate": desc_append += "Card Expiry: " + item.text + "\n" elif id == "creditcard-ccv": desc_append += "Card CCV: " + item.text + "\n" elif id == "generic-pin": if item.text is not None: desc_append += "PIN: " + item.text + "\n" elif id == "phone-phonenumber": ElementTree.SubElement(element, "password").text = item.text elif id == "generic-code": ElementTree.SubElement(element, "password").text = item.text elif id in ("creditcard-cardtype", "generic-location", "generic-certificate", "generic-keyfile"): stripped_ids[id] = 1 else: error("unexpected field id: " + id) elif item.tag == "description": description = item.text else: error("unexpected tag: " + item.tag) if description is not None or len(desc_append) > 0: if len(desc_append) == 0: ElementTree.SubElement(element, "comment").text = description elif description is None: ElementTree.SubElement(element, "comment").text = desc_append else: ElementTree.SubElement(element, "comment").text = description + "\n" + desc_append parse_folder(old_root, new_root, 0) if len(stripped_ids) and not options.ignore_stripped: error("stripped following ids: " + ", ".join(stripped_ids.keys())) sys.stdout.write("\n") new_doc.write(sys.stdout) except FatalError: pass