multiplatform: local file encryption (#3043)

* multiplatform: file encryption

* setting

* fixed sharing

* check

* fixes, change lock icon

* update JNI bindings (crashes on desktop)

* fix JNI

* fix errors and warnings

* fix saving

---------

Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
Stanislav Dmitrenko
2023-09-10 19:05:12 +03:00
committed by GitHub
parent a87aaa50c7
commit 54e1e10382
43 changed files with 522 additions and 151 deletions
@@ -25,6 +25,8 @@ fun initApp() {
initChatController()
runMigrations()
}
// LALAL
//testCrypto()
}
private fun applyAppLocale() {
@@ -1,7 +1,7 @@
package chat.simplex.common.platform
import androidx.compose.runtime.MutableState
import chat.simplex.common.model.ChatItem
import chat.simplex.common.model.*
import chat.simplex.common.views.usersettings.showInDevelopingAlert
import kotlinx.coroutines.CoroutineScope
@@ -18,7 +18,7 @@ actual class RecorderNative: RecorderInterface {
}
actual object AudioPlayer: AudioPlayerInterface {
override fun play(filePath: String?, audioPlaying: MutableState<Boolean>, progress: MutableState<Int>, duration: MutableState<Int>, resetOnEnd: Boolean) {
override fun play(fileSource: CryptoFile, audioPlaying: MutableState<Boolean>, progress: MutableState<Int>, duration: MutableState<Int>, resetOnEnd: Boolean) {
showInDevelopingAlert()
}
@@ -3,6 +3,8 @@ package chat.simplex.common.platform
import androidx.compose.ui.platform.ClipboardManager
import androidx.compose.ui.platform.UriHandler
import androidx.compose.ui.text.AnnotatedString
import chat.simplex.common.model.*
import chat.simplex.common.views.helpers.getAppFileUri
import chat.simplex.common.views.helpers.withApi
import java.io.File
import java.net.URI
@@ -20,12 +22,16 @@ actual fun ClipboardManager.shareText(text: String) {
showToast(MR.strings.copied.localized())
}
actual fun shareFile(text: String, filePath: String) {
actual fun shareFile(text: String, fileSource: CryptoFile) {
withApi {
FileChooserLauncher(false) { to: URI? ->
if (to != null) {
copyFileToFile(File(filePath), to) {}
if (fileSource.cryptoArgs != null) {
decryptCryptoFile(getAppFilePath(fileSource.filePath), fileSource.cryptoArgs, to.path)
} else {
copyFileToFile(File(fileSource.filePath), to) {}
}
}
}.launch(filePath)
}.launch(fileSource.filePath)
}
}
@@ -11,7 +11,7 @@ import java.net.URI
@Composable
actual fun SimpleAndAnimatedImageView(
uri: URI,
data: ByteArray,
imageBitmap: ImageBitmap,
file: CIFile?,
imageProvider: () -> ImageGalleryProvider,
@@ -31,7 +31,7 @@ actual fun ReactionIcon(text: String, fontSize: TextUnit) {
@Composable
actual fun SaveContentItemAction(cItem: ChatItem, saveFileLauncher: FileChooserLauncher, showMenu: MutableState<Boolean>) {
ItemAction(stringResource(MR.strings.save_verb), painterResource(MR.images.ic_download), onClick = {
ItemAction(stringResource(MR.strings.save_verb), painterResource(if (cItem.file?.fileSource?.cryptoArgs == null) MR.images.ic_download else MR.images.ic_lock_open_right), onClick = {
when (cItem.content.msgContent) {
is MsgContent.MCImage, is MsgContent.MCFile, is MsgContent.MCVoice, is MsgContent.MCVideo -> withApi { saveFileLauncher.launch(cItem.file?.fileName ?: "") }
else -> {}
@@ -4,19 +4,16 @@ import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.layout.ContentScale
import chat.simplex.common.platform.VideoPlayer
import chat.simplex.common.views.helpers.getBitmapFromUri
import chat.simplex.common.views.helpers.getBitmapFromByteArray
import chat.simplex.res.MR
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import java.net.URI
@Composable
actual fun FullScreenImageView(modifier: Modifier, uri: URI, imageBitmap: ImageBitmap) {
actual fun FullScreenImageView(modifier: Modifier, data: ByteArray, imageBitmap: ImageBitmap) {
Image(
getBitmapFromUri(uri, false) ?: MR.images.decentralized.image.toComposeImageBitmap(),
getBitmapFromByteArray(data, false) ?: MR.images.decentralized.image.toComposeImageBitmap(),
contentDescription = stringResource(MR.strings.image_descr),
contentScale = ContentScale.Fit,
modifier = modifier,
@@ -6,8 +6,10 @@ import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Density
import chat.simplex.common.model.CIFile
import chat.simplex.common.model.readCryptoFile
import chat.simplex.common.platform.*
import chat.simplex.common.simplexWindowState
import java.io.ByteArrayInputStream
import java.io.File
import java.net.URI
import javax.imageio.ImageIO
@@ -88,11 +90,12 @@ actual fun escapedHtmlToAnnotatedString(text: String, density: Density): Annotat
actual fun getAppFileUri(fileName: String): URI =
URI("file:" + appFilesDir.absolutePath + File.separator + fileName)
actual fun getLoadedImage(file: CIFile?): ImageBitmap? {
actual fun getLoadedImage(file: CIFile?): Pair<ImageBitmap, ByteArray>? {
val filePath = getLoadedFilePath(file)
return if (filePath != null) {
val uri = getAppFileUri(filePath.substringAfterLast(File.separator))
getBitmapFromUri(uri, false)
val data = if (file?.fileSource?.cryptoArgs != null) readCryptoFile(filePath, file.fileSource.cryptoArgs) else File(filePath).readBytes()
val bitmap = getBitmapFromByteArray(data, false)
if (bitmap != null) bitmap to data else null
} else {
null
}
@@ -107,6 +110,9 @@ actual fun getFileSize(uri: URI): Long? = uri.toPath().toFile().length()
actual fun getBitmapFromUri(uri: URI, withAlertOnException: Boolean): ImageBitmap? =
ImageIO.read(uri.inputStream()).toComposeImageBitmap()
actual fun getBitmapFromByteArray(data: ByteArray, withAlertOnException: Boolean): ImageBitmap? =
ImageIO.read(ByteArrayInputStream(data)).toComposeImageBitmap()
// LALAL implement to support animated drawable
actual fun getDrawableFromUri(uri: URI, withAlertOnException: Boolean): Any? = null