def create_test_db(): passfile = PassSafeFile() passfile.new_db('pasaffe') entries, empty_folders = get_test_data() for entry in entries: uuid = passfile.new_entry() for key in entry.keys(): passfile.records[uuid][key] = entry[key] for folder in empty_folders: passfile.add_empty_folder(folder) return passfile
class TestReadDB(unittest.TestCase): def setUp(self): self.passfile = PassSafeFile() def test_folder_list_to_field(self): folder_list = [ [[], ""], [["foldera"], "foldera"], [["folder.a"], "folder\.a"], # noqa: W605 [["foldera."], "foldera\."], # noqa: W605 [[".foldera"], "\.foldera"], # noqa: W605 [["foldera.", "folderb."], "foldera\..folderb\."], # noqa: W605 [["foldera", "folderb"], "foldera.folderb"], [["folder.a", "folderb"], "folder\.a.folderb"], # noqa: W605 [["foldera", "folder.b"], "foldera.folder\.b"], [["folder.a", "folder.b"], "folder\.a.folder\.b"], [["folder.a", "folder.b", "folder.c"], "folder\.a.folder\.b.folder\.c"], [["", "foldera", "folderb"], ".foldera.folderb"], [["", "", "folderb"], "..folderb"], [["foldera", "", "folderb"], "foldera..folderb"], [["foldera", "folderb", ""], "foldera.folderb."], ] for (folder, field) in folder_list: self.assertEqual(self.passfile._folder_list_to_field(folder), field) def test_field_to_folder_list(self): folder_list = [ ["", []], ["foldera", ["foldera"]], ["folder\.a", ["folder.a"]], # noqa: W605 ["foldera\.", ["foldera."]], # noqa: W605 ["\.foldera", [".foldera"]], # noqa: W605 ["foldera\..folderb\.", ["foldera.", "folderb."]], # noqa: W605 ["foldera.folderb", ["foldera", "folderb"]], ["folder\.a.folderb", ["folder.a", "folderb"]], ["foldera.folder\.b", ["foldera", "folder.b"]], ["folder\.a.folder\.b", ["folder.a", "folder.b"]], [ "folder\.a.folder\.b.folder\.c", ["folder.a", "folder.b", "folder.c"] ], [".foldera.folderb", ["", "foldera", "folderb"]], ["..folderb", ["", "", "folderb"]], ["foldera..folderb", ["foldera", "", "folderb"]], ["foldera.folderb.", ["foldera", "folderb", ""]], ] for (field, folder) in folder_list: self.assertEqual(self.passfile._field_to_folder_list(field), folder) def test_get_database_version_string(self): self.passfile.new_db("test") expected = '%s.%s' % (hexlify(self.passfile.db_version[1:2]).decode( 'utf-8'), hexlify(self.passfile.db_version[0:1]).decode('utf-8')) self.assertEqual(self.passfile.get_database_version_string(), expected) self.passfile.header[0] = b'\x0B\x03' self.assertEqual(self.passfile.get_database_version_string(), "03.0b") def test_new_entry(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() self.assertEqual(len(uuid_hex), 32) self.assertTrue(uuid_hex in self.passfile.records) for field in [1, 3, 4, 5, 6, 7, 8, 12, 13]: self.assertTrue(field in self.passfile.records[uuid_hex]) def test_delete_entry(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() self.assertTrue(uuid_hex in self.passfile.records) self.passfile.delete_entry(uuid_hex) self.assertTrue(uuid_hex not in self.passfile.records) def test_update_modification_time(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() old_time = self.passfile.records[uuid_hex][12] time.sleep(1.1) self.passfile.update_modification_time(uuid_hex) new_time = self.passfile.records[uuid_hex][12] self.assertTrue(old_time != new_time) def test_update_password_time(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() old_time = self.passfile.records[uuid_hex][8] time.sleep(1.1) self.passfile.update_password_time(uuid_hex) new_time = self.passfile.records[uuid_hex][8] self.assertTrue(old_time != new_time) def test_get_title(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() test_title = "Test title" self.passfile.records[uuid_hex][3] = test_title title = self.passfile.get_title(uuid_hex) self.assertTrue(title == test_title) def test_get_username(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() test_username = "******" self.passfile.records[uuid_hex][4] = test_username username = self.passfile.get_username(uuid_hex) self.assertTrue(username == test_username) def test_get_notes(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() test_note = "This is a note." self.passfile.records[uuid_hex][5] = test_note note = self.passfile.get_notes(uuid_hex) self.assertTrue(note == test_note) def test_get_password(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() test_password = "******" self.passfile.records[uuid_hex][6] = test_password password = self.passfile.get_password(uuid_hex) self.assertTrue(password == test_password) def test_get_url(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() test_url = "http://www.example.com" self.passfile.records[uuid_hex][13] = test_url url = self.passfile.get_url(uuid_hex) self.assertTrue(url == test_url) def test_update_folder_list(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() self.assertTrue(2 not in self.passfile.records[uuid_hex]) folder = ['folderA', 'folderB', 'folderC'] folder_field = 'folderA.folderB.folderC' self.passfile.update_folder_list(uuid_hex, folder) self.assertTrue(2 in self.passfile.records[uuid_hex]) self.assertTrue(self.passfile.records[uuid_hex][2] == folder_field) self.passfile.update_folder_list(uuid_hex, []) self.assertTrue(2 not in self.passfile.records[uuid_hex]) def test_get_folder_list(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() self.assertTrue(2 not in self.passfile.records[uuid_hex]) self.assertTrue(self.passfile.get_folder_list(uuid_hex) == []) folder = ['folderA', 'folderB', 'folderC'] folder_field = 'folderA.folderB.folderC' self.passfile.update_folder_list(uuid_hex, folder) self.assertTrue(2 in self.passfile.records[uuid_hex]) self.assertTrue(self.passfile.records[uuid_hex][2] == folder_field) self.assertTrue(self.passfile.get_folder_list(uuid_hex) == folder) self.assertTrue(self.passfile.get_folder_list('nonexistent') == []) def test_get_empty_folders(self): folder_fields = [ 'folderA', 'folderA.folderB', 'folderA.folderB.folderC' ] folder_list = [['folderA'], ['folderA', 'folderB'], ['folderA', 'folderB', 'folderC']] self.assertTrue(self.passfile.get_empty_folders() == []) self.passfile.empty_folders = folder_fields self.assertTrue(self.passfile.get_empty_folders() == folder_list) def test_add_empty_folder(self): folder_fields = [ 'folderA', 'folderA.folderB', 'folderA.folderB.folderC' ] folder = ['folderA', 'folderB', 'folderC'] # Make sure it's empty self.assertTrue(self.passfile.empty_folders == []) # Add a folder, and make sure it created the children self.passfile.add_empty_folder(folder) self.assertTrue(self.passfile.empty_folders == folder_fields) # Make sure empty parameters work self.passfile.add_empty_folder(None) self.assertTrue(self.passfile.empty_folders == folder_fields) self.passfile.add_empty_folder([]) self.assertTrue(self.passfile.empty_folders == folder_fields) # Try adding it again, to make sure we don't have duplicates self.passfile.add_empty_folder(folder) self.assertTrue(self.passfile.empty_folders == folder_fields) # Make sure adding an empty folder that isn't actually empty # works uuid_hex = self.passfile.new_entry() entry_folder = ['otherA'] self.passfile.update_folder_list(uuid_hex, entry_folder) self.passfile.add_empty_folder(entry_folder) self.assertTrue(self.passfile.empty_folders == folder_fields) # Adding an empty folder that only has an empty subfolder should # only add the subfolder uuid_hex = self.passfile.new_entry() entry_folder = ['thirdA', 'thirdB'] self.passfile.update_folder_list(uuid_hex, entry_folder) self.passfile.add_empty_folder(entry_folder) folder_fields.append('thirdA') self.assertTrue(self.passfile.empty_folders == folder_fields) # Do the same, but for 3 levels uuid_hex = self.passfile.new_entry() entry_folder = ['fourthA', 'fourthB', 'fourthC'] self.passfile.update_folder_list(uuid_hex, entry_folder) self.passfile.add_empty_folder(entry_folder) folder_fields.append('fourthA') folder_fields.append('fourthA.fourthB') self.assertTrue(self.passfile.empty_folders == folder_fields) def test_remove_empty_folder(self): folder_fields = [ 'folderA', 'folderA.folderB', 'folderA.folderB.folderC' ] # pass by value self.passfile.empty_folders = folder_fields[:] # Try and remove a bogus folder self.passfile.remove_empty_folder(['bogus']) self.assertTrue(self.passfile.empty_folders == folder_fields) # Make sure empty parameters work self.passfile.remove_empty_folder(None) self.assertTrue(self.passfile.empty_folders == folder_fields) self.passfile.remove_empty_folder([]) self.assertTrue(self.passfile.empty_folders == folder_fields) # Now, remove an empty folder self.passfile.remove_empty_folder(['folderA', 'folderB']) folder_fields.remove('folderA.folderB') self.assertTrue(self.passfile.empty_folders == folder_fields) def test_get_all_folders(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() # First make sure there's no folders at all self.assertTrue(self.passfile.get_all_folders() == []) # Now handle an entry, but no empty folders folder = ['folderA', 'folderB'] self.passfile.update_folder_list(uuid_hex, folder) self.assertTrue(self.passfile.get_all_folders() == [folder]) # Now handle empty folders, but no entry self.passfile.update_folder_list(uuid_hex, []) self.assertTrue(self.passfile.get_all_folders() == []) folder_fields = [ 'folderA', 'folderA.folderB', 'folderA.folderB.folderC' ] self.passfile.empty_folders = folder_fields folder_list = [['folderA'], ['folderA', 'folderB'], ['folderA', 'folderB', 'folderC']] self.assertTrue(self.passfile.get_all_folders() == folder_list) # Now handle multiple entries, and empty folders self.passfile.update_folder_list(uuid_hex, folder) folderB = ['OtherFolderA', 'OtherFolderB'] uuid_hex_B = self.passfile.new_entry() self.passfile.new_entry() self.passfile.update_folder_list(uuid_hex_B, folderB) all_folders = folder_list + [folderB] self.assertTrue(self.passfile.get_all_folders() == all_folders) def test_rename_folder_list(self): self.passfile.new_db("test") # Create a few entries folderA = ['firstA', 'firstB'] folderB = ['firstA', 'firstB', 'firstC'] folderC = ['secondA', 'secondB'] uuid_hex_A = self.passfile.new_entry() uuid_hex_B = self.passfile.new_entry() uuid_hex_C = self.passfile.new_entry() uuid_hex_D = self.passfile.new_entry() self.passfile.update_folder_list(uuid_hex_A, folderA) self.passfile.update_folder_list(uuid_hex_B, folderB) self.passfile.update_folder_list(uuid_hex_C, folderC) self.assertTrue(self.passfile.get_folder_list(uuid_hex_A) == folderA) self.assertTrue(self.passfile.get_folder_list(uuid_hex_B) == folderB) self.assertTrue(self.passfile.get_folder_list(uuid_hex_C) == folderC) self.assertTrue(self.passfile.get_folder_list(uuid_hex_D) == []) # Ok, let's rename one new_folderA = ['firstA', 'renamedB'] new_folderB = ['firstA', 'renamedB', 'firstC'] self.passfile.rename_folder_list(folderA, new_folderA) self.assertTrue( self.passfile.get_folder_list(uuid_hex_A) == new_folderA) self.assertTrue( self.passfile.get_folder_list(uuid_hex_B) == new_folderB) self.assertTrue(self.passfile.get_folder_list(uuid_hex_C) == folderC) self.assertTrue(self.passfile.get_folder_list(uuid_hex_D) == []) # Now add some empty_folders folder_fields = ['firstA', 'secondA', 'thirdA', 'thirdA.thirdB'] # pass by value self.passfile.empty_folders = folder_fields[:] # OK, rename entries and empty_folders another_new_folderA = ['renamedA', 'renamedB'] another_new_folderB = ['renamedA', 'renamedB', 'firstC'] new_empty_folders = [['secondA'], ['thirdA'], ['thirdA', 'thirdB'], ['renamedA']] self.passfile.rename_folder_list(['firstA'], ['renamedA']) self.assertTrue( self.passfile.get_folder_list(uuid_hex_A) == another_new_folderA) self.assertTrue( self.passfile.get_folder_list(uuid_hex_B) == another_new_folderB) self.assertTrue(self.passfile.get_folder_list(uuid_hex_C) == folderC) self.assertTrue(self.passfile.get_folder_list(uuid_hex_D) == []) self.assertTrue(self.passfile.get_empty_folders() == new_empty_folders) def test_delete_folder(self): self.passfile.new_db("test") # Create a few entries folderA = ['firstA', 'firstB'] folderB = ['firstA', 'firstB', 'firstC'] folderC = ['secondA', 'secondB'] uuid_hex_A = self.passfile.new_entry() uuid_hex_B = self.passfile.new_entry() uuid_hex_C = self.passfile.new_entry() uuid_hex_D = self.passfile.new_entry() self.passfile.update_folder_list(uuid_hex_A, folderA) self.passfile.update_folder_list(uuid_hex_B, folderB) self.passfile.update_folder_list(uuid_hex_C, folderC) self.assertTrue(self.passfile.get_folder_list(uuid_hex_A) == folderA) self.assertTrue(self.passfile.get_folder_list(uuid_hex_B) == folderB) self.assertTrue(self.passfile.get_folder_list(uuid_hex_C) == folderC) self.assertTrue(self.passfile.get_folder_list(uuid_hex_D) == []) self.assertTrue(self.passfile.get_empty_folders() == []) # Try and delete some invalid things self.passfile.delete_folder(None) self.passfile.delete_folder([]) self.passfile.delete_folder(['banana']) self.assertTrue(self.passfile.get_folder_list(uuid_hex_A) == folderA) self.assertTrue(self.passfile.get_folder_list(uuid_hex_B) == folderB) self.assertTrue(self.passfile.get_folder_list(uuid_hex_C) == folderC) self.assertTrue(self.passfile.get_folder_list(uuid_hex_D) == []) self.assertTrue(self.passfile.get_empty_folders() == []) # Now, delete a third level. self.passfile.delete_folder(folderB) self.assertTrue(self.passfile.get_folder_list(uuid_hex_A) == folderA) self.assertTrue(uuid_hex_B not in self.passfile.records) self.assertTrue(self.passfile.get_folder_list(uuid_hex_C) == folderC) self.assertTrue(self.passfile.get_folder_list(uuid_hex_D) == []) self.assertTrue(uuid_hex_D in self.passfile.records) self.assertTrue(self.passfile.get_empty_folders() == []) # Add some empty_folders and delete a toplevel emptyA = [['firstA'], ['firstA', 'firstB', 'emptyC']] emptyB = emptyA + [['some'], ['some', 'random']] for folder in emptyB: self.passfile.add_empty_folder(folder) self.assertTrue(self.passfile.get_empty_folders() == emptyB) self.passfile.delete_folder(['some']) self.assertTrue(self.passfile.get_empty_folders() == emptyA) self.assertTrue(self.passfile.get_folder_list(uuid_hex_A) == folderA) self.assertTrue(self.passfile.get_folder_list(uuid_hex_C) == folderC) self.assertTrue(self.passfile.get_folder_list(uuid_hex_D) == []) self.assertTrue(uuid_hex_D in self.passfile.records) # Now delete a top level self.passfile.delete_folder(['firstA']) self.assertTrue(self.passfile.get_empty_folders() == []) self.assertTrue(uuid_hex_A not in self.passfile.records) self.assertTrue(self.passfile.get_folder_list(uuid_hex_C) == folderC) self.assertTrue(self.passfile.get_folder_list(uuid_hex_D) == []) self.assertTrue(uuid_hex_D in self.passfile.records) # Delete the remaining second level. We should gain an empty folder. self.passfile.delete_folder(['secondA', 'secondB']) self.assertTrue(uuid_hex_C not in self.passfile.records) self.assertTrue(self.passfile.get_folder_list(uuid_hex_D) == []) self.assertTrue(uuid_hex_D in self.passfile.records) self.assertTrue(self.passfile.get_empty_folders() == [['secondA']]) def test_get_tree_status(self): self.passfile.new_db("test") self.assertEqual(self.passfile.get_tree_status(), None) self.passfile.header[6] = "Pasaffe test" self.assertEqual(self.passfile.get_tree_status(), None) self.passfile.header[3] = "101010" self.assertEqual(self.passfile.get_tree_status(), "101010") self.passfile.header[6] = "AnotherApp v1" self.assertEqual(self.passfile.get_tree_status(), None) def test_set_tree_status(self): self.passfile.new_db("test") self.passfile.header[6] = "Pasaffe test" self.assertEqual(self.passfile.get_tree_status(), None) self.passfile.set_tree_status("101010") self.assertEqual(self.passfile.get_tree_status(), "101010") self.assertTrue(3 in self.passfile.header) self.passfile.set_tree_status(None) self.assertEqual(self.passfile.get_tree_status(), None) self.assertFalse(3 in self.passfile.header) def test_fixups(self): self.passfile.new_db("test") uuid_hex = self.passfile.new_entry() # New entry should have empty strings self.assertEqual(self.passfile.records[uuid_hex][3], '') self.assertEqual(self.passfile.records[uuid_hex][4], '') self.assertEqual(self.passfile.records[uuid_hex][5], '') self.assertEqual(self.passfile.records[uuid_hex][6], '') # Delete title, username and password del self.passfile.records[uuid_hex][3] del self.passfile.records[uuid_hex][4] del self.passfile.records[uuid_hex][6] # add a comment with CRLF terminators crlf = ("First line\r\n" + "Second line\r\n" + "Third line") lf = ("First line\n" + "Second line\n" + "Third line") self.passfile.records[uuid_hex][5] = crlf self.assertTrue(3 not in self.passfile.records[uuid_hex]) self.assertTrue(4 not in self.passfile.records[uuid_hex]) self.assertTrue(6 not in self.passfile.records[uuid_hex]) self.assertEqual(self.passfile.records[uuid_hex][5], crlf) # Now do the postread fixup self.passfile._postread_fixup() self.assertEqual(self.passfile.records[uuid_hex][3], '') self.assertEqual(self.passfile.records[uuid_hex][4], '') self.assertEqual(self.passfile.records[uuid_hex][5], lf) self.assertEqual(self.passfile.records[uuid_hex][6], '') # OK, do the presave fixup self.assertEqual(self.passfile._presave_fixup(uuid_hex, 5), crlf) def _create_find_db(self): entries = [{ 3: "carte de crédit", 4: "username1", 5: "This is a note", 6: "password1", 13: "http://www.example.com" }, { 2: "folder1", 3: "carte de credit", 4: "username1", 5: "anothernote", 6: "password1" }, { 2: "level1group.level2group.level3group", 3: "level3entry", 4: "usernamelevel3", 6: "passwordlevel3", 13: "http://note.com" }] self.passfile.new_db('pasaffe') for entry in entries: uuid = self.passfile.new_entry() for key in entry.keys(): self.passfile.records[uuid][key] = entry[key] def test_update_find_results(self): self._create_find_db() self.passfile.update_find_results("") self.assertEqual(self.passfile.find_results, []) self.assertEqual(self.passfile.find_results_index, None) self.assertEqual(self.passfile.find_value, "") # Test field 3 self.passfile.update_find_results("level3entry") self.assertEqual(len(self.passfile.find_results), 1) self.assertEqual(self.passfile.find_results_index, None) self.assertEqual(self.passfile.find_value, "level3entry") # Test field 5 self.passfile.update_find_results("another") self.assertEqual(len(self.passfile.find_results), 1) self.assertEqual(self.passfile.find_results_index, None) self.assertEqual(self.passfile.find_value, "another") # Test field 13 self.passfile.update_find_results("example.com") self.assertEqual(len(self.passfile.find_results), 1) self.assertEqual(self.passfile.find_results_index, None) self.assertEqual(self.passfile.find_value, "example.com") # Test matching entries with accents self.passfile.update_find_results("credit") self.assertEqual(len(self.passfile.find_results), 2) self.assertEqual(self.passfile.find_results_index, None) self.assertEqual(self.passfile.find_value, "credit") # Test specifying search term with accent self.passfile.update_find_results("crédit") self.assertEqual(len(self.passfile.find_results), 2) self.assertEqual(self.passfile.find_results_index, None) self.assertEqual(self.passfile.find_value, "crédit") # Test force option self.passfile.find_results = [] self.passfile.update_find_results("crédit") self.assertEqual(len(self.passfile.find_results), 0) self.passfile.update_find_results("crédit", True) self.assertEqual(len(self.passfile.find_results), 2) # Test clearing out values self.passfile.update_find_results("") self.assertEqual(self.passfile.find_results, []) self.assertEqual(self.passfile.find_results_index, None) self.assertEqual(self.passfile.find_value, "") def test_get_next_find_result(self): self._create_find_db() self.assertEqual(self.passfile.get_next_find_result(), None) self.assertEqual(self.passfile.get_next_find_result(True), None) self.passfile.update_find_results("note") self.assertEqual(len(self.passfile.find_results), 3) self.assertEqual(self.passfile.find_results_index, None) self.assertEqual(self.passfile.find_value, "note") self.assertEqual(self.passfile.find_results_index, None) uuid1 = self.passfile.get_next_find_result() self.assertEqual(self.passfile.find_results_index, 0) self.assertNotEqual(uuid1, None) uuid2 = self.passfile.get_next_find_result() self.assertEqual(self.passfile.find_results_index, 1) self.assertNotEqual(uuid2, None) self.assertNotEqual(uuid1, uuid2) uuid3 = self.passfile.get_next_find_result() self.assertEqual(self.passfile.find_results_index, 2) self.assertNotEqual(uuid3, None) self.assertNotEqual(uuid1, uuid3) self.assertNotEqual(uuid2, uuid3) # This should wrap around uuid4 = self.passfile.get_next_find_result() self.assertEqual(self.passfile.find_results_index, 0) self.assertNotEqual(uuid4, None) self.assertEqual(uuid1, uuid4) # And now try backwards uuid5 = self.passfile.get_next_find_result(True) self.assertEqual(self.passfile.find_results_index, 2) self.assertNotEqual(uuid5, None) self.assertEqual(uuid3, uuid5)