diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/CrashActivity.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/CrashActivity.kt index 6f488fe6..d2093380 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/CrashActivity.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/CrashActivity.kt @@ -6,9 +6,12 @@ import android.net.Uri import android.os.Build import android.os.Bundle import androidx.appcompat.app.AppCompatActivity +import com.yogeshpaliyal.common.data.UserSettings +import com.yogeshpaliyal.common.utils.getUserSettings import com.yogeshpaliyal.keypass.BuildConfig import com.yogeshpaliyal.keypass.databinding.ActivityCrashBinding import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.runBlocking import java.lang.StringBuilder @AndroidEntryPoint @@ -31,35 +34,70 @@ class CrashActivity : AppCompatActivity() { binding = ActivityCrashBinding.inflate(layoutInflater) setContentView(binding.root) - binding.txtCrash.text = intent.extras?.getString(ARG_DATA) + binding.txtCrash.text = getCrashWithMetaData(intent.extras?.getString(ARG_DATA)) binding.btnSendFeedback.setOnClickListener { - val deviceInfo = StringBuilder() - deviceInfo.append(binding.txtCrash.text.toString()) - try { - deviceInfo.append("\n") - deviceInfo.append("App Version: " + BuildConfig.VERSION_NAME) - deviceInfo.append("\n") - deviceInfo.append("Brand Name: " + Build.BRAND) - deviceInfo.append("\n") - deviceInfo.append("Manufacturer Name: " + Build.MANUFACTURER) - deviceInfo.append("\n") - deviceInfo.append("Device Name: " + Build.MODEL) - deviceInfo.append("\n") - deviceInfo.append("Device API Version: " + Build.VERSION.SDK_INT) - deviceInfo.append("\n") - } catch (e: Exception) { - e.printStackTrace() - } - val intent = Intent(Intent.ACTION_SENDTO) intent.data = Uri.parse("mailto:") intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("yogeshpaliyal.foss+keypass@gmail.com")) intent.putExtra(Intent.EXTRA_SUBJECT, "Crash Report in KeyPass") - intent.putExtra(Intent.EXTRA_TEXT, deviceInfo.toString()) + intent.putExtra(Intent.EXTRA_TEXT, binding.txtCrash.text.toString()) startActivity(Intent.createChooser(intent, "")) } } + + private fun getCrashWithMetaData(crashData: String?): String { + var userSettings: UserSettings? = null + var currentAppVersion = "Not able to fetch" + var lastAppVersion = "Not able to fetch" + runBlocking { + try { + userSettings = getUserSettings() + currentAppVersion = userSettings?.currentAppVersion.toString() + lastAppVersion = userSettings?.lastAppVersion.toString() + } catch (e: Exception) { + currentAppVersion = e.message ?: "Not able to fetch" + lastAppVersion = e.message ?: "Not able to fetch" + e.printStackTrace() + } + } + val installerPackageName = getInstallerPackageName(this, BuildConfig.APPLICATION_ID) + val deviceInfo = StringBuilder() + deviceInfo.append(crashData) + try { + deviceInfo.append("\n") + deviceInfo.append("App Version from Build: " + BuildConfig.VERSION_NAME) + deviceInfo.append("\n") + deviceInfo.append("Current App Version: $currentAppVersion") + deviceInfo.append("\n") + deviceInfo.append("Previous App Version: $lastAppVersion") + deviceInfo.append("\n") + deviceInfo.append("Installed from: $installerPackageName") + deviceInfo.append("\n") + deviceInfo.append("Brand Name: " + Build.BRAND) + deviceInfo.append("\n") + deviceInfo.append("Manufacturer Name: " + Build.MANUFACTURER) + deviceInfo.append("\n") + deviceInfo.append("Device Name: " + Build.MODEL) + deviceInfo.append("\n") + deviceInfo.append("Device API Version: " + Build.VERSION.SDK_INT) + deviceInfo.append("\n") + } catch (e: Exception) { + e.printStackTrace() + } + return deviceInfo.toString() + } + + fun getInstallerPackageName(context: Context, packageName: String): String? { + kotlin.runCatching { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + return context.packageManager.getInstallSourceInfo(packageName).installingPackageName + } + @Suppress("DEPRECATION") + return context.packageManager.getInstallerPackageName(packageName) + } + return null + } } diff --git a/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt b/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt index 99bfefcf..c29e50fc 100644 --- a/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt +++ b/app/src/main/java/com/yogeshpaliyal/keypass/ui/nav/DashboardComposeActivity.kt @@ -19,8 +19,10 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import com.yogeshpaliyal.common.data.UserSettings +import com.yogeshpaliyal.common.utils.getUserSettings import com.yogeshpaliyal.common.utils.getUserSettingsFlow import com.yogeshpaliyal.common.utils.migrateOldDataToNewerDataStore +import com.yogeshpaliyal.common.utils.setUserSettings import com.yogeshpaliyal.keypass.BuildConfig import com.yogeshpaliyal.keypass.ui.addTOTP.TOTPScreen import com.yogeshpaliyal.keypass.ui.auth.AuthScreen @@ -66,6 +68,7 @@ class DashboardComposeActivity : AppCompatActivity() { WindowManager.LayoutParams.FLAG_SECURE ) } + setContent { val localUserSettings by getUserSettingsFlow().collectAsState(initial = UserSettings()) @@ -79,6 +82,12 @@ class DashboardComposeActivity : AppCompatActivity() { LaunchedEffect(key1 = Unit, block = { migrateOldDataToNewerDataStore() + val userSettings = getUserSettings() + val buildConfigVersion = BuildConfig.VERSION_CODE + val currentAppVersion = userSettings.currentAppVersion + if (buildConfigVersion != currentAppVersion) { + applicationContext.setUserSettings(userSettings.copy(lastAppVersion = currentAppVersion, currentAppVersion = buildConfigVersion)) + } }) } } diff --git a/common/src/main/java/com/yogeshpaliyal/common/data/UserSettings.kt b/common/src/main/java/com/yogeshpaliyal/common/data/UserSettings.kt index dd141fa5..12eba6a9 100644 --- a/common/src/main/java/com/yogeshpaliyal/common/data/UserSettings.kt +++ b/common/src/main/java/com/yogeshpaliyal/common/data/UserSettings.kt @@ -16,7 +16,9 @@ data class UserSettings( val backupDirectory: String? = null, val backupTime: Long? = null, val autoBackupEnable: Boolean = false, - val overrideAutoBackup: Boolean = false + val overrideAutoBackup: Boolean = false, + val lastAppVersion: Int? = null, + val currentAppVersion: Int? = null ) { fun isKeyPresent() = backupKey != null } diff --git a/common/src/main/java/com/yogeshpaliyal/common/utils/CryptoManager.kt b/common/src/main/java/com/yogeshpaliyal/common/utils/CryptoManager.kt index c8de6204..78e0569e 100644 --- a/common/src/main/java/com/yogeshpaliyal/common/utils/CryptoManager.kt +++ b/common/src/main/java/com/yogeshpaliyal/common/utils/CryptoManager.kt @@ -2,7 +2,6 @@ package com.yogeshpaliyal.common.utils import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyProperties -import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.InputStream import java.io.OutputStream @@ -64,50 +63,8 @@ class CryptoManager { } } - private fun decryptOld(inputStream: InputStream): ByteArray? { + fun decrypt(inputStream: InputStream): ByteArray { return inputStream.use { - val ivSize = inputStream.read() - val iv = ByteArray(ivSize) - inputStream.read(iv) - val cipher = Cipher.getInstance(TRANSFORMATION) - cipher.init(Cipher.DECRYPT_MODE, getKey(), IvParameterSpec(iv)) - val decryptedSize = inputStream.read() - val decryptedData = ByteArray(decryptedSize) - inputStream.read(decryptedData) - - // check if more data is there - try { - val input = inputStream.read() - if (input != -1) { - return null - } - } catch (e: Exception) { - e.printStackTrace() - } - - return cipher.doFinal(decryptedData) - } - } - - private fun copyInputStream(inputS: InputStream): InputStream { - val byteArrayOutputStream = ByteArrayOutputStream() - inputS.copyTo(byteArrayOutputStream, 1024) - val data = byteArrayOutputStream.toByteArray() - return ByteArrayInputStream(data) - } - - fun decrypt(inputS: InputStream): ByteArray { - return inputS.use { - // TODO remove after migrations - val data = inputS.readBytes() - val inputStreamForOld = copyInputStream(ByteArrayInputStream(data)) - val oldDecrypt = decryptOld(inputStreamForOld) - if (oldDecrypt != null) { - return oldDecrypt - } - - val inputStream = copyInputStream(ByteArrayInputStream(data)) - val ivSize = inputStream.read() val iv = ByteArray(ivSize) inputStream.read(iv)