Skip to content

Instantly share code, notes, and snippets.

@top
Last active January 26, 2023 20:17
Show Gist options
  • Save top/816544eb2adac4b6c1fe09f47b878437 to your computer and use it in GitHub Desktop.
Save top/816544eb2adac4b6c1fe09f47b878437 to your computer and use it in GitHub Desktop.
Chrome passwords to Keepass db
from pykeepass import PyKeePass
import re
import csv
class Keepass(object):
def __init__(self, database, password):
self.kp = PyKeePass(database, password=password)
def all_entries(self, group='Logins'):
g = self.add_group(group=group)
return [{
'name': x.title or '',
'url': Util.trim_url(x.url),
'username': x.username or '',
'password': x.password or '',
'notes': x.notes or ''} for x in g.entries]
def add_group(self, group=''):
return self.kp.find_groups(name=group, first=True) or self.kp.add_group(destination_group=self.kp.root_group, group_name=group)
def save_entries(self, group, items):
for item in items:
entry = self.kp.find_entries(group=group, title=item['name'], username=item['username'], first=True)
if not entry:
print(f'====> new entry: {item["name"] or item["url"]}, {item["username"]}')
self.kp.add_entry(
destination_group=group,
title=item.get('name', ''),
url=item.get('url', ''),
username=item.get('username', ''),
password=item.get('password', ''),
notes=item.get('notes', ''))
self.kp.save()
else:
print(f'----> skip existing entry: {item["name"] or item["url"]}, {item["username"]}')
class Browser(object):
def __init__(self, csvfile=''):
self.csvfile = csvfile
def all_entries(self):
rows = []
with open(self.csvfile, 'r') as f:
reader = csv.reader(f)
fields = next(reader)
csv_reader = csv.DictReader(f, fieldnames=fields)
for row in csv_reader:
rows.append(dict(row.items()))
return [{
'name': x.get('name', ''),
'url': Util.trim_url(x['url']),
'username': x.get('username', ''),
'password': x.get('password', ''),
} for x in rows]
class Util(object):
@staticmethod
def trim_url(url):
return re.sub(r'/?$', '', re.sub(r'^(https?)?(://)?(www\.)?', '', url or ''))
@staticmethod
def merge_slices(s1, s2):
s1x = {f"{x['url']}{x['username']}": x for x in s1}
s2x = {f"{x['url']}{x['username']}": x for x in s2}
for k in s2x:
# 如果旧库里面没有这条记录,添加进旧库
if not s1x.get(k):
s1x[k] = s2x[k]
else:
# 如果旧库中的密码与新库不一致,以新库覆盖旧库
if s1x[k]['password'] != s2x[k]['password']:
s1x[k]['password'] = s2x[k]['password']
return [v for k, v in s1x.items()]
if __name__ == '__main__':
kp = Keepass(database='Tang.kdbx', password='')
entries_db = kp.all_entries()
br = Browser('Microsoft Edge Passwords.csv')
entries_br = br.all_entries()
items = Util.merge_slices(entries_db, entries_br)
# print(len(items), [item for item in items if item.get('notes', '')])
# exit()
group = kp.add_group(group='Logins 2')
kp.save_entries(group, items)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment