mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-05 19:08:23 +00:00
Refactor encrypt/decrypt permissions to be by EncryptedDataKind
Instead of storing permissions as nip04_encrypt, nip44_encrypt, etc. (grouped by encryption algorithm), permissions are now stored based on the type of data being encrypted or decrypted: - ENCRYPT_CLEAR_TEXT / DECRYPT_CLEAR_TEXT (text messages) - ENCRYPT_EVENT / DECRYPT_EVENT (nostr events) - ENCRYPT_TAG_ARRAY / DECRYPT_TAG_ARRAY (tag arrays) - DECRYPT_ZAP_EVENT (private zap events, unchanged) This allows more granular permission control based on what data is being processed rather than which NIP algorithm is used. Backward compatibility is maintained by falling back to old NIP-based permission types during lookup. Key changes: - EncryptedDataKind.kt: add toPermissionType(), toPermissionTypeString(), permissionTypeFromContent() helpers - AmberUtils.acceptPermission(): use EncryptedDataKind-based type when storing - BunkerRequestUtils/IntentUtils: pass encryptedData to acceptPermission - BunkerSingleEventHomeScreen/IntentSingleEventHomeScreen: look up permissions by EncryptedDataKind type with NIP-based fallbacks - SignerProvider: classify content to determine permission type before lookup - BasicPermissions/Permission: add new permission types and string resources https://claude.ai/code/session_01Q7XBgjPSfeVdiQ3smLw7YC
This commit is contained in:
@@ -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<Any>(result, result, result))
|
||||
cursor.addRow(arrayOf<Any>(finalResult, finalResult, finalResult))
|
||||
return cursor
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -13,3 +13,39 @@ class TagArrayEncryptedDataKind(val tagArray: Array<Array<String>>, 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"
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -734,6 +734,7 @@ object IntentUtils {
|
||||
kind = kind,
|
||||
rememberType = rememberType,
|
||||
relay = relay,
|
||||
encryptedData = intentData.encryptedData,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+33
-4
@@ -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 {
|
||||
|
||||
+10
-1
@@ -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 {
|
||||
|
||||
@@ -134,6 +134,12 @@
|
||||
<string name="decrypt_data_using_nip_44">Decrypt data using nip 44</string>
|
||||
<string name="encrypt_data_using_nip_44">Encrypt data using nip 44</string>
|
||||
<string name="decrypt_private_zaps">Decrypt private zaps</string>
|
||||
<string name="encrypt_clear_text">Encrypt text messages</string>
|
||||
<string name="decrypt_clear_text">Decrypt text messages</string>
|
||||
<string name="encrypt_event">Encrypt events</string>
|
||||
<string name="decrypt_event">Decrypt events</string>
|
||||
<string name="encrypt_tag_array">Encrypt tag arrays</string>
|
||||
<string name="decrypt_tag_array">Decrypt tag arrays</string>
|
||||
<string name="event_kind_0">Metadata</string>
|
||||
<string name="event_kind_1">Short text note</string>
|
||||
<string name="event_kind_3">Follows</string>
|
||||
|
||||
Reference in New Issue
Block a user