def write_entry(kdbx_file, kdbx_password, group_path, entry_title, entry_username, entry_password, entry_url, entry_notes, entry_tags, kdbx_keyfile=None, force_creation=False, outfile=None): logging.info('Attempt to write entry "{}: {}:{}" to {}'.format( entry_title, entry_username, entry_password, group_path)) samba_db = False if kdbx_file.startswith('smb://'): samba_db = True smb_kdbx_file = smb_retrieve(kdbx_file) kp = PyKeePass(smb_kdbx_file if samba_db else kdbx_file, password=kdbx_password, keyfile=kdbx_keyfile) dest_group = kp.find_groups_by_path(group_path, first=True) kp.add_entry(destination_group=dest_group, title=entry_title, username=entry_username, password=entry_password, url=entry_url, notes=entry_notes, tags=entry_tags, force_creation=force_creation) if outfile: if outfile.startswith('smb://'): file_written = kp.save() smb_send(file_written.name, outfile) logging.info('Sent database file to {}'.format(outfile)) else: file_written = kp.save(kdbx_file) logging.info('KeePass DB written to {}'.format(file_written.name)) else: if samba_db: file_written = kp.save() smb_send(file_written.name, kdbx_file) logging.info('Sent database file to {}'.format(kdbx_file)) else: file_written = kp.save(kdbx_file) logging.info('KeePass DB written to {}'.format(file_written.name))
class GroupFunctionTests(unittest.TestCase): # get some things ready before testing def setUp(self): self.kp = PyKeePass(os.path.join(base_dir, 'test.kdbx'), password='******', keyfile=os.path.join(base_dir, 'test.key')) #---------- Finding groups ----------- def test_find_groups_by_name(self): results = self.kp.find_groups_by_name('subgroup') self.assertEqual(len(results), 1) results = self.kp.find_groups_by_name('subgroup', first=True) self.assertEqual(results.name, 'subgroup') g = self.kp.find_groups(name='foobar_group', first=True) results = self.kp.find_groups(group=g, name='.*group.*', regex=True) self.assertEqual(len(results), 2) results = self.kp.find_groups(group=g, name='.*group.*', regex=True, recursive=False) self.assertEqual(len(results), 1) def test_find_groups_by_path(self): results = self.kp.find_groups_by_path('/foobar_group/subgroup/') self.assertIsInstance(results[0], Group) results = self.kp.find_groups_by_path('/foobar_group/subgroup/', first=True) self.assertEqual(results.name, 'subgroup') def test_find_groups_by_uuid(self): results = self.kp.find_groups_by_uuid('lRVaMlMXoQ/U5NDCAwJktg==', first=True) self.assertIsInstance(results, Group) results = self.kp.find_groups(uuid='^lRVaMlMX|^kwTZdSoU', regex=True) self.assertEqual(len(results), 2) def test_find_groups_by_notes(self): results = self.kp.find_groups(notes='group notes') self.assertEqual(len(results), 1) self.assertEqual(results[0].uuid, 'lRVaMlMXoQ/U5NDCAwJktg==') def test_find_groups(self): results = self.kp.find_groups(path='/foobar_group/subgroup/') self.assertIsInstance(results[0], Group) results = self.kp.find_groups_by_path('/foobar_group/subgroup/', first=True) self.assertEqual(results.name, 'subgroup') def test_groups(self): results = self.kp.groups self.assertEqual(len(results), 6) #---------- Adding/Deleting Groups ----------- def test_add_delete_move_group(self): notes_text = "this is a note for a group!" base_group = self.kp.add_group(self.kp.root_group, 'base_group', notes=notes_text) sub_group = self.kp.add_group(base_group, 'sub_group') sub_group2 = self.kp.add_group(base_group, 'sub_group2') self.assertEqual(base_group.notes, notes_text) base_group.notes = '' self.assertEqual(base_group.notes, '') results = self.kp.find_groups_by_path('base_group/sub_group/', first=True) self.assertIsInstance(results, Group) self.assertEqual(results.name, sub_group.name) self.kp.move_group(sub_group2, sub_group) results = self.kp.find_groups(path='base_group/sub_group/sub_group2/', first=True) self.assertEqual(results.name, sub_group2.name) self.kp.delete_group(sub_group) results = self.kp.find_groups_by_path('base_group/sub_group/', first=True) self.assertIsNone(results) # ---------- Groups representation ----------- def test_print_groups(self): self.assertIsInstance(self.kp.groups.__repr__(), str)
class KeepassLoader: kp = NotImplemented database_path = "" password_try = "" password_check = "" password = "" group_list = [] def __init__(self, database_path, password): self.kp = PyKeePass(database_path, password) self.database_path = database_path def add_group(self, name, icon, note, parent_group): group = Group(name, icon, note, parent_group) self.kp.add_group(group.get_parent_group(), group.get_name()) self.group_list.append(group) def add_entry(self, group_path, entry_name, username, password, url, notes, icon): entry = Entry(group_path, entry_name, username, password, url, notes, icon) self.kp.add_entry(self.kp.find_groups_by_path(entry.get_group_path()), entry.get_entry_name(), entry.get_username(), entry.get_password(), url=entry.get_url(), notes=entry.get_notes(), icon=entry.get_icon()) def get_entries(self, group_path): group = self.kp.find_groups_by_path(group_path, first=True) #group = self.kp.find_groups(name="Untergruppe", first=True) print(group) print(group.entries) entry_list = [] for entry in group.entries: entry_list.append( Entry(group, entry.title, entry.username, entry.password, entry.url, entry.notes, entry.icon)) return entry_list def get_groups(self): group_list = [] groups = self.kp.groups for group in groups: if group.path != "/": group_list.append( Group(group.name, group.path, icon=group.icon, notes="", parent_group=group.parent_group)) return group_list #we wanted to turn off the automatic saving after each action and connect it instead to a button def save(self): self.kp.save() #this method sets the initial password for the newly created database def set_database_password(self, new_password): self.kp.set_credentials(new_password) self.save() #this method changes the password of existing database (therefore the old password must be typed in to prevent others changing your password) def change_database_password(self, old_password, new_password): if self.password == old_password: self.kp.set_credentials(new_password) self.save() # # Return the database filesystem path # def get_database(self): print(self.database_path) return self.database_path # # Return the root group of the database instance # def get_root_group(self): return self.kp.root_group # # Set the first password entered by the user (for comparing reasons) # def set_password_try(self, password): self.password_try = password # # Set the second password entered by the user (for comparing reasons) # def set_password_check(self, password): self.password_check = password # # Compare the first password entered by the user with the second one # def compare_passwords(self): if self.password_try == self.password_check: if self.password_try == "" and self.password_check == "": return False else: return True else: return False
class KeeFinder(object): def __init__(self, db_path, db_pass, verbosity): self.db = PyKeePass(db_path, db_pass) self.verbosity = verbosity self.found_entries = list() def find(self, strings): if not isinstance(strings, list): raise TypeError("Passed value has to be list type") self.found_entries = self._find_entries(strings[-1]) if not self.found_entries: return if len(strings) > 1: self.found_entries = self._find_in_entries(self.found_entries, strings[:-1]) def print_found(self): if not self.found_entries: print('Nothing found') return for entr in self.found_entries: self._print_entry(entr, self.verbosity) def _find_entries(self, substring, glob=True): search_string = substring.lower() res = list() if glob: search_string = '.*%s.*' % search_string method_names = ['title', 'username', 'url', 'password', 'path'] for method_name in method_names: method = getattr(self.db, 'find_entries_by_%s' % method_name) results = method(search_string, regex=True, flags='i') for result in results: if result not in res: res.append(result) root_group = self.db.find_groups_by_path('/') res_groups = list() # Now any group in res_groups will have a substring in path self._find_groups(substring, root_group, res_groups) for grp in res_groups: # As group has substring in path, it means any entry in this group # will have this substring in path too. There is no other way to do # this, sorry group_entries = self.db.find_entries_by_title('.*', regex=True, group=grp) for entr in group_entries: if entr not in res: res.append(entr) return res def _find_in_entries(self, entries, entry_names): survivors = entries.copy() while entry_names: entry_name = entry_names.pop() for index, entr in enumerate(entries): if not self._find_in_entry(entry_name, entr): survivors.remove(entr) survivors = self._find_in_entries(survivors, entry_names) return survivors def _find_in_entry(self, substring, entr): substring = substring.lower() if isinstance(entr, entry.Entry): subentries = [ entr.group.path, entr.title, entr.username, entr.password, entr.url ] elif isinstance(entr, group.Group): subentries = [entr.path] for subentry in subentries: if subentry and (substring in subentry.lower()): return True return False def _find_groups(self, name, root_groups, result=[]): for grp in root_groups: if name.lower() in grp.path.lower(): result.append(grp) subgroups = grp.subgroups self._find_groups(name, subgroups, result) def _print_entry(self, entr, verbosity): info = dict() def _get_fields(count): _info = dict() fields = ('group', 'username', 'password', 'title', 'url') if count == 2: fields = fields[:3] for field in fields: if field == 'group': _info[field] = entr.group.path else: _info[field] = getattr(entr, field) return _info if not verbosity: print(entr.password) elif verbosity == 1: print("%s - %s" % (entr.group.path, entr.username), file=sys.stderr) print(entr.password, end="") sys.stdout.flush() print("", file=sys.stderr) else: info = _get_fields(verbosity) if info: pprint.pprint(info) print()