Skip to content

Instantly share code, notes, and snippets.

@firecat53
Last active August 29, 2015 14:03
Show Gist options
  • Save firecat53/fffab123019a12e4fb66 to your computer and use it in GitHub Desktop.
Save firecat53/fffab123019a12e4fb66 to your computer and use it in GitHub Desktop.
Import keepass 1.x password database into GNU pass (no GUI required)
#!/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.
"""
title = re.sub("(\\|\||\(|\)|/)", "-", title)
title = re.sub("-$", "", title)
title = re.sub("\@", "At", title)
title = re.sub("'", "", 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', 'username', 'url', 'comment']:
ret.append(getattr(entry, field))
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()
@tr37ion
Copy link

tr37ion commented Mar 25, 2015

Hi, great script. I have two questions:

I have trouble using the Firefox "Passff" addon and how it matches imported data of this script. Instead of using the keepass user/loginname, Passff uses the name of the generated entry of this script. I'm not sure if this is a passff issue or related in which order this script imports data?! Which leads to my second question.
Could you extend the script in a way, that the "import matching rules" can be easily adapted via variables? This way the user could easily create it's own matching rules.

  • [script variable name] = [keepass section name] + [string]
  • var group_name = "kgroupname" + "-"' + "kentryname"
  • var entry_name = "kentry" + "(" + "kusername" + ")"
  • var user = "kusername"
  • var password = "kpassword"
  • ...

Btw. where can I find an overview of the Keepass database entries for creating matching rules?

@dames57
Copy link

dames57 commented May 9, 2015

Thanks for this. I've made some modifications, like improving the clean up of titles for file name creation and also have added titles like Username:, Title:, and URL: for additional password entry data. The modified script is here: https://gist.github.com/dames57/b3e0324cd78559744f0a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment