diff --git a/app/src/main/java/com/bitchat/android/services/ConversationRepository.kt b/app/src/main/java/com/bitchat/android/services/ConversationRepository.kt index 84420ec0..bc474158 100644 --- a/app/src/main/java/com/bitchat/android/services/ConversationRepository.kt +++ b/app/src/main/java/com/bitchat/android/services/ConversationRepository.kt @@ -317,6 +317,7 @@ class ConversationRepository internal constructor( true } catch (error: Exception) { Log.e(TAG, "Unable to synchronously clear private conversations", error) + database.destroyStorage() _storeState.value = ConversationStoreState.Error( error.message ?: "Unable to erase conversations" ) @@ -1097,6 +1098,22 @@ internal class ConversationDatabase( writableDatabase.rawQuery("PRAGMA incremental_vacuum", null).use { } } + /** + * Last-resort panic cleanup when [clearAll] throws: drop the encrypted database + * files so a later reload cannot resurrect erased conversations (#699). + */ + fun destroyStorage() { + try { + clearAll() + } catch (error: Exception) { + Log.e(TAG, "clearAll failed during destroyStorage; deleting database files", error) + } + try { + close() + } catch (_: Exception) { } + applicationContext.deleteDatabase(databaseName) + } + fun pruneToRetentionLimits(): Set { val db = writableDatabase val orphanedMediaPaths = linkedSetOf() diff --git a/app/src/test/kotlin/com/bitchat/android/services/ConversationDatabaseTest.kt b/app/src/test/kotlin/com/bitchat/android/services/ConversationDatabaseTest.kt index 9a01ef37..65f484a8 100644 --- a/app/src/test/kotlin/com/bitchat/android/services/ConversationDatabaseTest.kt +++ b/app/src/test/kotlin/com/bitchat/android/services/ConversationDatabaseTest.kt @@ -433,6 +433,22 @@ class ConversationDatabaseTest { } } + @Test + fun `destroy storage deletes database files so history cannot reload`() { + database.upsertMessage( + "contact_alice", + setOf("contact_alice"), + "alice", + message("survives-failure", "alice", 1L), + true + ) + assertTrue(context.databaseList().contains(databaseName)) + + database.destroyStorage() + + assertFalse(context.databaseList().contains(databaseName)) + } + @Test fun `version one plaintext database migrates without losing history`() { database.close()