diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/MessagesFetcherWorker.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/MessagesFetcherWorker.kt index 3b8902b58..0152f5e8c 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/MessagesFetcherWorker.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/MessagesFetcherWorker.kt @@ -3,11 +3,12 @@ package chat.simplex.app import android.content.Context import android.util.Log import androidx.work.* -import chat.simplex.app.* import chat.simplex.app.SimplexService.Companion.showPassphraseNotification import chat.simplex.common.model.ChatController import chat.simplex.common.views.helpers.DBMigrationResult -import chat.simplex.app.BuildConfig +import chat.simplex.common.platform.chatModel +import chat.simplex.common.platform.initChatControllerAndRunMigrations +import chat.simplex.common.views.helpers.DatabaseUtils import kotlinx.coroutines.* import java.util.Date import java.util.concurrent.TimeUnit @@ -57,6 +58,10 @@ class MessagesFetcherWork( val durationSeconds = inputData.getInt(INPUT_DATA_DURATION, 60) var shouldReschedule = true try { + // In case of self-destruct is enabled the initialization process will not start in SimplexApp, Let's start it here + if (DatabaseUtils.ksSelfDestructPassword.get() != null && chatModel.chatDbStatus.value == null) { + initChatControllerAndRunMigrations() + } withTimeout(durationSeconds * 1000L) { val chatController = ChatController SimplexService.waitDbMigrationEnds(chatController) diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt index 84b39e983..6273263f4 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexApp.kt @@ -26,6 +26,7 @@ import kotlinx.coroutines.sync.withLock import java.io.* import java.util.* import java.util.concurrent.TimeUnit +import kotlin.system.exitProcess const val TAG = "SIMPLEX" @@ -46,8 +47,8 @@ class SimplexApp: Application(), LifecycleEventObserver { try { Looper.loop() } catch (e: Throwable) { - if (e.message != null && e.message!!.startsWith("Unable to start activity")) { - android.os.Process.killProcess(android.os.Process.myPid()) + if (e is UnsatisfiedLinkError || e.message?.startsWith("Unable to start activity") == true) { + Process.killProcess(Process.myPid()) break } else { // Send it to our exception handled because it will not get the exception otherwise @@ -63,7 +64,9 @@ class SimplexApp: Application(), LifecycleEventObserver { tmpDir.deleteRecursively() tmpDir.mkdir() - initChatControllerAndRunMigrations(false) + if (DatabaseUtils.ksSelfDestructPassword.get() == null) { + initChatControllerAndRunMigrations() + } ProcessLifecycleOwner.get().lifecycle.addObserver(this@SimplexApp) } diff --git a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt index d1e0d9721..8dfe04b3d 100644 --- a/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt +++ b/apps/multiplatform/android/src/main/java/chat/simplex/app/SimplexService.kt @@ -72,6 +72,10 @@ class SimplexService: Service() { stopSelf() } else { isServiceStarted = true + // In case of self-destruct is enabled the initialization process will not start in SimplexApp, Let's start it here + if (DatabaseUtils.ksSelfDestructPassword.get() != null && chatModel.chatDbStatus.value == null) { + initChatControllerAndRunMigrations() + } } } diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt index 00a824438..8ed662ae6 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/platform/Core.kt @@ -41,21 +41,20 @@ val appPreferences: AppPreferences val chatController: ChatController = ChatController -fun initChatControllerAndRunMigrations(ignoreSelfDestruct: Boolean) { - if (ignoreSelfDestruct || DatabaseUtils.ksSelfDestructPassword.get() == null) { - withBGApi { - if (appPreferences.chatStopped.get() && appPreferences.storeDBPassphrase.get() && ksDatabasePassword.get() != null) { - initChatController(startChat = ::showStartChatAfterRestartAlert) - } else { - initChatController() - } - runMigrations() +fun initChatControllerAndRunMigrations() { + withBGApi { + if (appPreferences.chatStopped.get() && appPreferences.storeDBPassphrase.get() && ksDatabasePassword.get() != null) { + initChatController(startChat = ::showStartChatAfterRestartAlert) + } else { + initChatController() } + runMigrations() } } suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: () -> CompletableDeferred = { CompletableDeferred(true) }) { try { + if (chatModel.ctrlInitInProgress.value) return chatModel.ctrlInitInProgress.value = true val dbKey = useKey ?: DatabaseUtils.useDatabaseKey() val confirm = confirmMigrations ?: if (appPreferences.confirmDBUpgrades.get()) MigrationConfirmation.Error else MigrationConfirmation.YesUp diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt index 3769e0fc9..cc1953afc 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt @@ -460,10 +460,10 @@ suspend fun deleteChatAsync(m: ChatModel) { m.controller.apiDeleteStorage() DatabaseUtils.ksDatabasePassword.remove() m.controller.appPrefs.storeDBPassphrase.set(true) - deleteChatDatabaseFiles() + deleteAppDatabaseAndFiles() } -fun deleteChatDatabaseFiles() { +fun deleteAppDatabaseAndFiles() { val chat = File(dataDir, chatDatabaseFileName) val chatBak = File(dataDir, "$chatDatabaseFileName.bak") val agent = File(dataDir, agentDatabaseFileName) @@ -473,6 +473,7 @@ fun deleteChatDatabaseFiles() { agent.delete() agentBak.delete() filesDir.deleteRecursively() + filesDir.mkdir() remoteHostsDir.deleteRecursively() tmpDir.deleteRecursively() tmpDir.mkdir() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt index cc06716da..3ab74a6ad 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/DatabaseUtils.kt @@ -17,7 +17,7 @@ object DatabaseUtils { val ksAppPassword = KeyStoreItem(APP_PASSWORD_ALIAS, appPreferences.encryptedAppPassphrase, appPreferences.initializationVectorAppPassphrase) val ksSelfDestructPassword = KeyStoreItem(SELF_DESTRUCT_PASSWORD_ALIAS, appPreferences.encryptedSelfDestructPassphrase, appPreferences.initializationVectorSelfDestructPassphrase) - class KeyStoreItem(val alias: String, val passphrase: SharedPreference, val initVector: SharedPreference) { + class KeyStoreItem(private val alias: String, val passphrase: SharedPreference, val initVector: SharedPreference) { fun get(): String? { return cryptor.decryptData( passphrase.get()?.toByteArrayFromBase64ForPassphrase() ?: return null, diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt index b758ecdcf..16d8a34b1 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/LocalAuthView.kt @@ -34,7 +34,7 @@ fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) { } else { val r: LAResult = if (passcode.value == authRequest.password) { if (authRequest.selfDestruct && sdPassword != null && controller.ctrl == -1L) { - initChatControllerAndRunMigrations(true) + initChatControllerAndRunMigrations() } LAResult.Success } else { @@ -67,8 +67,8 @@ private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: ( * */ chatCloseStore(ctrl) } - deleteChatDatabaseFiles() - // Clear sensitive data on screen just in case ModalManager will fail to prevent hiding its modals while database encrypts itself + deleteAppDatabaseAndFiles() + // Clear sensitive data on screen just in case ModalManager fails to hide its modals while new database is created m.chatId.value = null m.chatItems.clear() m.chats.clear() diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt index eadd39942..1d620c915 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/localauth/SetAppPasscodeView.kt @@ -12,6 +12,7 @@ import chat.simplex.res.MR @Composable fun SetAppPasscodeView( passcodeKeychain: DatabaseUtils.KeyStoreItem = ksAppPassword, + prohibitedPasscodeKeychain: DatabaseUtils.KeyStoreItem = ksSelfDestructPassword, title: String = generalGetString(MR.strings.new_passcode), reason: String? = null, submit: () -> Unit, @@ -51,7 +52,7 @@ fun SetAppPasscodeView( } else { SetPasswordView(title, generalGetString(MR.strings.save_verb), // Do not allow to set app passcode == selfDestruct passcode - submitEnabled = { pwd -> pwd != (if (passcodeKeychain.alias == ksSelfDestructPassword.alias) ksAppPassword else ksSelfDestructPassword).get() }) { + submitEnabled = { pwd -> pwd != prohibitedPasscodeKeychain.get() }) { enteredPassword = passcode.value passcode.value = "" confirming = true diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt index 82196a9b6..f163a5464 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/PrivacySettings.kt @@ -454,6 +454,7 @@ fun SimplexLockView( Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { SetAppPasscodeView( passcodeKeychain = ksSelfDestructPassword, + prohibitedPasscodeKeychain = ksAppPassword, reason = generalGetString(MR.strings.self_destruct), submit = { selfDestructPasscodeAlert(generalGetString(MR.strings.self_destruct_passcode_changed)) @@ -600,7 +601,7 @@ private fun EnableSelfDestruct( ) { Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) { SetAppPasscodeView( - passcodeKeychain = ksSelfDestructPassword, title = generalGetString(MR.strings.set_passcode), reason = generalGetString(MR.strings.enabled_self_destruct_passcode), + passcodeKeychain = ksSelfDestructPassword, prohibitedPasscodeKeychain = ksAppPassword, title = generalGetString(MR.strings.set_passcode), reason = generalGetString(MR.strings.enabled_self_destruct_passcode), submit = { selfDestruct.set(true) selfDestructPasscodeAlert(generalGetString(MR.strings.self_destruct_passcode_enabled)) diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt index 4e70956be..9cf194398 100644 --- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt +++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/platform/AppCommon.desktop.kt @@ -24,7 +24,9 @@ fun initApp() { override fun cancelAllNotifications() = chat.simplex.common.model.NtfManager.cancelAllNotifications() } applyAppLocale() - initChatControllerAndRunMigrations(false) + if (DatabaseUtils.ksSelfDestructPassword.get() == null) { + initChatControllerAndRunMigrations() + } // LALAL //testCrypto() }