Skip to content

Instantly share code, notes, and snippets.

@dames57
Forked from firecat53/keepass_kppy_pass.py
Last active August 29, 2015 14:20
Show Gist options
  • Save dames57/b3e0324cd78559744f0a to your computer and use it in GitHub Desktop.
Save dames57/b3e0324cd78559744f0a to your computer and use it in GitHub Desktop.
#!/bin/env python
"""Import keepass 1.x compatible password database into GNU pass
http://www.passwordstore.org/.
Uses the kppy (https://pypi.python.org/pypi/kppy) library to open and decode
the database. Python 2.7+ and Python 3.x compatible. Best results with Python3
for any unicode issues.
Usage: keepass2pass.py <keepass db> [--keyfile <key file if necessary>]
Based on http://git.zx2c4.com/password-store/tree/contrib/importers/keepassx2pass.py
keepassx2pass.py: Juhamatti Niemelä <iiska@iki.fi>
This file is licensed under the GPLv2+.
keepass_kppy_pass.py: Copyright (C) 2014 Scott Hansen <firecat4153@gmail.com>
"""
import argparse
import os.path
import re
from getpass import getpass
from subprocess import Popen, PIPE
from kppy.database import KPDBv1
from kppy.exceptions import KPError
def open_db(fn, pw, key=None, ro=True):
"""Open and load the database.
"""
db = KPDBv1(fn, pw, key, ro)
db.load()
return db
def clean_title(title):
"""Make the title more command line friendly.
"""
#Strip leading and trailing whitespace
title = title.strip()
#Remove all non-word characters (everything except numbers and letters)
title = re.sub(r"[^\w\s]", '', title)
#Replace all occurances of whitespace with a single dash
title = re.sub(r"\s+", '-', title)
return title
def path_for(title, path=''):
""" Generate path name from entry title and current path.
"""
title = clean_title(title)
return os.path.join(path, title)
def password_data(entry):
"""Return password data and additional info if available from
password entry element.
"""
ret = []
for field in ['password', 'title', 'username', 'url', 'comment']:
if field == 'password':
ret.append(getattr(entry,field))
elif field == 'title':
s = getattr(entry,field)
s = s.strip().replace(':','')
ret.append('Title: ' + s)
elif field == 'username':
ret.append('Username: ' + getattr(entry,field))
elif field == 'url':
ret.append('URL: ' + getattr(entry,field))
elif field == 'comment':
s = getattr(entry,field)
if s:
ret.append('\n' + s + '\n')
else:
ret.append('')
return "\n".join(ret)
def import_group(group, path=''):
"""Import all entries and sub-groups from given group.
"""
npath = path_for(group.title, path)
for child_group in group.children:
import_group(child_group, npath)
for entry in group.entries:
import_entry(entry, npath)
def import_entry(entry, path=''):
"""Import new password entry to password-store using pass insert
command.
"""
print("Importing: {}".format(entry.title))
try:
data = password_data(entry).encode()
except UnicodeEncodeError:
try:
data = password_data(entry).encode('latin1')
except UnicodeEncodeError:
print("Unicode error. Unable to import {}".format(entry.title))
return
proc = Popen(['pass', 'insert', '--multiline', '--force',
path_for(entry.title, path)], stdin=PIPE, stdout=PIPE)
proc.communicate(data)
proc.wait()
def parse_args():
"""Command line arguments.
Returns: db-file: path to database file
key-file: path to key file, if necessary
"""
parser = argparse.ArgumentParser()
parser.add_argument('dbfile')
parser.add_argument('--keyfile')
args = parser.parse_args()
key = args.keyfile or None
return args.dbfile, key
def main():
fn, key = parse_args()
pw = getpass('Database passphrase: ')
try:
db = open_db(fn, pw, key)
except KPError as e:
print("{}".format(e))
else:
for group in db.root_group.children:
import_group(group)
db.close()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment