Skip to content

Instantly share code, notes, and snippets.

@nejdetckenobi
Created December 30, 2024 10:25
Show Gist options
  • Select an option

  • Save nejdetckenobi/0967b2ed578772464d49fa218682325d to your computer and use it in GitHub Desktop.

Select an option

Save nejdetckenobi/0967b2ed578772464d49fa218682325d to your computer and use it in GitHub Desktop.
`kdbx` deposunu, `pass` deposuna aktarmak için yazılmış bir araç. `-f` argümanına XML halinde dışa aktardığın parola listesinin yolunu vererek çalıştırabilirsin.
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Script for importing KeeWeb (Keepass XML) data to pass.
# This file is licensed under the GPLv2+. Please see COPYING for more information.
import getopt
import sys
from subprocess import Popen, PIPE
from xml.etree import ElementTree
def pass_import_entry(path, data):
""" Import new password entry to password-store using pass insert command """
proc = Popen(['pass', 'insert', '--multiline', path], stdin=PIPE, stdout=PIPE)
proc.communicate(data.encode('utf-8'))
proc.wait()
def get_value(elements, node_text):
""" Get value for a specific key from XML elements """
for element in elements:
for child in element.findall('Key'):
if child.text == node_text:
value = element.find('Value')
return value.text if value is not None else ''
return ''
def path_for(element, path=''):
""" Generate path name from elements title and current path """
if element.tag == 'Entry':
title = get_value(element.findall("String"), "Title")
elif element.tag == 'Group':
title = element.find('Name').text
else:
title = ''
if path == '':
return title
else:
return '/'.join([path, title])
def password_data(element, path=''):
""" Return password data and additional info if available from password entry element """
data = ""
password = get_value(element.findall('String'), 'Password')
if password:
data = password + "\n"
else:
print(f"[WARN] No password: {path_for(element, path)}")
for field in ['UserName', 'URL', 'Notes']:
value = get_value(element.findall('String'), field)
if value:
data += f"{field}: {value}\n"
# OTP Secret için özel işlem
otp_secret = get_value(element.findall('String'), 'otp')
if otp_secret:
# KeeWeb'den gelen OTP verisini pass-otp formatına dönüştür
if otp_secret.startswith('otpauth://'):
otp_entry = f"{otp_secret}"
else:
otp_entry = f"otpauth://totp/default?secret={otp_secret}"
data += otp_entry
return data
def import_entry(entries, element, path=''):
""" Import a single password entry """
element_path = path_for(element, path)
if element_path in entries:
print(f"[INFO] Duplicate needs merging: {element_path}")
existing_data = entries[element_path]
data = f"{existing_data}---------\nPassword: {password_data(element)}"
else:
data = password_data(element, path)
entries[element_path] = data
def import_group(entries, element, path='', npath=None):
""" Import all entries and sub-groups from a given group """
if npath is None:
npath = path_for(element, path)
for group in element.findall('Group'):
import_group(entries, group, npath)
for entry in element.findall('Entry'):
import_entry(entries, entry, npath)
def import_passwords(xml_file, root_path=None):
""" Parse given KeeWeb XML file and import password groups from it """
print(f"[>>>>] Importing passwords from file {xml_file}")
print(f"[INFO] Root path: {root_path}")
entries = {}
with open(xml_file, 'r', encoding='utf-8') as xml:
text = xml.read()
xml_tree = ElementTree.XML(text)
root = xml_tree.find('Root')
root_group = root.find('Group')
import_group(entries, root_group, '', root_path)
password_count = 0
for path, data in sorted(entries.items()):
sys.stdout.write(f"[>>>>] Importing {path} ... ")
pass_import_entry(path, data)
sys.stdout.write("OK\n")
password_count += 1
print(f"[ OK ] Done. Imported {password_count} passwords.")
def usage():
""" Print usage """
print(f"Usage: {sys.argv[0]} -f XML_FILE")
print("Optional:")
print(" -r ROOT_PATH Different root path to use than the one in xml file, use \"\" for none")
def main(argv):
""" Main function to handle command-line arguments and execute the script """
try:
opts, args = getopt.gnu_getopt(argv, "f:r:")
except getopt.GetoptError as err:
print(str(err))
usage()
sys.exit(2)
xml_file = None
root_path = None
for opt, arg in opts:
if opt == "-f":
xml_file = arg
if opt == "-r":
root_path = arg
if xml_file:
import_passwords(xml_file, root_path)
else:
usage()
sys.exit(2)
if __name__ == '__main__':
main(sys.argv[1:])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment