diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt b/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt index 9c0cb03d..893b3440 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/MainActivity.kt @@ -268,7 +268,7 @@ class MainActivity : AppCompatActivity() { override fun onResume() { Amber.instance.setMainActivity(this) - mainViewModel.showBunkerRequests(callingPackage) + mainViewModel.showBunkerRequests() @Suppress("KotlinConstantConditions") if (BuildConfig.FLAVOR != "offline") { val connectivityManager = diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/MainViewModel.kt b/app/src/main/java/com/greenart7c3/nostrsigner/MainViewModel.kt index e8e17d11..98eed212 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/MainViewModel.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/MainViewModel.kt @@ -4,22 +4,18 @@ import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.util.Log -import androidx.core.net.toUri import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.navigation.NavHostController import com.greenart7c3.nostrsigner.models.IntentData import com.greenart7c3.nostrsigner.service.BunkerRequestUtils import com.greenart7c3.nostrsigner.service.IntentUtils -import com.greenart7c3.nostrsigner.service.MultiEventScreenIntents.intents import com.greenart7c3.nostrsigner.ui.AccountStateViewModel import com.greenart7c3.nostrsigner.ui.navigation.Route import com.vitorpamplona.quartz.nip19Bech32.Nip19Parser import com.vitorpamplona.quartz.nip19Bech32.entities.NPub import com.vitorpamplona.quartz.nip19Bech32.toNpub import com.vitorpamplona.quartz.utils.Hex -import kotlin.text.isNotBlank -import kotlin.text.startsWith import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow @@ -96,32 +92,13 @@ class MainViewModel(val context: Context) : ViewModel() { } } - fun showBunkerRequests(callingPackage: String?, accountStateViewModel: AccountStateViewModel? = null) { + fun showBunkerRequests(accountStateViewModel: AccountStateViewModel? = null) { val requests = BunkerRequestUtils.getBunkerRequests().map { it.copy() } viewModelScope.launch(Dispatchers.IO) { - val account = LocalPreferences.loadFromEncryptedStorage(context) - account?.let { acc -> - requests.forEach { - val contentIntent = - Intent(Amber.instance, MainActivity::class.java).apply { - data = "nostrsigner:".toUri() - } - contentIntent.putExtra("bunker", it.toJson()) - contentIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) - val intentData = IntentUtils.getIntentData(context, contentIntent, callingPackage, Route.IncomingRequest.route, acc) - contentIntent.putExtra("current_account", acc.npub) - if (intentData != null) { - if (intents.value.none { item -> item.id == intentData.id }) { - intents.value += listOf(intentData) - } - } - } - } - if (requests.isNotEmpty()) { val npub = getAccount(null) val currentAccount = LocalPreferences.currentAccount(context) diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt b/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt index 121bf6d9..0c34e9f1 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt @@ -69,8 +69,9 @@ class SignerProvider : ContentProvider() { } else { if (Hex.isHex(sortOrder)) { sortOrder + } else { + null } - null } if (packageName == null) { Log.d(Amber.TAG, "No package name") diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/models/AmberBunkerRequest.kt b/app/src/main/java/com/greenart7c3/nostrsigner/models/AmberBunkerRequest.kt index 9dacbcc2..f107f685 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/models/AmberBunkerRequest.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/models/AmberBunkerRequest.kt @@ -2,26 +2,10 @@ package com.greenart7c3.nostrsigner.models import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf -import com.fasterxml.jackson.core.JsonGenerator -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.databind.DeserializationContext -import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.SerializerProvider -import com.fasterxml.jackson.databind.deser.std.StdDeserializer -import com.fasterxml.jackson.databind.module.SimpleModule -import com.fasterxml.jackson.databind.ser.std.StdSerializer -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import com.greenart7c3.nostrsigner.Amber import com.greenart7c3.nostrsigner.ui.RememberType import com.vitorpamplona.quartz.nip01Core.core.Event -import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequest -import kotlin.collections.asIterable enum class EncryptionType { NIP44, @@ -37,80 +21,8 @@ data class AmberBunkerRequest( val closeApplication: Boolean, val name: String, val signedEvent: Event?, - val encryptDecryptResponse: String?, + val encryptedData: EncryptedDataKind?, val checked: MutableState = mutableStateOf(true), val rememberType: MutableState = mutableStateOf(RememberType.NEVER), val encryptionType: EncryptionType, -) { - fun toJson(): String { - return mapper.writeValueAsString(this) - } - - companion object { - val mapper: ObjectMapper = - jacksonObjectMapper() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .registerModule( - SimpleModule() - .addDeserializer(AmberBunkerRequest::class.java, AmberBunkerRequestDeserializer()) - .addSerializer(AmberBunkerRequest::class.java, AmberBunkerRequestSerializer()), - ) - - fun fromJson(jsonObject: JsonNode): AmberBunkerRequest { - return AmberBunkerRequest( - request = JacksonMapper.mapper.readValue(jsonObject.get("request").asText().intern()), - localKey = jsonObject.get("localKey")?.asText()?.intern() ?: "", - relays = jsonObject.get("relays")?.asIterable()?.toList()?.mapNotNull { - RelayUrlNormalizer.normalizeOrNull(it.asText()) - } ?: Amber.instance.getSavedRelays().toList(), - currentAccount = jsonObject.get("currentAccount")?.asText()?.intern() ?: "", - nostrConnectSecret = jsonObject.get("nostrConnectSecret")?.asText()?.intern() ?: "", - closeApplication = jsonObject.get("closeApplication")?.asBoolean() != false, - name = jsonObject.get("name")?.asText()?.intern() ?: "", - signedEvent = jsonObject.get("signedEvent")?.asText()?.intern()?.let { - try { - JacksonMapper.fromJson(it) - } catch (_: Exception) { - null - } - }, - encryptDecryptResponse = jsonObject.get("encryptDecryptResponse")?.asText()?.intern(), - encryptionType = EncryptionType.valueOf(jsonObject.get("encryptionType")?.asText()?.intern() ?: "NIP44"), - ) - } - - private class AmberBunkerRequestDeserializer : StdDeserializer(AmberBunkerRequest::class.java) { - override fun deserialize( - jp: JsonParser, - ctxt: DeserializationContext, - ): AmberBunkerRequest { - return fromJson(jp.codec.readTree(jp)) - } - } - - private class AmberBunkerRequestSerializer : StdSerializer(AmberBunkerRequest::class.java) { - override fun serialize( - value: AmberBunkerRequest, - gen: JsonGenerator, - provider: SerializerProvider, - ) { - gen.writeStartObject() - gen.writeStringField("request", mapper.writeValueAsString(value.request)) - gen.writeStringField("localKey", value.localKey) - gen.writeArrayFieldStart("relays") - value.relays.forEach { - gen.writeString(it.url) - } - gen.writeEndArray() - gen.writeStringField("currentAccount", value.currentAccount) - gen.writeStringField("nostrConnectSecret", value.nostrConnectSecret) - gen.writeBooleanField("closeApplication", value.closeApplication) - gen.writeStringField("name", value.name) - gen.writeStringField("signedEvent", value.signedEvent?.toJson()) - gen.writeStringField("encryptDecryptResponse", value.encryptDecryptResponse) - gen.writeStringField("encryptionType", value.encryptionType.name) - gen.writeEndObject() - } - } - } -} +) diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/service/EventNotificationConsumer.kt b/app/src/main/java/com/greenart7c3/nostrsigner/service/EventNotificationConsumer.kt index 3fffbd50..29a896e2 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/service/EventNotificationConsumer.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/EventNotificationConsumer.kt @@ -36,9 +36,12 @@ import com.greenart7c3.nostrsigner.database.HistoryEntity import com.greenart7c3.nostrsigner.database.LogEntity import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.AmberBunkerRequest +import com.greenart7c3.nostrsigner.models.ClearTextEncryptedDataKind import com.greenart7c3.nostrsigner.models.EncryptionType +import com.greenart7c3.nostrsigner.models.EventEncryptedDataKind import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.models.SignerType +import com.greenart7c3.nostrsigner.models.TagArrayEncryptedDataKind import com.greenart7c3.nostrsigner.service.NotificationUtils.sendNotification import com.greenart7c3.nostrsigner.service.model.AmberEvent import com.vitorpamplona.quartz.nip01Core.core.Event @@ -56,6 +59,7 @@ import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestNip44Encrypt import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestSign import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerResponse import com.vitorpamplona.quartz.nip46RemoteSigner.NostrConnectEvent +import com.vitorpamplona.quartz.nip59Giftwrap.seals.SealedRumorEvent import com.vitorpamplona.quartz.utils.TimeUtils import java.util.UUID import kotlinx.coroutines.launch @@ -174,21 +178,114 @@ class EventNotificationConsumer(private val applicationContext: Context) { null } - val encryptDecryptResponse = if (bunkerRequest is BunkerRequestNip44Decrypt) { - acc.signer.signerSync.nip44Decrypt(bunkerRequest.ciphertext, bunkerRequest.pubKey) + val encryptedDataKind = if (bunkerRequest is BunkerRequestNip44Decrypt) { + val result = acc.signer.signerSync.nip44Decrypt(bunkerRequest.ciphertext, bunkerRequest.pubKey) + + if (result.startsWith("{")) { + val event = AmberEvent.fromJson(result) + if (event.kind == SealedRumorEvent.KIND) { + val decryptedSealData = acc.signer.signerSync.decrypt(event.content, acc.hexKey) + if (decryptedSealData.startsWith("{")) { + val sealEvent = AmberEvent.fromJson(decryptedSealData) + EventEncryptedDataKind(event, EventEncryptedDataKind(sealEvent, null, decryptedSealData), result) + } else if (decryptedSealData.startsWith("[")) { + val tagArray = JacksonMapper.fromJsonToTagArray(decryptedSealData) + EventEncryptedDataKind(event, TagArrayEncryptedDataKind(tagArray, decryptedSealData), decryptedSealData) + } else { + EventEncryptedDataKind(event, ClearTextEncryptedDataKind(event.content, decryptedSealData), result) + } + } else { + EventEncryptedDataKind(event, null, result) + } + } else if (result.startsWith("[")) { + val tagArray = JacksonMapper.fromJsonToTagArray(result) + TagArrayEncryptedDataKind(tagArray, result) + } else { + ClearTextEncryptedDataKind(bunkerRequest.ciphertext, result) + } } else if (bunkerRequest is BunkerRequestNip44Encrypt) { - acc.signer.signerSync.nip44Encrypt(bunkerRequest.message, bunkerRequest.pubKey) + val result = acc.signer.signerSync.nip44Encrypt(bunkerRequest.message, bunkerRequest.pubKey) + if (bunkerRequest.message.startsWith("{")) { + try { + val event = AmberEvent.fromJson(bunkerRequest.message) + if (event.kind == SealedRumorEvent.KIND) { + val decryptedSealData = acc.signer.signerSync.decrypt(event.content, acc.hexKey) + if (decryptedSealData.startsWith("{")) { + val sealEvent = AmberEvent.fromJson(decryptedSealData) + EventEncryptedDataKind(event, EventEncryptedDataKind(sealEvent, null, decryptedSealData), result) + } else if (decryptedSealData.startsWith("[")) { + val tagArray = JacksonMapper.fromJsonToTagArray(decryptedSealData) + EventEncryptedDataKind(event, TagArrayEncryptedDataKind(tagArray, decryptedSealData), decryptedSealData) + } else { + EventEncryptedDataKind(event, ClearTextEncryptedDataKind(event.content, decryptedSealData), result) + } + } else { + EventEncryptedDataKind(event, null, result) + } + } catch (e: Exception) { + Log.e("IntentUtils", "Error parsing JSON: ${e.message}") + ClearTextEncryptedDataKind(bunkerRequest.message, result) + } + } else if (bunkerRequest.message.startsWith("[")) { + val tagArray = JacksonMapper.fromJsonToTagArray(bunkerRequest.message) + TagArrayEncryptedDataKind(tagArray, result) + } else { + ClearTextEncryptedDataKind(bunkerRequest.message, result) + } } else if (bunkerRequest is BunkerRequestNip04Decrypt) { - acc.signer.signerSync.nip04Decrypt(bunkerRequest.ciphertext, bunkerRequest.pubKey) + val result = acc.signer.signerSync.nip04Decrypt(bunkerRequest.ciphertext, bunkerRequest.pubKey) + + if (result.startsWith("{")) { + val event = AmberEvent.fromJson(result) + if (event.kind == SealedRumorEvent.KIND) { + val decryptedSealData = acc.signer.signerSync.decrypt(event.content, acc.hexKey) + if (decryptedSealData.startsWith("{")) { + val sealEvent = AmberEvent.fromJson(decryptedSealData) + EventEncryptedDataKind(event, EventEncryptedDataKind(sealEvent, null, decryptedSealData), result) + } else if (decryptedSealData.startsWith("[")) { + val tagArray = JacksonMapper.fromJsonToTagArray(decryptedSealData) + EventEncryptedDataKind(event, TagArrayEncryptedDataKind(tagArray, decryptedSealData), decryptedSealData) + } else { + EventEncryptedDataKind(event, ClearTextEncryptedDataKind(event.content, decryptedSealData), result) + } + } else { + EventEncryptedDataKind(event, null, result) + } + } else if (result.startsWith("[")) { + val tagArray = JacksonMapper.fromJsonToTagArray(result) + TagArrayEncryptedDataKind(tagArray, result) + } else { + ClearTextEncryptedDataKind(bunkerRequest.ciphertext, result) + } } else if (bunkerRequest is BunkerRequestNip04Encrypt) { - acc.signer.signerSync.nip04Encrypt(bunkerRequest.message, bunkerRequest.pubKey) - } else if (bunkerRequest.method == "decrypt_zap_event") { - AmberUtils.encryptOrDecryptData( - bunkerRequest.params[1], - SignerType.DECRYPT_ZAP_EVENT, - acc, - bunkerRequest.params.first(), - ) + val result = acc.signer.signerSync.nip04Encrypt(bunkerRequest.message, bunkerRequest.pubKey) + if (bunkerRequest.message.startsWith("{")) { + try { + val event = AmberEvent.fromJson(bunkerRequest.message) + if (event.kind == SealedRumorEvent.KIND) { + val decryptedSealData = acc.signer.signerSync.decrypt(event.content, acc.hexKey) + if (decryptedSealData.startsWith("{")) { + val sealEvent = AmberEvent.fromJson(decryptedSealData) + EventEncryptedDataKind(event, EventEncryptedDataKind(sealEvent, null, decryptedSealData), result) + } else if (decryptedSealData.startsWith("[")) { + val tagArray = JacksonMapper.fromJsonToTagArray(decryptedSealData) + EventEncryptedDataKind(event, TagArrayEncryptedDataKind(tagArray, decryptedSealData), decryptedSealData) + } else { + EventEncryptedDataKind(event, ClearTextEncryptedDataKind(event.content, decryptedSealData), result) + } + } else { + EventEncryptedDataKind(event, null, result) + } + } catch (e: Exception) { + Log.e("IntentUtils", "Error parsing JSON: ${e.message}") + ClearTextEncryptedDataKind(bunkerRequest.message, result) + } + } else if (bunkerRequest.message.startsWith("[")) { + val tagArray = JacksonMapper.fromJsonToTagArray(bunkerRequest.message) + TagArrayEncryptedDataKind(tagArray, result) + } else { + ClearTextEncryptedDataKind(bunkerRequest.message, result) + } } else { null } @@ -217,7 +314,7 @@ class EventNotificationConsumer(private val applicationContext: Context) { closeApplication = true, name = "", signedEvent = signedEvent, - encryptDecryptResponse = encryptDecryptResponse, + encryptedData = encryptedDataKind, encryptionType = encryptionType, ) diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt b/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt index c4e6cc22..6dd44b55 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt @@ -25,7 +25,6 @@ import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions import com.greenart7c3.nostrsigner.database.HistoryEntity import com.greenart7c3.nostrsigner.database.LogEntity import com.greenart7c3.nostrsigner.models.Account -import com.greenart7c3.nostrsigner.models.AmberBunkerRequest import com.greenart7c3.nostrsigner.models.ClearTextEncryptedDataKind import com.greenart7c3.nostrsigner.models.CompressionType import com.greenart7c3.nostrsigner.models.EventEncryptedDataKind @@ -595,22 +594,8 @@ object IntentUtils { return null } - val bunkerRequest = - if (intent.getStringExtra("bunker") != null) { - AmberBunkerRequest.mapper.readValue( - intent.getStringExtra("bunker"), - AmberBunkerRequest::class.java, - ) - } else { - null - } - var localAccount = currentLoggedInAccount - if (bunkerRequest != null) { - LocalPreferences.loadFromEncryptedStorageSync(context, bunkerRequest.currentAccount)?.let { - localAccount = it - } - } else if (intent.getStringExtra("current_user") != null) { + if (intent.getStringExtra("current_user") != null) { var npub = intent.getStringExtra("current_user") if (npub != null) { npub = parsePubKey(npub) @@ -622,8 +607,6 @@ object IntentUtils { if (intent.dataString?.startsWith("nostrconnect:") == true) { NostrConnectUtils.getIntentFromNostrConnect(intent, localAccount) - } else if (bunkerRequest != null) { - BunkerRequestUtils.addRequest(bunkerRequest) } else if (intent.extras?.getString(Browser.EXTRA_APPLICATION_ID) == null) { return getIntentDataFromIntent(context, intent, packageName, route, localAccount) } else { diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/service/NostrConnectUtils.kt b/app/src/main/java/com/greenart7c3/nostrsigner/service/NostrConnectUtils.kt index e0ffa619..3ef5ea21 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/service/NostrConnectUtils.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/NostrConnectUtils.kt @@ -124,7 +124,7 @@ object NostrConnectUtils { closeApplication = intent.getBooleanExtra("closeApplication", true), name = name, signedEvent = null, - encryptDecryptResponse = null, + encryptedData = null, encryptionType = EncryptionType.NIP44, ), ) diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/SeeDetailsScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/SeeDetailsScreen.kt index 708cdd4f..580e5149 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/SeeDetailsScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/SeeDetailsScreen.kt @@ -183,7 +183,21 @@ fun SeeDetailsScreen( val event = bunkerRequest.signedEvent!! if (event.kind == 22242) AmberEvent.relay(event) else event.content } else { - bunkerRequest.encryptDecryptResponse ?: BunkerRequestUtils.getDataFromBunker(bunkerRequest.request) + if (type.name.contains("ENCRYPT") && bunkerRequest.encryptedData is ClearTextEncryptedDataKind) { + bunkerRequest.encryptedData.text + } else if (bunkerRequest.encryptedData is EventEncryptedDataKind) { + if (bunkerRequest.encryptedData.sealEncryptedDataKind != null) { + if (bunkerRequest.encryptedData.sealEncryptedDataKind is EventEncryptedDataKind) { + bunkerRequest.encryptedData.sealEncryptedDataKind.event.content + } else { + bunkerRequest.encryptedData.sealEncryptedDataKind.result + } + } else { + bunkerRequest.encryptedData.event.content + } + } else { + bunkerRequest.encryptedData?.result ?: BunkerRequestUtils.getDataFromBunker(bunkerRequest.request) + } } Text( diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/BunkerSingleEventHomeScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/BunkerSingleEventHomeScreen.kt index 2d3e9263..7a6d94b4 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/BunkerSingleEventHomeScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/BunkerSingleEventHomeScreen.kt @@ -306,7 +306,7 @@ fun BunkerSingleEventHomeScreen( account = account, modifier = modifier, content = bunkerRequest.request.message, - encryptedData = bunkerRequest.encryptDecryptResponse ?: "", + encryptedData = bunkerRequest.encryptedData, shouldRunOnAccept = acceptOrReject, appName = appName, type = type, @@ -315,7 +315,7 @@ fun BunkerSingleEventHomeScreen( context = context, account = account, key = key, - response = bunkerRequest.encryptDecryptResponse ?: "", + response = bunkerRequest.encryptedData?.result ?: "", bunkerRequest = bunkerRequest, kind = null, onLoading = onLoading, @@ -371,12 +371,12 @@ fun BunkerSingleEventHomeScreen( account = account, modifier = modifier, content = bunkerRequest.request.ciphertext, - encryptedData = bunkerRequest.encryptDecryptResponse ?: "", + encryptedData = bunkerRequest.encryptedData, shouldRunOnAccept = acceptOrReject, appName = appName, type = type, onAccept = { - val result = bunkerRequest.encryptDecryptResponse ?: "" + val result = bunkerRequest.encryptedData?.result ?: "" BunkerRequestUtils.sendResult( context = context, @@ -438,12 +438,12 @@ fun BunkerSingleEventHomeScreen( account = account, modifier = modifier, content = bunkerRequest.request.message, - encryptedData = bunkerRequest.encryptDecryptResponse ?: "", + encryptedData = bunkerRequest.encryptedData, shouldRunOnAccept = acceptOrReject, appName = appName, type = type, onAccept = { - val result = bunkerRequest.encryptDecryptResponse ?: "" + val result = bunkerRequest.encryptedData?.result ?: "" BunkerRequestUtils.sendResult( context = context, @@ -505,12 +505,12 @@ fun BunkerSingleEventHomeScreen( account = account, modifier = modifier, content = bunkerRequest.request.ciphertext, - encryptedData = bunkerRequest.encryptDecryptResponse ?: "", + encryptedData = bunkerRequest.encryptedData, shouldRunOnAccept = acceptOrReject, appName = appName, type = type, onAccept = { - val result = bunkerRequest.encryptDecryptResponse ?: "" + val result = bunkerRequest.encryptedData?.result ?: "" BunkerRequestUtils.sendResult( context = context, @@ -658,16 +658,16 @@ fun BunkerSingleEventHomeScreen( account = account, modifier = modifier, content = bunkerRequest.request.params[1], - encryptedData = bunkerRequest.encryptDecryptResponse ?: "", + encryptedData = bunkerRequest.encryptedData, shouldRunOnAccept = acceptOrReject, appName = appName, type = type, onAccept = { val result = - if (bunkerRequest.encryptDecryptResponse == "Could not decrypt the message") { + if (bunkerRequest.encryptedData?.result == "Could not decrypt the message") { "" } else { - bunkerRequest.encryptDecryptResponse ?: "" + bunkerRequest.encryptedData?.result ?: "" } BunkerRequestUtils.sendResult( diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt index fd00148f..53089612 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/EncryptDecryptData.kt @@ -1,11 +1,8 @@ package com.greenart7c3.nostrsigner.ui.components -import android.content.ClipData -import android.widget.Toast import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.Card @@ -17,7 +14,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ClipEntry import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -27,7 +23,6 @@ import androidx.compose.ui.text.capitalize import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.intl.Locale import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -42,7 +37,6 @@ import com.greenart7c3.nostrsigner.models.SignerType import com.greenart7c3.nostrsigner.models.TagArrayEncryptedDataKind import com.greenart7c3.nostrsigner.ui.RememberType import com.vitorpamplona.quartz.nip02FollowList.ContactListEvent -import kotlinx.coroutines.launch @Composable fun EncryptDecryptData( @@ -200,7 +194,7 @@ fun BunkerEncryptDecryptData( account: Account, modifier: Modifier, content: String, - encryptedData: String, + encryptedData: EncryptedDataKind?, shouldRunOnAccept: Boolean?, appName: String, type: SignerType, @@ -222,41 +216,91 @@ fun BunkerEncryptDecryptData( ) { ProfilePicture(account) - val message = - when (type) { - SignerType.NIP44_ENCRYPT -> stringResource(R.string.encrypt_nip44) - SignerType.NIP04_ENCRYPT -> stringResource(R.string.encrypt_nip04) - SignerType.NIP44_DECRYPT -> stringResource(R.string.decrypt_nip44) - SignerType.NIP04_DECRYPT -> stringResource(R.string.decrypt_nip04) - SignerType.DECRYPT_ZAP_EVENT -> stringResource(R.string.decrypt_zap_event) - else -> stringResource(R.string.encrypt_decrypt) - } - Text( buildAnnotatedString { withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { append(appName) } - append(" requests $message") + if (type.name.contains("ENCRYPT")) { + when (encryptedData) { + is EventEncryptedDataKind -> { + val permission = Permission("sign_event", encryptedData.event.kind) + append(stringResource(R.string.wants_to_encrypt_with, permission.toLocalizedString(Amber.instance), type.name.split("_").first())) + } + + is TagArrayEncryptedDataKind -> { + append(stringResource(R.string.wants_to_encrypt_this_list_of_tags_with, type.name.split("_").first())) + } + + else -> append(stringResource(R.string.wants_to_encrypt_this_text_with, type.name.split("_").first())) + } + } else { + when (encryptedData) { + is EventEncryptedDataKind -> { + val permission = Permission("sign_event", encryptedData.event.kind) + append(stringResource(R.string.wants_to_read_from_encrypted_content, permission.toLocalizedString(Amber.instance), type.name.split("_").first())) + } + + is TagArrayEncryptedDataKind -> { + append(stringResource(R.string.wants_to_read_this_list_of_tags_from_encrypted_content, type.name.split("_").first())) + } + + else -> append(stringResource(R.string.wants_to_read_this_text_from_encrypted_content, type.name.split("_").first())) + } + } }, fontSize = 18.sp, ) Spacer(Modifier.size(4.dp)) - if (!type.toString().contains("DECRYPT")) { - Card( - modifier = Modifier - .fillMaxWidth(), - ) { - Column(Modifier.padding(6.dp)) { - Text( - "Event content", - fontWeight = FontWeight.Bold, - ) + Card( + modifier = Modifier + .fillMaxWidth(), + ) { + Column(Modifier.padding(6.dp)) { + Text( + stringResource(R.string.content).capitalize(Locale.current), + fontWeight = FontWeight.Bold, + ) + + if (encryptedData is EventEncryptedDataKind) { + if (encryptedData.sealEncryptedDataKind != null) { + if (encryptedData.sealEncryptedDataKind is EventEncryptedDataKind) { + val content = if (encryptedData.sealEncryptedDataKind.event.kind == 22242) encryptedData.sealEncryptedDataKind.event.relay() else encryptedData.sealEncryptedDataKind.event.content + if (encryptedData.event.kind == ContactListEvent.KIND) { + ContactListDetail( + title = stringResource(R.string.following), + text = "${encryptedData.event.verifiedFollowKeySet().size}", + ) + } else { + Text( + content, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + ) + } + } + } else { + val content = if (encryptedData.event.kind == 22242) encryptedData.event.relay() else encryptedData.event.content + if (encryptedData.event.kind == ContactListEvent.KIND) { + ContactListDetail( + title = stringResource(R.string.following), + text = "${encryptedData.event.verifiedFollowKeySet().size}", + ) + } else { + Text( + content, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + ) + } + } + } else { + val content = if (type.name.contains("ENCRYPT") && encryptedData is ClearTextEncryptedDataKind) encryptedData.text else encryptedData?.result ?: "" Text( content, - maxLines = 1, - overflow = TextOverflow.Ellipsis, modifier = Modifier .fillMaxWidth() .padding(top = 8.dp), @@ -264,37 +308,8 @@ fun BunkerEncryptDecryptData( } } } - RawJsonButton( - onCLick = { - showMore = !showMore - }, - if (!showMore) stringResource(R.string.show_details) else stringResource(R.string.hide_details), - ) - if (showMore) { - RawJson( - content, - encryptedData, - Modifier.height(200.dp), - stringResource(R.string.encrypted_decrypted_data), - type, - ) { - coroutineScope.launch { - clipboardManager.setClipEntry( - ClipEntry( - ClipData.newPlainText("", encryptedData), - ), - ) - Toast.makeText( - context, - context.getString(R.string.data_copied_to_the_clipboard), - Toast.LENGTH_SHORT, - ).show() - } - } - } else { - Spacer(modifier = Modifier.weight(1f)) - } + Spacer(modifier = Modifier.weight(1f)) RememberMyChoice( shouldRunOnAccept, diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt index fe7ce4f2..dc9b4604 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/MultiEventHomeScreen.kt @@ -894,7 +894,7 @@ fun BunkerMultiEventHomeScreen( thisAccount.npub, ) - val signature = request.encryptDecryptResponse ?: continue + val signature = request.encryptedData?.result ?: continue val localBunkerRequest = request.copy() BunkerRequestUtils.remove(request.request.id) if (request.checked.value) { diff --git a/app/src/test/java/com/greenart7c3/nostrsigner/models/AmberBunkerRequestTest.kt b/app/src/test/java/com/greenart7c3/nostrsigner/models/AmberBunkerRequestTest.kt deleted file mode 100644 index 2314fc0d..00000000 --- a/app/src/test/java/com/greenart7c3/nostrsigner/models/AmberBunkerRequestTest.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.greenart7c3.nostrsigner.models - -import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.nip46RemoteSigner.BunkerRequestConnect -import org.junit.Assert.assertEquals -import org.junit.Test - -class AmberBunkerRequestTest { - @Test - fun `encryption type survives serialization`() { - val relay = RelayUrlNormalizer.normalizeOrNull("wss://relay.example.com") - requireNotNull(relay) { "Expected relay URL to normalize" } - - val request = - AmberBunkerRequest( - request = BunkerRequestConnect(remoteKey = HEX_KEY, secret = "secret", permissions = null), - localKey = HEX_KEY, - relays = listOf(relay), - currentAccount = "npub1test", - nostrConnectSecret = "secret", - closeApplication = true, - name = "Test App", - signedEvent = null, - encryptDecryptResponse = null, - encryptionType = EncryptionType.NIP04, - ) - - val json = request.toJson() - val roundTrip = AmberBunkerRequest.mapper.readValue(json, AmberBunkerRequest::class.java) - - assertEquals(EncryptionType.NIP04, roundTrip.encryptionType) - } - - private companion object { - private const val HEX_KEY = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" - } -}