mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 09:25:19 +00:00
fix(security): Clear in-memory keys during panic mode (#596)
* fix(security): Clear in-memory keys during panic mode #588 * feat: Recreate mesh service after panic clear (#602) * feat: Recreate mesh service after panic clear This commit refactors the panic clear process to ensure a new mesh identity is immediately created and applied. Previously, the `ChatViewModel` would clear sensitive data, but the recreation of the `BluetoothMeshService` was handled externally. This could lead to a delay or failure in adopting the new identity. Key changes: - Introduces `MeshServiceHolder` to manage the lifecycle of the `BluetoothMeshService` instance. - Adds `recreateMeshServiceAfterPanic()` to `ChatViewModel`, which now explicitly clears the old service instance and creates a new one with a regenerated identity. - The `meshService` property in `ChatViewModel` is now a `var` to allow it to be replaced with the fresh instance post-panic. - The new service is started, and a broadcast announcement is sent immediately, ensuring the new peer ID is used on the network. * fix: Ensure mesh service is properly managed in foreground service * refactor: Decouple handlers from direct service reference This commit updates the `VerificationHandler` and `MediaSendingManager` to receive the `meshService` via a lambda function (`getMeshService`) instead of a direct reference. This change decouples the handlers from the service instance, preventing them from holding a stale reference if the service reconnects or changes. By invoking the lambda to get the current service instance when needed, it ensures they always interact with the active `meshService`. * fix: restart bluetooth --------- Co-authored-by: Moe Hamade <69801237+moehamade@users.noreply.github.com>
This commit is contained in:
@@ -11,6 +11,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import com.bitchat.android.mesh.BluetoothMeshDelegate
|
||||
import com.bitchat.android.mesh.BluetoothMeshService
|
||||
import com.bitchat.android.service.MeshServiceHolder
|
||||
import com.bitchat.android.model.BitchatMessage
|
||||
import com.bitchat.android.model.BitchatMessageType
|
||||
import com.bitchat.android.nostr.NostrIdentityBridge
|
||||
@@ -37,8 +38,12 @@ import java.security.MessageDigest
|
||||
*/
|
||||
class ChatViewModel(
|
||||
application: Application,
|
||||
val meshService: BluetoothMeshService
|
||||
initialMeshService: BluetoothMeshService
|
||||
) : AndroidViewModel(application), BluetoothMeshDelegate {
|
||||
|
||||
// Made var to support mesh service replacement after panic clear
|
||||
var meshService: BluetoothMeshService = initialMeshService
|
||||
private set
|
||||
private val debugManager by lazy { try { com.bitchat.android.ui.debug.DebugSettingsManager.getInstance() } catch (e: Exception) { null } }
|
||||
|
||||
companion object {
|
||||
@@ -104,7 +109,7 @@ class ChatViewModel(
|
||||
private val verificationHandler = VerificationHandler(
|
||||
context = application.applicationContext,
|
||||
scope = viewModelScope,
|
||||
meshService = meshService,
|
||||
getMeshService = { meshService },
|
||||
identityManager = identityManager,
|
||||
state = state,
|
||||
notificationManager = notificationManager,
|
||||
@@ -113,7 +118,7 @@ class ChatViewModel(
|
||||
val verifiedFingerprints = verificationHandler.verifiedFingerprints
|
||||
|
||||
// Media file sending manager
|
||||
private val mediaSendingManager = MediaSendingManager(state, messageManager, channelManager, meshService)
|
||||
private val mediaSendingManager = MediaSendingManager(state, messageManager, channelManager) { meshService }
|
||||
|
||||
// Delegate handler for mesh callbacks
|
||||
private val meshDelegateHandler = MeshDelegateHandler(
|
||||
@@ -908,6 +913,11 @@ class ChatViewModel(
|
||||
privateChatManager.clearAllPrivateChats()
|
||||
dataManager.clearAllData()
|
||||
|
||||
// Clear seen message store
|
||||
try {
|
||||
com.bitchat.android.services.SeenMessageStore.getInstance(getApplication()).clear()
|
||||
} catch (_: Exception) { }
|
||||
|
||||
// Clear all mesh service data
|
||||
clearAllMeshServiceData()
|
||||
|
||||
@@ -935,10 +945,37 @@ class ChatViewModel(
|
||||
state.setNickname(newNickname)
|
||||
dataManager.saveNickname(newNickname)
|
||||
|
||||
Log.w(TAG, "🚨 PANIC MODE COMPLETED - All sensitive data cleared")
|
||||
|
||||
// Note: Mesh service restart is now handled by MainActivity
|
||||
// This method now only clears data, not mesh service lifecycle
|
||||
// Recreate mesh service with fresh identity
|
||||
recreateMeshServiceAfterPanic()
|
||||
|
||||
Log.w(TAG, "🚨 PANIC MODE COMPLETED - New identity: ${meshService.myPeerID}")
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreate the mesh service with a fresh identity after panic clear.
|
||||
* This ensures the new cryptographic keys are used for a new peer ID.
|
||||
*/
|
||||
private fun recreateMeshServiceAfterPanic() {
|
||||
val oldPeerID = meshService.myPeerID
|
||||
|
||||
// Clear the holder so getOrCreate() returns a fresh instance
|
||||
MeshServiceHolder.clear()
|
||||
|
||||
// Create fresh mesh service with new identity (keys were regenerated in clearAllCryptographicData)
|
||||
val freshMeshService = MeshServiceHolder.getOrCreate(getApplication())
|
||||
|
||||
// Replace our reference and set up the new service
|
||||
meshService = freshMeshService
|
||||
meshService.delegate = this
|
||||
|
||||
// Restart mesh operations with new identity
|
||||
meshService.startServices()
|
||||
meshService.sendBroadcastAnnounce()
|
||||
|
||||
Log.d(
|
||||
TAG,
|
||||
"✅ Mesh service recreated. Old peerID: $oldPeerID, New peerID: ${meshService.myPeerID}"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,8 +16,11 @@ class MediaSendingManager(
|
||||
private val state: ChatState,
|
||||
private val messageManager: MessageManager,
|
||||
private val channelManager: ChannelManager,
|
||||
private val meshService: BluetoothMeshService
|
||||
private val getMeshService: () -> BluetoothMeshService
|
||||
) {
|
||||
// Helper to get current mesh service (may change after panic clear)
|
||||
private val meshService: BluetoothMeshService
|
||||
get() = getMeshService()
|
||||
companion object {
|
||||
private const val TAG = "MediaSendingManager"
|
||||
private const val MAX_FILE_SIZE = com.bitchat.android.util.AppConstants.Media.MAX_FILE_SIZE_BYTES // 50MB limit
|
||||
|
||||
@@ -26,12 +26,15 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
class VerificationHandler(
|
||||
private val context: Context,
|
||||
private val scope: CoroutineScope,
|
||||
private val meshService: BluetoothMeshService,
|
||||
private val getMeshService: () -> BluetoothMeshService,
|
||||
private val identityManager: SecureIdentityStateManager,
|
||||
private val state: ChatState,
|
||||
private val notificationManager: NotificationManager,
|
||||
private val messageManager: MessageManager
|
||||
) {
|
||||
// Helper to get current mesh service (may change after panic clear)
|
||||
private val meshService: BluetoothMeshService
|
||||
get() = getMeshService()
|
||||
|
||||
private val _verifiedFingerprints = MutableStateFlow<Set<String>>(emptySet())
|
||||
val verifiedFingerprints: StateFlow<Set<String>> = _verifiedFingerprints.asStateFlow()
|
||||
|
||||
Reference in New Issue
Block a user