diff --git a/src/password_manager/manager.py b/src/password_manager/manager.py index 2054dab..78f853a 100644 --- a/src/password_manager/manager.py +++ b/src/password_manager/manager.py @@ -908,11 +908,59 @@ class PasswordManager: print(colored(f"Entry updated successfully for index {index}.", "green")) + # Push the updated index to Nostr so changes are backed up. + try: + encrypted_data = self.get_encrypted_data() + if encrypted_data: + self.nostr_client.publish_json_to_nostr(encrypted_data) + logging.info( + "Encrypted index posted to Nostr after entry modification." + ) + except Exception as nostr_error: + logging.error(f"Failed to post updated index to Nostr: {nostr_error}") + logging.error(traceback.format_exc()) + except Exception as e: logging.error(f"Error during modifying entry: {e}") logging.error(traceback.format_exc()) print(colored(f"Error: Failed to modify entry: {e}", "red")) + def delete_entry(self) -> None: + """Deletes an entry from the password index.""" + try: + index_input = input( + "Enter the index number of the entry to delete: " + ).strip() + if not index_input.isdigit(): + print(colored("Error: Index must be a number.", "red")) + return + index_to_delete = int(index_input) + + if not confirm_action( + f"Are you sure you want to delete entry {index_to_delete}? (Y/N): " + ): + print(colored("Deletion cancelled.", "yellow")) + return + + self.entry_manager.delete_entry(index_to_delete) + + # Push updated index to Nostr after deletion + try: + encrypted_data = self.get_encrypted_data() + if encrypted_data: + self.nostr_client.publish_json_to_nostr(encrypted_data) + logging.info( + "Encrypted index posted to Nostr after entry deletion." + ) + except Exception as nostr_error: + logging.error(f"Failed to post updated index to Nostr: {nostr_error}") + logging.error(traceback.format_exc()) + + except Exception as e: + logging.error(f"Error during entry deletion: {e}") + logging.error(traceback.format_exc()) + print(colored(f"Error: Failed to delete entry: {e}", "red")) + def handle_verify_checksum(self) -> None: """ Handles verifying the script's checksum against the stored checksum to ensure integrity. @@ -1203,18 +1251,9 @@ class PasswordManager: print(colored("Master password changed successfully.", "green")) - # Automatically push the newly re-encrypted index to Nostr so the - # latest state is backed up remotely after a password change. - try: - encrypted_data = self.get_encrypted_data() - if encrypted_data: - self.nostr_client.publish_json_to_nostr(encrypted_data) - logging.info( - "Encrypted index posted to Nostr after password change." - ) - except Exception as nostr_error: - logging.error(f"Failed to post updated index to Nostr: {nostr_error}") - logging.error(traceback.format_exc()) + # All data has been re-encrypted with the new password. Since no + # entries changed, avoid pushing the database to Nostr here. + # Subsequent entry modifications will trigger a push when needed. except Exception as e: logging.error(f"Failed to change password: {e}") logging.error(traceback.format_exc()) diff --git a/src/tests/test_password_change.py b/src/tests/test_password_change.py index 12efc66..9de4436 100644 --- a/src/tests/test_password_change.py +++ b/src/tests/test_password_change.py @@ -14,7 +14,7 @@ from password_manager.config_manager import ConfigManager from password_manager.manager import PasswordManager -def test_change_password_triggers_nostr_backup(monkeypatch): +def test_change_password_does_not_trigger_nostr_backup(monkeypatch): with TemporaryDirectory() as tmpdir: fp = Path(tmpdir) enc_mgr = EncryptionManager(Fernet.generate_key(), fp) @@ -43,4 +43,4 @@ def test_change_password_triggers_nostr_backup(monkeypatch): mock_instance = MockClient.return_value pm.nostr_client = mock_instance pm.change_password() - mock_instance.publish_json_to_nostr.assert_called_once() + mock_instance.publish_json_to_nostr.assert_not_called()