Improved backup/restore w/o Crypto class

This commit is contained in:
Juha Heinanen
2022-02-09 12:52:09 +02:00
parent 52f693f49c
commit d975ab522a
2 changed files with 31 additions and 36 deletions
@@ -35,12 +35,11 @@ import com.google.android.material.snackbar.Snackbar
import com.tutpro.baresip.Utils.showSnackBar import com.tutpro.baresip.Utils.showSnackBar
import com.tutpro.baresip.databinding.ActivityMainBinding import com.tutpro.baresip.databinding.ActivityMainBinding
import java.io.File import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.net.URLDecoder import java.net.URLDecoder
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.system.exitProcess import kotlin.system.exitProcess
import android.content.IntentFilter import android.content.IntentFilter
import androidx.core.net.toUri
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
@@ -88,10 +87,8 @@ class MainActivity : AppCompatActivity() {
private lateinit var contactsRequest: ActivityResultLauncher<Intent> private lateinit var contactsRequest: ActivityResultLauncher<Intent>
private lateinit var callsRequest: ActivityResultLauncher<Intent> private lateinit var callsRequest: ActivityResultLauncher<Intent>
private var downloadsInputStream: FileInputStream? = null private var downloadsInputUri: Uri? = null
private var downloadsOutputStream: FileOutputStream? = null private var downloadsOutputUri: Uri? = null
private var downloadsInputFile = "baresip.bs"
private var downloadsOutputFile = "baresip.bs"
private lateinit var baresipService: Intent private lateinit var baresipService: Intent
@@ -543,24 +540,18 @@ class MainActivity : AppCompatActivity() {
backupRequest = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { backupRequest = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) if (it.resultCode == Activity.RESULT_OK)
it.data?.data?.also { uri -> it.data?.data?.also { uri ->
downloadsOutputStream = applicationContext.contentResolver.openOutputStream(uri) downloadsOutputUri = uri
as FileOutputStream if (downloadsOutputUri != null)
if (downloadsOutputStream != null) {
downloadsOutputFile = Utils.fileNameOfUri(applicationContext, uri)
askPassword(getString(R.string.encrypt_password)) askPassword(getString(R.string.encrypt_password))
}
} }
} }
restoreRequest = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { restoreRequest = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) if (it.resultCode == Activity.RESULT_OK)
it.data?.data?.also { uri -> it.data?.data?.also { uri ->
downloadsInputStream = applicationContext.contentResolver.openInputStream(uri) downloadsInputUri = uri
as FileInputStream if (downloadsInputUri != null)
if (downloadsInputStream != null) {
downloadsInputFile = Utils.fileNameOfUri(applicationContext, uri)
askPassword(getString(R.string.decrypt_password)) askPassword(getString(R.string.decrypt_password))
}
} }
} }
@@ -1266,7 +1257,7 @@ class MainActivity : AppCompatActivity() {
) == PackageManager.PERMISSION_GRANTED -> { ) == PackageManager.PERMISSION_GRANTED -> {
Log.d(TAG, "Write External Storage permission granted") Log.d(TAG, "Write External Storage permission granted")
val path = Utils.downloadsPath("baresip.bs") val path = Utils.downloadsPath("baresip.bs")
downloadsOutputStream = FileOutputStream(File(path)) downloadsOutputUri = File(path).toUri()
askPassword(getString(R.string.encrypt_password)) askPassword(getString(R.string.encrypt_password))
} }
ActivityCompat.shouldShowRequestPermissionRationale( ActivityCompat.shouldShowRequestPermissionRationale(
@@ -1289,14 +1280,15 @@ class MainActivity : AppCompatActivity() {
R.id.restore -> { R.id.restore -> {
when { when {
Build.VERSION.SDK_INT >= 29 -> pickupFileFromDownloads("restore") Build.VERSION.SDK_INT >= 29 ->
pickupFileFromDownloads("restore")
ContextCompat.checkSelfPermission( ContextCompat.checkSelfPermission(
this, this,
Manifest.permission.READ_EXTERNAL_STORAGE Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED -> { ) == PackageManager.PERMISSION_GRANTED -> {
Log.d(TAG, "Read External Storage permission granted") Log.d(TAG, "Read External Storage permission granted")
val path = Utils.downloadsPath("baresip.bs") val path = Utils.downloadsPath("baresip.bs")
downloadsInputStream = FileInputStream(File(path)) downloadsInputUri = File(path).toUri()
askPassword(getString(R.string.decrypt_password)) askPassword(getString(R.string.decrypt_password))
} }
ActivityCompat.shouldShowRequestPermissionRationale( ActivityCompat.shouldShowRequestPermissionRationale(
@@ -1552,7 +1544,7 @@ class MainActivity : AppCompatActivity() {
Log.w(TAG, "Failed to write zip file '$zipFile'") Log.w(TAG, "Failed to write zip file '$zipFile'")
Utils.alertView(this, getString(R.string.error), Utils.alertView(this, getString(R.string.error),
String.format(getString(R.string.backup_failed), String.format(getString(R.string.backup_failed),
downloadsOutputFile)) Utils.fileNameOfUri(applicationContext, downloadsOutputUri!!)))
return return
} }
val content = Utils.getFileContents(zipFilePath) val content = Utils.getFileContents(zipFilePath)
@@ -1560,43 +1552,43 @@ class MainActivity : AppCompatActivity() {
Log.w(TAG, "Failed to read zip file '$zipFile'") Log.w(TAG, "Failed to read zip file '$zipFile'")
Utils.alertView(this, getString(R.string.error), Utils.alertView(this, getString(R.string.error),
String.format(getString(R.string.backup_failed), String.format(getString(R.string.backup_failed),
downloadsOutputFile)) Utils.fileNameOfUri(applicationContext, downloadsOutputUri!!)))
return return
} }
if (!Utils.encryptToStream(downloadsOutputStream, content, password)) { if (!Utils.encryptToUri(applicationContext, downloadsOutputUri!!, content, password)) {
Utils.alertView(this, getString(R.string.error), Utils.alertView(this, getString(R.string.error),
String.format(getString(R.string.backup_failed), String.format(getString(R.string.backup_failed),
downloadsOutputFile)) Utils.fileNameOfUri(applicationContext, downloadsOutputUri!!)))
return return
} }
Utils.alertView(this, getString(R.string.info), Utils.alertView(this, getString(R.string.info),
String.format(getString(R.string.backed_up), String.format(getString(R.string.backed_up),
downloadsOutputFile)) Utils.fileNameOfUri(applicationContext, downloadsOutputUri!!)))
Utils.deleteFile(File(zipFilePath)) Utils.deleteFile(File(zipFilePath))
} }
private fun restore(password: String) { private fun restore(password: String) {
val zipFile = getString(R.string.app_name) + ".zip" val zipFile = getString(R.string.app_name) + ".zip"
val zipFilePath = BaresipService.filesPath + "/$zipFile" val zipFilePath = BaresipService.filesPath + "/$zipFile"
val zipData = Utils.decryptFromStream(downloadsInputStream, password) val zipData = Utils.decryptFromUri(applicationContext, downloadsInputUri!!, password)
if (zipData == null) { if (zipData == null) {
Utils.alertView(this, getString(R.string.error), Utils.alertView(this, getString(R.string.error),
String.format(getString(R.string.restore_failed), String.format(getString(R.string.restore_failed),
downloadsInputFile)) Utils.fileNameOfUri(applicationContext, downloadsInputUri!!)))
return return
} }
if (!Utils.putFileContents(zipFilePath, zipData)) { if (!Utils.putFileContents(zipFilePath, zipData)) {
Log.w(TAG, "Failed to write zip file '$zipFile'") Log.w(TAG, "Failed to write zip file '$zipFile'")
Utils.alertView(this, getString(R.string.error), Utils.alertView(this, getString(R.string.error),
String.format(getString(R.string.restore_failed), String.format(getString(R.string.restore_failed),
downloadsInputFile)) Utils.fileNameOfUri(applicationContext, downloadsInputUri!!)))
return return
} }
if (!Utils.unZip(zipFilePath)) { if (!Utils.unZip(zipFilePath)) {
Log.w(TAG, "Failed to unzip file '$zipFile'") Log.w(TAG, "Failed to unzip file '$zipFile'")
Utils.alertView(this, getString(R.string.error), Utils.alertView(this, getString(R.string.error),
String.format(getString(R.string.restore_failed), String.format(getString(R.string.restore_failed),
downloadsInputFile)) Utils.fileNameOfUri(applicationContext, downloadsInputUri!!)))
return return
} }
Utils.deleteFile(File(zipFilePath)) Utils.deleteFile(File(zipFilePath))
@@ -629,38 +629,41 @@ object Utils {
return plainData return plainData
} }
fun encryptToStream(stream: FileOutputStream?, content: ByteArray, password: String): Boolean { fun encryptToUri(ctx: Context, uri: Uri, content: ByteArray, password: String): Boolean {
val obj = encrypt(content, password.toCharArray()) val obj = encrypt(content, password.toCharArray())
val stream = ctx.contentResolver.openOutputStream(uri) as FileOutputStream
try { try {
ObjectOutputStream(stream).use { ObjectOutputStream(stream).use {
it.writeObject(obj) it.writeObject(obj)
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "encryptToStream failed: $e") Log.w(TAG, "encryptToUri failed: $e")
return false return false
} }
return true return true
} }
fun decryptFromStream(stream: FileInputStream?, password: String): ByteArray? { fun decryptFromUri(ctx: Context, uri: Uri, password: String): ByteArray? {
var plainData: ByteArray? = null var plainData: ByteArray? = null
if (stream == null) var stream = ctx.contentResolver.openInputStream(uri) as FileInputStream
return null
try { try {
ObjectInputStream(stream).use { ObjectInputStream(stream).use {
val content = it.readObject() as ByteArray val content = it.readObject() as ByteArray
plainData = decrypt(content, password.toCharArray()) plainData = decrypt(content, password.toCharArray())
} }
stream.close()
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "decryptFromStream as ByteArray failed: $e") Log.w(TAG, "decryptFromUri as ByteArray failed: $e")
stream.close()
try { try {
stream.close() stream = ctx.contentResolver.openInputStream(uri) as FileInputStream
ObjectInputStream(stream).use { ObjectInputStream(stream).use {
val obj = it.readObject() as Crypto val obj = it.readObject() as Crypto
plainData = decryptOld(obj, password.toCharArray()) plainData = decryptOld(obj, password.toCharArray())
} }
stream.close()
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "decryptFromStream as Crypto failed: $e") Log.w(TAG, "decryptFromUri as Crypto failed: $e")
} }
} }
return plainData return plainData