-
-
Save dames57/b3e0324cd78559744f0a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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ä <[email protected]> | |
This file is licensed under the GPLv2+. | |
keepass_kppy_pass.py: Copyright (C) 2014 Scott Hansen <[email protected]> | |
""" | |
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