diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt b/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt index 2f1e13b0..da3de199 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/SignerProvider.kt @@ -10,6 +10,7 @@ import com.greenart7c3.nostrsigner.database.HistoryEntity import com.greenart7c3.nostrsigner.database.LogEntity import com.greenart7c3.nostrsigner.models.SignerType import com.greenart7c3.nostrsigner.models.kindToNip +import com.greenart7c3.nostrsigner.models.permissionTypeFromContent import com.greenart7c3.nostrsigner.service.AmberUtils import com.greenart7c3.nostrsigner.service.IntentUtils import com.greenart7c3.nostrsigner.service.model.AmberEvent @@ -287,13 +288,59 @@ class SignerProvider : ContentProvider() { val database = Amber.instance.getDatabase(account.npub) val logDatabase = Amber.instance.getLogDatabase(account.npub) val historyDatabase = Amber.instance.getHistoryDatabase(account.npub) - var permission = - database - .dao() - .getPermission( - packageName, - uri.toString().replace("content://$appId.", ""), - ) + val type = + when (stringType) { + "NIP04_DECRYPT" -> SignerType.NIP04_DECRYPT + "NIP44_DECRYPT" -> SignerType.NIP44_DECRYPT + "NIP04_ENCRYPT" -> SignerType.NIP04_ENCRYPT + "NIP44_ENCRYPT" -> SignerType.NIP44_ENCRYPT + "DECRYPT_ZAP_EVENT" -> SignerType.DECRYPT_ZAP_EVENT + else -> null + } ?: return null + + val isEncrypt = type == SignerType.NIP04_ENCRYPT || type == SignerType.NIP44_ENCRYPT + + // For ENCRYPT: classify plaintext input; for DECRYPT: perform operation first then classify result + val result = + if (isEncrypt) { + null // defer until after permission check + } else { + try { + runBlocking { + AmberUtils.encryptOrDecryptData( + content, + type, + account, + pubkey, + ) ?: "Could not decrypt the message" + } + } catch (e: Exception) { + scope.launch { + logDatabase.dao().insertLog( + LogEntity( + 0, + packageName, + uri.toString().replace("content://$appId.", ""), + e.message ?: "Could not decrypt the message", + System.currentTimeMillis(), + ), + ) + } + "Could not decrypt the message" + } + } + + // Classify the content to determine EncryptedDataKind-based permission type + val classifyContent = if (isEncrypt) content else (result ?: content) + val permType = permissionTypeFromContent(classifyContent, isEncrypt, type) + + var permission = database.dao().getPermission(packageName, permType) + if (permission == null) { + permission = database.dao().getPermission( + packageName, + type.toString(), + ) + } if (permission == null) { val nip = when (stringType) { "NIP04_DECRYPT" -> 4 @@ -340,18 +387,9 @@ class SignerProvider : ContentProvider() { return cursor } - val type = - when (stringType) { - "NIP04_DECRYPT" -> SignerType.NIP04_DECRYPT - "NIP44_DECRYPT" -> SignerType.NIP44_DECRYPT - "NIP04_ENCRYPT" -> SignerType.NIP04_ENCRYPT - "NIP44_ENCRYPT" -> SignerType.NIP44_ENCRYPT - "DECRYPT_ZAP_EVENT" -> SignerType.DECRYPT_ZAP_EVENT - else -> null - } ?: return null - - val result = - try { + // For encrypt: perform the operation now after permission is confirmed + val finalResult = + result ?: try { runBlocking { AmberUtils.encryptOrDecryptData( content, @@ -384,14 +422,14 @@ class SignerProvider : ContentProvider() { null, TimeUtils.now(), true, - content = if (type == SignerType.NIP04_DECRYPT || type == SignerType.NIP44_DECRYPT || type == SignerType.DECRYPT_ZAP_EVENT) result else content, + content = if (!isEncrypt) finalResult else content, ), account.npub, ) } val cursor = MatrixCursor(arrayOf("signature", "event", "result")) - cursor.addRow(arrayOf(result, result, result)) + cursor.addRow(arrayOf(finalResult, finalResult, finalResult)) return cursor } diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/models/BasicPermissions.kt b/app/src/main/java/com/greenart7c3/nostrsigner/models/BasicPermissions.kt index 710b19de..d6cd67e2 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/models/BasicPermissions.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/models/BasicPermissions.kt @@ -2,10 +2,12 @@ package com.greenart7c3.nostrsigner.models val basicPermissions = listOf( Permission("get_public_key", null), - Permission("nip04_encrypt", null), - Permission("nip04_decrypt", null), - Permission("nip44_decrypt", null), - Permission("nip44_encrypt", null), + Permission("encrypt_clear_text", null), + Permission("decrypt_clear_text", null), + Permission("encrypt_event", null), + Permission("decrypt_event", null), + Permission("encrypt_tag_array", null), + Permission("decrypt_tag_array", null), Permission("decrypt_zap_event", null), Permission("sign_event", 0), Permission("sign_event", 1), diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/models/EncryptedDataKind.kt b/app/src/main/java/com/greenart7c3/nostrsigner/models/EncryptedDataKind.kt index 1ff84116..91962683 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/models/EncryptedDataKind.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/models/EncryptedDataKind.kt @@ -13,3 +13,39 @@ class TagArrayEncryptedDataKind(val tagArray: Array>, override val class EventEncryptedDataKind(val event: AmberEvent, val sealEncryptedDataKind: EncryptedDataKind?, override val result: String) : EncryptedDataKind class PrivateZapEncryptedDataKind(override val result: String) : EncryptedDataKind + +fun EncryptedDataKind?.toPermissionType(isEncrypt: Boolean): String = when (this) { + is ClearTextEncryptedDataKind -> if (isEncrypt) "ENCRYPT_CLEAR_TEXT" else "DECRYPT_CLEAR_TEXT" + is TagArrayEncryptedDataKind -> if (isEncrypt) "ENCRYPT_TAG_ARRAY" else "DECRYPT_TAG_ARRAY" + is EventEncryptedDataKind -> if (isEncrypt) "ENCRYPT_EVENT" else "DECRYPT_EVENT" + is PrivateZapEncryptedDataKind -> "DECRYPT_ZAP_EVENT" + null -> if (isEncrypt) "ENCRYPT_CLEAR_TEXT" else "DECRYPT_CLEAR_TEXT" + else -> if (isEncrypt) "ENCRYPT_CLEAR_TEXT" else "DECRYPT_CLEAR_TEXT" +} + +fun SignerType.toPermissionTypeString(encryptedData: EncryptedDataKind?): String = when (this) { + SignerType.NIP04_ENCRYPT, SignerType.NIP44_ENCRYPT -> encryptedData.toPermissionType(isEncrypt = true) + SignerType.NIP04_DECRYPT, SignerType.NIP44_DECRYPT -> encryptedData.toPermissionType(isEncrypt = false) + SignerType.DECRYPT_ZAP_EVENT -> "DECRYPT_ZAP_EVENT" + else -> this.toString() +} + +val encryptDecryptSignerTypes = setOf( + SignerType.NIP04_ENCRYPT, + SignerType.NIP44_ENCRYPT, + SignerType.NIP04_DECRYPT, + SignerType.NIP44_DECRYPT, + SignerType.DECRYPT_ZAP_EVENT, +) + +/** + * Determines the permission type string based on content string and operation direction. + * For ENCRYPT: pass the plaintext to classify what kind of data is being encrypted. + * For DECRYPT: pass the decrypted plaintext to classify what was decrypted. + */ +fun permissionTypeFromContent(content: String, isEncrypt: Boolean, signerType: SignerType): String = when { + signerType == SignerType.DECRYPT_ZAP_EVENT -> "DECRYPT_ZAP_EVENT" + content.startsWith("{") -> if (isEncrypt) "ENCRYPT_EVENT" else "DECRYPT_EVENT" + content.startsWith("[") -> if (isEncrypt) "ENCRYPT_TAG_ARRAY" else "DECRYPT_TAG_ARRAY" + else -> if (isEncrypt) "ENCRYPT_CLEAR_TEXT" else "DECRYPT_CLEAR_TEXT" +} diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/models/Permission.kt b/app/src/main/java/com/greenart7c3/nostrsigner/models/Permission.kt index 0813a1eb..1847e503 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/models/Permission.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/models/Permission.kt @@ -84,6 +84,24 @@ data class Permission( "decrypt_zap_event" -> { context.getString(R.string.decrypt_private_zaps) } + "encrypt_clear_text" -> { + context.getString(R.string.encrypt_clear_text) + } + "decrypt_clear_text" -> { + context.getString(R.string.decrypt_clear_text) + } + "encrypt_event" -> { + context.getString(R.string.encrypt_event) + } + "decrypt_event" -> { + context.getString(R.string.decrypt_event) + } + "encrypt_tag_array" -> { + context.getString(R.string.encrypt_tag_array) + } + "decrypt_tag_array" -> { + context.getString(R.string.decrypt_tag_array) + } "sign_event" -> { when (kind) { 0 -> context.getString(R.string.event_kind_0) @@ -577,5 +595,11 @@ val supportedKindNumbers = listOf( Permission("nip44_decrypt", null), Permission("nip44_encrypt", null), Permission("decrypt_zap_event", null), + Permission("encrypt_clear_text", null), + Permission("decrypt_clear_text", null), + Permission("encrypt_event", null), + Permission("decrypt_event", null), + Permission("encrypt_tag_array", null), + Permission("decrypt_tag_array", null), Permission("get_public_key", null), ) diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/service/AmberUtils.kt b/app/src/main/java/com/greenart7c3/nostrsigner/service/AmberUtils.kt index 7e28e66f..c779e9c1 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/service/AmberUtils.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/AmberUtils.kt @@ -8,9 +8,12 @@ import com.greenart7c3.nostrsigner.database.ApplicationPermissionsEntity import com.greenart7c3.nostrsigner.database.ApplicationWithPermissions import com.greenart7c3.nostrsigner.models.Account import com.greenart7c3.nostrsigner.models.AmberBunkerRequest +import com.greenart7c3.nostrsigner.models.EncryptedDataKind import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.models.SignerType import com.greenart7c3.nostrsigner.models.basicPermissions +import com.greenart7c3.nostrsigner.models.encryptDecryptSignerTypes +import com.greenart7c3.nostrsigner.models.toPermissionTypeString import com.greenart7c3.nostrsigner.ui.RememberType import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl @@ -186,6 +189,7 @@ object AmberUtils { kind: Int?, rememberType: RememberType, relay: String = "", + encryptedData: EncryptedDataKind? = null, ) { val until = when (rememberType) { RememberType.ALWAYS -> Long.MAX_VALUE / 1000 @@ -195,25 +199,31 @@ object AmberUtils { else -> 0L } + val permissionTypeStr = type.toPermissionTypeString(encryptedData) + if (kind != null) { if (relay.isNotEmpty()) { if (relay == "*") { - application.permissions.removeIf { it.kind == kind && it.type == type.toString() } + application.permissions.removeIf { it.kind == kind && it.type == permissionTypeStr } } else { - application.permissions.removeIf { it.kind == kind && it.type == type.toString() && it.relay == relay } + application.permissions.removeIf { it.kind == kind && it.type == permissionTypeStr && it.relay == relay } } } else { - application.permissions.removeIf { it.kind == kind && it.type == type.toString() && it.relay.isEmpty() } + application.permissions.removeIf { it.kind == kind && it.type == permissionTypeStr && it.relay.isEmpty() } } } else { - application.permissions.removeIf { it.type == type.toString() && it.type != "SIGN_EVENT" } + application.permissions.removeIf { it.type == permissionTypeStr && it.type != "SIGN_EVENT" } + // Also remove any old NIP-based permission entries for this operation type + if (type in encryptDecryptSignerTypes) { + application.permissions.removeIf { it.type == type.toString() } + } } application.permissions.add( ApplicationPermissionsEntity( null, key, - type.toString(), + permissionTypeStr, kind, true, rememberType.screenCode, diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/service/BunkerRequestUtils.kt b/app/src/main/java/com/greenart7c3/nostrsigner/service/BunkerRequestUtils.kt index e64f5f2b..da376d50 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/service/BunkerRequestUtils.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/BunkerRequestUtils.kt @@ -241,6 +241,7 @@ object BunkerRequestUtils { oldKey: String = "", deleteAfter: Long = 0L, relay: String = "", + encryptedData: com.greenart7c3.nostrsigner.models.EncryptedDataKind? = null, ) { onLoading(true) Amber.instance.applicationIOScope.launch { @@ -321,6 +322,7 @@ object BunkerRequestUtils { kind = kind, rememberType = rememberType, relay = relay, + encryptedData = encryptedData ?: bunkerRequest.encryptedData, ) } 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 a8444639..b4010e7e 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/service/IntentUtils.kt @@ -734,6 +734,7 @@ object IntentUtils { kind = kind, rememberType = rememberType, relay = relay, + encryptedData = intentData.encryptedData, ) } 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 884cdc92..17811c97 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 @@ -33,6 +33,7 @@ import com.greenart7c3.nostrsigner.models.AmberBunkerRequest import com.greenart7c3.nostrsigner.models.Permission import com.greenart7c3.nostrsigner.models.SignerType import com.greenart7c3.nostrsigner.models.kindToNip +import com.greenart7c3.nostrsigner.models.toPermissionType import com.greenart7c3.nostrsigner.service.BunkerRequestUtils import com.greenart7c3.nostrsigner.service.isPrivateEvent import com.greenart7c3.nostrsigner.service.model.AmberEvent @@ -336,10 +337,17 @@ fun BunkerSingleEventHomeScreen( is BunkerRequestNip04Encrypt -> { val nip = 4 + val permType = bunkerRequest.encryptedData.toPermissionType(isEncrypt = true) var permission = applicationEntity?.permissions?.firstOrNull { - it.pkKey == key && it.type == type.toString() + it.pkKey == key && it.type == permType } + if (permission == null) { + permission = + applicationEntity?.permissions?.firstOrNull { + it.pkKey == key && it.type == type.toString() + } + } if (permission == null) { permission = applicationEntity?.permissions?.firstOrNull { @@ -400,10 +408,17 @@ fun BunkerSingleEventHomeScreen( is BunkerRequestNip04Decrypt -> { val nip = 4 + val permType = bunkerRequest.encryptedData.toPermissionType(isEncrypt = false) var permission = applicationEntity?.permissions?.firstOrNull { - it.pkKey == key && it.type == type.toString() + it.pkKey == key && it.type == permType } + if (permission == null) { + permission = + applicationEntity?.permissions?.firstOrNull { + it.pkKey == key && it.type == type.toString() + } + } if (permission == null) { permission = applicationEntity?.permissions?.firstOrNull { @@ -466,10 +481,17 @@ fun BunkerSingleEventHomeScreen( is BunkerRequestNip44Encrypt -> { val nip = 44 + val permType = bunkerRequest.encryptedData.toPermissionType(isEncrypt = true) var permission = applicationEntity?.permissions?.firstOrNull { - it.pkKey == key && it.type == type.toString() + it.pkKey == key && it.type == permType } + if (permission == null) { + permission = + applicationEntity?.permissions?.firstOrNull { + it.pkKey == key && it.type == type.toString() + } + } if (permission == null) { permission = applicationEntity?.permissions?.firstOrNull { @@ -532,10 +554,17 @@ fun BunkerSingleEventHomeScreen( is BunkerRequestNip44Decrypt -> { val nip = 44 + val permType = bunkerRequest.encryptedData.toPermissionType(isEncrypt = false) var permission = applicationEntity?.permissions?.firstOrNull { - it.pkKey == key && it.type == type.toString() + it.pkKey == key && it.type == permType } + if (permission == null) { + permission = + applicationEntity?.permissions?.firstOrNull { + it.pkKey == key && it.type == type.toString() + } + } if (permission == null) { permission = applicationEntity?.permissions?.firstOrNull { diff --git a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/IntentSingleEventHomeScreen.kt b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/IntentSingleEventHomeScreen.kt index 2c8151bb..366f95db 100644 --- a/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/IntentSingleEventHomeScreen.kt +++ b/app/src/main/java/com/greenart7c3/nostrsigner/ui/components/IntentSingleEventHomeScreen.kt @@ -28,6 +28,7 @@ import com.greenart7c3.nostrsigner.models.IntentData import com.greenart7c3.nostrsigner.models.IntentResultType import com.greenart7c3.nostrsigner.models.SignerType import com.greenart7c3.nostrsigner.models.kindToNip +import com.greenart7c3.nostrsigner.models.toPermissionType import com.greenart7c3.nostrsigner.service.IntentUtils import com.greenart7c3.nostrsigner.service.isPrivateEvent import com.greenart7c3.nostrsigner.service.model.AmberEvent @@ -164,10 +165,18 @@ fun IntentSingleEventHomeScreen( SignerType.DECRYPT_ZAP_EVENT -> null else -> null } + val isEncrypt = intentData.type == SignerType.NIP04_ENCRYPT || intentData.type == SignerType.NIP44_ENCRYPT + val permType = intentData.encryptedData.toPermissionType(isEncrypt = isEncrypt) var permission = applicationEntity?.permissions?.firstOrNull { - it.pkKey == key && it.type == intentData.type.toString() + it.pkKey == key && it.type == permType } + if (permission == null) { + permission = + applicationEntity?.permissions?.firstOrNull { + it.pkKey == key && it.type == intentData.type.toString() + } + } if (permission == null && nip != null) { permission = applicationEntity?.permissions?.firstOrNull { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6ca303e0..3e4b7ba8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -134,6 +134,12 @@ Decrypt data using nip 44 Encrypt data using nip 44 Decrypt private zaps + Encrypt text messages + Decrypt text messages + Encrypt events + Decrypt events + Encrypt tag arrays + Decrypt tag arrays Metadata Short text note Follows