mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-06 03:18:23 +00:00
Merge pull request #317 from greenart7c3/claude/per-relay-auth-permissions-9KU65
Add NIP-42 relay authentication (kind 22242) support
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 17,
|
||||
"identityHash": "cc242d2c391a6dec67e7613458bffd30",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "application",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `name` TEXT NOT NULL, `relays` TEXT NOT NULL, `url` TEXT NOT NULL, `icon` TEXT NOT NULL, `description` TEXT NOT NULL, `pubKey` TEXT NOT NULL, `isConnected` INTEGER NOT NULL, `secret` TEXT NOT NULL, `useSecret` INTEGER NOT NULL, `signPolicy` INTEGER NOT NULL, `closeApplication` INTEGER NOT NULL, `deleteAfter` INTEGER NOT NULL, `lastUsed` INTEGER NOT NULL, PRIMARY KEY(`key`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "key",
|
||||
"columnName": "key",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "relays",
|
||||
"columnName": "relays",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "icon",
|
||||
"columnName": "icon",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "description",
|
||||
"columnName": "description",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "pubKey",
|
||||
"columnName": "pubKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isConnected",
|
||||
"columnName": "isConnected",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "secret",
|
||||
"columnName": "secret",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "useSecret",
|
||||
"columnName": "useSecret",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "signPolicy",
|
||||
"columnName": "signPolicy",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "closeApplication",
|
||||
"columnName": "closeApplication",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "deleteAfter",
|
||||
"columnName": "deleteAfter",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "lastUsed",
|
||||
"columnName": "lastUsed",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"key"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "index_key",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"key"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_key` ON `${TABLE_NAME}` (`key`)"
|
||||
},
|
||||
{
|
||||
"name": "index_name",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"name"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "applicationPermission",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `acceptable` INTEGER NOT NULL, `rememberType` INTEGER NOT NULL, `acceptUntil` INTEGER NOT NULL, `rejectUntil` INTEGER NOT NULL, `relay` TEXT NOT NULL, PRIMARY KEY(`id`), FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER"
|
||||
},
|
||||
{
|
||||
"fieldPath": "pkKey",
|
||||
"columnName": "pkKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "kind",
|
||||
"columnName": "kind",
|
||||
"affinity": "INTEGER"
|
||||
},
|
||||
{
|
||||
"fieldPath": "acceptable",
|
||||
"columnName": "acceptable",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "rememberType",
|
||||
"columnName": "rememberType",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "acceptUntil",
|
||||
"columnName": "acceptUntil",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "rejectUntil",
|
||||
"columnName": "rejectUntil",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "relay",
|
||||
"columnName": "relay",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "permissions_by_pk_key",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pkKey"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `permissions_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
|
||||
},
|
||||
{
|
||||
"name": "permissions_unique",
|
||||
"unique": true,
|
||||
"columnNames": [
|
||||
"pkKey",
|
||||
"type",
|
||||
"kind",
|
||||
"relay"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `permissions_unique` ON `${TABLE_NAME}` (`pkKey`, `type`, `kind`, `relay`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "application",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"pkKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"key"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cc242d2c391a6dec67e7613458bffd30')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import com.greenart7c3.nostrsigner.models.SignerType
|
||||
import com.greenart7c3.nostrsigner.models.kindToNip
|
||||
import com.greenart7c3.nostrsigner.service.AmberUtils
|
||||
import com.greenart7c3.nostrsigner.service.IntentUtils
|
||||
import com.greenart7c3.nostrsigner.service.model.AmberEvent
|
||||
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent
|
||||
import com.vitorpamplona.quartz.utils.Hex
|
||||
@@ -175,7 +176,12 @@ class SignerProvider : ContentProvider() {
|
||||
|
||||
val database = Amber.instance.getDatabase(account.npub)
|
||||
val historyDatabase = Amber.instance.getHistoryDatabase(account.npub)
|
||||
var permission =
|
||||
var permission = if (event.kind == 22242) {
|
||||
// Kind 22242 = relay client auth (NIP-42): check relay-specific permission first
|
||||
val relayUrl = AmberEvent.relay(event) ?: ""
|
||||
database.dao().getPermissionForRelay(packageName, "SIGN_EVENT", 22242, relayUrl)
|
||||
?: database.dao().getWildcardRelayPermission(packageName, "SIGN_EVENT", 22242)
|
||||
} else {
|
||||
database
|
||||
.dao()
|
||||
.getPermission(
|
||||
@@ -183,7 +189,8 @@ class SignerProvider : ContentProvider() {
|
||||
"SIGN_EVENT",
|
||||
event.kind,
|
||||
)
|
||||
if (permission == null) {
|
||||
}
|
||||
if (permission == null && event.kind != 22242) {
|
||||
event.kind.kindToNip()?.let {
|
||||
val nipNumber = it.toIntOrNull()
|
||||
permission = if (nipNumber == null) {
|
||||
|
||||
@@ -148,12 +148,20 @@ val MIGRATION_15_16 = object : Migration(15, 16) {
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_16_17 = object : Migration(16, 17) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL("ALTER TABLE `applicationPermission` ADD COLUMN `relay` TEXT NOT NULL DEFAULT ''")
|
||||
db.execSQL("DROP INDEX IF EXISTS `permissions_unique`")
|
||||
db.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `permissions_unique` ON `applicationPermission` (`pkKey`, `type`, `kind`, `relay`)")
|
||||
}
|
||||
}
|
||||
|
||||
@Database(
|
||||
entities = [
|
||||
ApplicationEntity::class,
|
||||
ApplicationPermissionsEntity::class,
|
||||
],
|
||||
version = 16,
|
||||
version = 17,
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
@@ -190,6 +198,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
.addMigrations(MIGRATION_13_14)
|
||||
.addMigrations(MIGRATION_14_15)
|
||||
.addMigrations(MIGRATION_15_16)
|
||||
.addMigrations(MIGRATION_16_17)
|
||||
.build()
|
||||
|
||||
instance
|
||||
|
||||
@@ -59,7 +59,7 @@ interface ApplicationDao {
|
||||
@Transaction
|
||||
fun getAllAcceptedPermissions(): List<ApplicationPermissionsEntity>
|
||||
|
||||
@Query("SELECT * FROM applicationPermission WHERE pkKey = :key AND type = :type AND kind = :kind")
|
||||
@Query("SELECT * FROM applicationPermission WHERE pkKey = :key AND type = :type AND kind = :kind AND relay = ''")
|
||||
fun getPermission(
|
||||
key: String,
|
||||
type: String,
|
||||
@@ -72,6 +72,21 @@ interface ApplicationDao {
|
||||
type: String,
|
||||
): ApplicationPermissionsEntity?
|
||||
|
||||
@Query("SELECT * FROM applicationPermission WHERE pkKey = :key AND type = :type AND kind = :kind AND relay = :relay LIMIT 1")
|
||||
fun getPermissionForRelay(
|
||||
key: String,
|
||||
type: String,
|
||||
kind: Int,
|
||||
relay: String,
|
||||
): ApplicationPermissionsEntity?
|
||||
|
||||
@Query("SELECT * FROM applicationPermission WHERE pkKey = :key AND type = :type AND kind = :kind AND relay = '*' LIMIT 1")
|
||||
fun getWildcardRelayPermission(
|
||||
key: String,
|
||||
type: String,
|
||||
kind: Int,
|
||||
): ApplicationPermissionsEntity?
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
@Transaction
|
||||
suspend fun insertApplication(event: ApplicationEntity): Long?
|
||||
@@ -84,7 +99,17 @@ interface ApplicationDao {
|
||||
suspend fun insertPermissions(permissions: List<ApplicationPermissionsEntity>): List<Long>? {
|
||||
permissions.forEach {
|
||||
if (it.kind != null) {
|
||||
deletePermissions(it.pkKey, it.type, it.kind)
|
||||
if (it.relay.isNotEmpty()) {
|
||||
// For relay-specific permissions (kind 22242): wildcard "*" clears all relay entries,
|
||||
// specific relay only clears its own entry
|
||||
if (it.relay == "*") {
|
||||
deletePermissionsForKind(it.pkKey, it.type, it.kind)
|
||||
} else {
|
||||
deletePermissions(it.pkKey, it.type, it.kind, it.relay)
|
||||
}
|
||||
} else {
|
||||
deletePermissions(it.pkKey, it.type, it.kind)
|
||||
}
|
||||
} else {
|
||||
deletePermissions(it.pkKey, it.type)
|
||||
}
|
||||
@@ -107,7 +132,7 @@ interface ApplicationDao {
|
||||
type: String,
|
||||
)
|
||||
|
||||
@Query("DELETE FROM applicationPermission WHERE pkKey = :key AND type = :type and kind = :kind")
|
||||
@Query("DELETE FROM applicationPermission WHERE pkKey = :key AND type = :type AND kind = :kind AND relay = ''")
|
||||
@Transaction
|
||||
suspend fun deletePermissions(
|
||||
key: String,
|
||||
@@ -115,6 +140,23 @@ interface ApplicationDao {
|
||||
kind: Int,
|
||||
)
|
||||
|
||||
@Query("DELETE FROM applicationPermission WHERE pkKey = :key AND type = :type AND kind = :kind AND relay = :relay")
|
||||
@Transaction
|
||||
suspend fun deletePermissions(
|
||||
key: String,
|
||||
type: String,
|
||||
kind: Int,
|
||||
relay: String,
|
||||
)
|
||||
|
||||
@Query("DELETE FROM applicationPermission WHERE pkKey = :key AND type = :type AND kind = :kind")
|
||||
@Transaction
|
||||
suspend fun deletePermissionsForKind(
|
||||
key: String,
|
||||
type: String,
|
||||
kind: Int,
|
||||
)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
@Transaction
|
||||
suspend fun insertApplicationWithPermissions(application: ApplicationWithPermissions) {
|
||||
|
||||
+2
-1
@@ -21,7 +21,7 @@ import androidx.room.PrimaryKey
|
||||
name = "permissions_by_pk_key",
|
||||
),
|
||||
Index(
|
||||
value = ["pkKey", "type", "kind"],
|
||||
value = ["pkKey", "type", "kind", "relay"],
|
||||
name = "permissions_unique",
|
||||
unique = true,
|
||||
),
|
||||
@@ -37,4 +37,5 @@ data class ApplicationPermissionsEntity(
|
||||
val rememberType: Int,
|
||||
var acceptUntil: Long,
|
||||
var rejectUntil: Long,
|
||||
val relay: String = "",
|
||||
)
|
||||
|
||||
@@ -81,6 +81,7 @@ object AmberUtils {
|
||||
value: Boolean,
|
||||
rememberType: RememberType,
|
||||
account: Account,
|
||||
relay: String = "",
|
||||
) {
|
||||
val until = when (rememberType) {
|
||||
RememberType.ALWAYS -> Long.MAX_VALUE / 1000
|
||||
@@ -91,7 +92,17 @@ object AmberUtils {
|
||||
}
|
||||
|
||||
if (kind != null) {
|
||||
application.permissions.removeIf { it.kind == kind && it.type == signerType.toString() }
|
||||
if (relay.isNotEmpty()) {
|
||||
// For relay-specific permissions: wildcard "*" removes all relay entries for this kind,
|
||||
// specific relay removes only its own entry
|
||||
if (relay == "*") {
|
||||
application.permissions.removeIf { it.kind == kind && it.type == signerType.toString() }
|
||||
} else {
|
||||
application.permissions.removeIf { it.kind == kind && it.type == signerType.toString() && it.relay == relay }
|
||||
}
|
||||
} else {
|
||||
application.permissions.removeIf { it.kind == kind && it.type == signerType.toString() && it.relay.isEmpty() }
|
||||
}
|
||||
} else {
|
||||
application.permissions.removeIf { it.type == signerType.toString() && it.type != "SIGN_EVENT" }
|
||||
}
|
||||
@@ -106,6 +117,7 @@ object AmberUtils {
|
||||
rememberType.screenCode,
|
||||
if (value) until else 0L,
|
||||
if (!value) until else 0L,
|
||||
relay,
|
||||
),
|
||||
)
|
||||
|
||||
@@ -173,6 +185,7 @@ object AmberUtils {
|
||||
type: SignerType,
|
||||
kind: Int?,
|
||||
rememberType: RememberType,
|
||||
relay: String = "",
|
||||
) {
|
||||
val until = when (rememberType) {
|
||||
RememberType.ALWAYS -> Long.MAX_VALUE / 1000
|
||||
@@ -183,7 +196,15 @@ object AmberUtils {
|
||||
}
|
||||
|
||||
if (kind != null) {
|
||||
application.permissions.removeIf { it.kind == kind && it.type == type.toString() }
|
||||
if (relay.isNotEmpty()) {
|
||||
if (relay == "*") {
|
||||
application.permissions.removeIf { it.kind == kind && it.type == type.toString() }
|
||||
} else {
|
||||
application.permissions.removeIf { it.kind == kind && it.type == type.toString() && it.relay == relay }
|
||||
}
|
||||
} else {
|
||||
application.permissions.removeIf { it.kind == kind && it.type == type.toString() && it.relay.isEmpty() }
|
||||
}
|
||||
} else {
|
||||
application.permissions.removeIf { it.type == type.toString() && it.type != "SIGN_EVENT" }
|
||||
}
|
||||
@@ -198,6 +219,7 @@ object AmberUtils {
|
||||
rememberType.screenCode,
|
||||
until,
|
||||
0,
|
||||
relay,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -240,6 +240,7 @@ object BunkerRequestUtils {
|
||||
rememberType: RememberType,
|
||||
oldKey: String = "",
|
||||
deleteAfter: Long = 0L,
|
||||
relay: String = "",
|
||||
) {
|
||||
onLoading(true)
|
||||
Amber.instance.applicationIOScope.launch {
|
||||
@@ -319,6 +320,7 @@ object BunkerRequestUtils {
|
||||
type = type,
|
||||
kind = kind,
|
||||
rememberType = rememberType,
|
||||
relay = relay,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -434,6 +436,7 @@ object BunkerRequestUtils {
|
||||
signerType: SignerType,
|
||||
kind: Int?,
|
||||
onLoading: (Boolean) -> Unit,
|
||||
relay: String = "",
|
||||
) {
|
||||
onLoading(true)
|
||||
Amber.instance.applicationIOScope.launch(Dispatchers.IO) {
|
||||
@@ -481,6 +484,7 @@ object BunkerRequestUtils {
|
||||
false,
|
||||
rememberType,
|
||||
account,
|
||||
relay,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -681,6 +681,7 @@ object IntentUtils {
|
||||
shouldCloseApplication: Boolean? = null,
|
||||
rememberType: RememberType,
|
||||
deleteAfter: Long = 0L,
|
||||
relay: String = "",
|
||||
) {
|
||||
onLoading(true)
|
||||
Amber.instance.applicationIOScope.launch {
|
||||
@@ -732,6 +733,7 @@ object IntentUtils {
|
||||
type = intentData.type,
|
||||
kind = kind,
|
||||
rememberType = rememberType,
|
||||
relay = relay,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -864,6 +866,7 @@ object IntentUtils {
|
||||
kind: Int?,
|
||||
onLoading: (Boolean) -> Unit,
|
||||
onRemoveIntentData: (List<IntentData>, IntentResultType) -> Unit,
|
||||
relay: String = "",
|
||||
) {
|
||||
Amber.instance.applicationIOScope.launch(Dispatchers.IO) {
|
||||
if (key == "null") {
|
||||
@@ -901,6 +904,7 @@ object IntentUtils {
|
||||
false,
|
||||
rememberType,
|
||||
account,
|
||||
relay,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||
import com.vitorpamplona.quartz.nip01Core.core.HexKey
|
||||
import com.vitorpamplona.quartz.nip01Core.jackson.JacksonMapper
|
||||
import com.vitorpamplona.quartz.nip01Core.jackson.toTypedArray
|
||||
import com.vitorpamplona.quartz.nip01Core.signers.EventTemplate
|
||||
import com.vitorpamplona.quartz.nip02FollowList.tags.ContactTag
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
|
||||
@@ -102,5 +103,7 @@ open class AmberEvent(
|
||||
fun fromJson(json: String): AmberEvent = mapper.readValue(json, AmberEvent::class.java)
|
||||
|
||||
fun relay(event: Event): String? = event.tags.filter { it.size > 1 && it[0] == "relay" }.map { it[1] }.firstOrNull()
|
||||
|
||||
fun relay(event: EventTemplate<Event>): String? = event.tags.filter { it.size > 1 && it[0] == "relay" }.map { it[1] }.firstOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ fun PermissionRow(
|
||||
onDelete: (ApplicationPermissionsEntity) -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val message = remember(permission.type, permission.kind, permission.acceptable) {
|
||||
val message = remember(permission.type, permission.kind, permission.acceptable, permission.relay) {
|
||||
val localPermission = Permission(
|
||||
permission.type.toLowerCase(Locale.current),
|
||||
permission.kind,
|
||||
@@ -344,6 +344,22 @@ fun PermissionRow(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
if (permission.kind == 22242 && permission.relay.isNotEmpty()) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
text = if (permission.relay == "*") {
|
||||
context.getString(R.string.for_all_relays)
|
||||
} else {
|
||||
permission.relay
|
||||
},
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
|
||||
AmberToggles(
|
||||
count = 3,
|
||||
selectedIndex = optionIndex,
|
||||
|
||||
@@ -20,15 +20,17 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun AmberToggles(
|
||||
selectedIndex: Int,
|
||||
count: Int,
|
||||
segmentWidth: Dp = 55.dp,
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
val fixedSegmentWidth = 55.dp
|
||||
val fixedSegmentWidth = segmentWidth
|
||||
val padding = 2.dp
|
||||
val totalWidth = (fixedSegmentWidth * count) + (padding * 2)
|
||||
|
||||
|
||||
+46
-1
@@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
@@ -38,6 +39,7 @@ import com.greenart7c3.nostrsigner.service.ApplicationNameCache
|
||||
import com.greenart7c3.nostrsigner.service.BunkerRequestUtils
|
||||
import com.greenart7c3.nostrsigner.service.EventNotificationConsumer
|
||||
import com.greenart7c3.nostrsigner.service.MultiEventScreenIntents
|
||||
import com.greenart7c3.nostrsigner.service.model.AmberEvent
|
||||
import com.greenart7c3.nostrsigner.service.toShortenHex
|
||||
import com.greenart7c3.nostrsigner.ui.RememberType
|
||||
import com.greenart7c3.nostrsigner.ui.navigation.Route
|
||||
@@ -103,6 +105,8 @@ fun BunkerMultiEventHomeScreen(
|
||||
var localAccount by remember { mutableStateOf("") }
|
||||
val key = bunkerRequests.first().localKey
|
||||
var rememberType by remember { mutableStateOf(RememberType.NEVER) }
|
||||
var relayAuthScope by remember { mutableStateOf(RelayAuthScope.SPECIFIC) }
|
||||
val hasRelayAuthEvents = groupedEvents.keys.contains(22242)
|
||||
var appName by remember { mutableStateOf(ApplicationNameCache.names["$localAccount-$key"] ?: key.toShortenHex()) }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
@@ -223,6 +227,34 @@ fun BunkerMultiEventHomeScreen(
|
||||
}
|
||||
}
|
||||
|
||||
if (hasRelayAuthEvents) {
|
||||
LabeledBorderBox(
|
||||
label = stringResource(R.string.relay_auth_scope),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 4.dp, vertical = 8.dp),
|
||||
) {
|
||||
AmberToggles(
|
||||
selectedIndex = if (relayAuthScope == RelayAuthScope.SPECIFIC) 0 else 1,
|
||||
count = 2,
|
||||
segmentWidth = 120.dp,
|
||||
) {
|
||||
ToggleOption(
|
||||
modifier = Modifier.width(120.dp),
|
||||
text = stringResource(R.string.for_this_relay_only),
|
||||
isSelected = relayAuthScope == RelayAuthScope.SPECIFIC,
|
||||
onClick = { relayAuthScope = RelayAuthScope.SPECIFIC },
|
||||
)
|
||||
ToggleOption(
|
||||
modifier = Modifier.width(120.dp),
|
||||
text = stringResource(R.string.for_all_relays),
|
||||
isSelected = relayAuthScope == RelayAuthScope.ALL,
|
||||
onClick = { relayAuthScope = RelayAuthScope.ALL },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RememberMyChoice(
|
||||
alwaysShow = true,
|
||||
shouldRunAcceptOrReject = null,
|
||||
@@ -294,14 +326,21 @@ fun BunkerMultiEventHomeScreen(
|
||||
)
|
||||
|
||||
if (request.rememberType.value != RememberType.NEVER && request.checked.value) {
|
||||
val rejectKind = if (request.request is BunkerRequestSign) request.request.event.kind else null
|
||||
val rejectRelay = if (request.request is BunkerRequestSign && request.request.event.kind == 22242) {
|
||||
if (relayAuthScope == RelayAuthScope.ALL) "*" else (AmberEvent.relay(request.request.event) ?: "")
|
||||
} else {
|
||||
""
|
||||
}
|
||||
AmberUtils.acceptOrRejectPermission(
|
||||
application,
|
||||
localKey,
|
||||
BunkerRequestUtils.getTypeFromBunker(request.request),
|
||||
null,
|
||||
rejectKind,
|
||||
false,
|
||||
request.rememberType.value,
|
||||
thisAccount,
|
||||
relay = rejectRelay,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -376,6 +415,11 @@ fun BunkerMultiEventHomeScreen(
|
||||
val localEvent = request.signedEvent!!
|
||||
|
||||
if (request.rememberType.value != RememberType.NEVER && request.checked.value) {
|
||||
val signRelay = if (localEvent.kind == 22242) {
|
||||
if (relayAuthScope == RelayAuthScope.ALL) "*" else (AmberEvent.relay(localEvent) ?: "")
|
||||
} else {
|
||||
""
|
||||
}
|
||||
AmberUtils.acceptOrRejectPermission(
|
||||
application = application,
|
||||
key = localKey,
|
||||
@@ -384,6 +428,7 @@ fun BunkerMultiEventHomeScreen(
|
||||
value = true,
|
||||
rememberType = request.rememberType.value,
|
||||
account = thisAccount,
|
||||
relay = signRelay,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.greenart7c3.nostrsigner.ui.components
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.greenart7c3.nostrsigner.R
|
||||
import com.greenart7c3.nostrsigner.models.Account
|
||||
import com.greenart7c3.nostrsigner.ui.RememberType
|
||||
|
||||
/**
|
||||
* Scope for a kind 22242 relay authentication permission.
|
||||
* [SPECIFIC] means the permission applies only to the specific relay URL in the event.
|
||||
* [ALL] means the permission applies to all relays (wildcard "*").
|
||||
*/
|
||||
enum class RelayAuthScope {
|
||||
SPECIFIC,
|
||||
ALL,
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BunkerRelayAuthScreen(
|
||||
modifier: Modifier,
|
||||
appName: String,
|
||||
relayUrl: String,
|
||||
shouldAcceptOrReject: Boolean?,
|
||||
defaultScope: RelayAuthScope,
|
||||
account: Account,
|
||||
onAccept: (RememberType, RelayAuthScope) -> Unit,
|
||||
onReject: (RememberType, RelayAuthScope) -> Unit,
|
||||
) {
|
||||
var rememberType by remember { mutableStateOf(RememberType.NEVER) }
|
||||
var scope by remember { mutableStateOf(defaultScope) }
|
||||
val scopeIndex by remember(scope) { mutableIntStateOf(if (scope == RelayAuthScope.SPECIFIC) 0 else 1) }
|
||||
|
||||
if (shouldAcceptOrReject != null) {
|
||||
LaunchedEffect(Unit) {
|
||||
if (shouldAcceptOrReject) {
|
||||
onAccept(RememberType.entries[0], scope)
|
||||
} else {
|
||||
onReject(RememberType.entries[0], scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Spacer(Modifier.size(16.dp))
|
||||
|
||||
Text(
|
||||
buildAnnotatedString {
|
||||
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||
append(appName)
|
||||
}
|
||||
append(" ")
|
||||
append(stringResource(R.string.relay_auth_request, ""))
|
||||
},
|
||||
fontSize = 18.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(Modifier.size(8.dp))
|
||||
|
||||
Text(
|
||||
relayUrl,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
|
||||
Spacer(Modifier.size(16.dp))
|
||||
|
||||
SigningAs(account)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
LabeledBorderBox(
|
||||
label = stringResource(R.string.relay_auth_scope),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
) {
|
||||
AmberToggles(
|
||||
selectedIndex = scopeIndex,
|
||||
count = 2,
|
||||
segmentWidth = 120.dp,
|
||||
content = {
|
||||
ToggleOption(
|
||||
modifier = Modifier.width(120.dp),
|
||||
text = stringResource(R.string.for_this_relay_only),
|
||||
isSelected = scope == RelayAuthScope.SPECIFIC,
|
||||
onClick = { scope = RelayAuthScope.SPECIFIC },
|
||||
)
|
||||
ToggleOption(
|
||||
modifier = Modifier.width(120.dp),
|
||||
text = stringResource(R.string.for_all_relays),
|
||||
isSelected = scope == RelayAuthScope.ALL,
|
||||
onClick = { scope = RelayAuthScope.ALL },
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(Modifier.size(8.dp))
|
||||
|
||||
RememberMyChoice(
|
||||
shouldRunAcceptOrReject = null,
|
||||
packageName = null,
|
||||
alwaysShow = true,
|
||||
onAccept = { onAccept(it, scope) },
|
||||
onReject = { onReject(it, scope) },
|
||||
) {
|
||||
rememberType = it
|
||||
}
|
||||
|
||||
AcceptRejectButtons(
|
||||
onAccept = { onAccept(rememberType, scope) },
|
||||
onReject = { onReject(rememberType, scope) },
|
||||
)
|
||||
}
|
||||
}
|
||||
+77
@@ -35,6 +35,7 @@ import com.greenart7c3.nostrsigner.models.SignerType
|
||||
import com.greenart7c3.nostrsigner.models.kindToNip
|
||||
import com.greenart7c3.nostrsigner.service.BunkerRequestUtils
|
||||
import com.greenart7c3.nostrsigner.service.isPrivateEvent
|
||||
import com.greenart7c3.nostrsigner.service.model.AmberEvent
|
||||
import com.greenart7c3.nostrsigner.service.toShortenHex
|
||||
import com.greenart7c3.nostrsigner.ui.RememberType
|
||||
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
|
||||
@@ -616,6 +617,82 @@ fun BunkerSingleEventHomeScreen(
|
||||
Spacer(Modifier.size(8.dp))
|
||||
Text("Not logged in")
|
||||
}
|
||||
} else if (event.kind == 22242) {
|
||||
// Kind 22242 = relay client authentication (NIP-42)
|
||||
// Permission is per-relay URL extracted from the event's "relay" tag
|
||||
val relayUrl = AmberEvent.relay(event) ?: ""
|
||||
|
||||
// Check for a relay-specific permission first, then wildcard "*" (all relays)
|
||||
val permission = applicationEntity?.permissions?.firstOrNull {
|
||||
it.pkKey == key && it.type == type.toString() && it.kind == 22242 && it.relay == relayUrl
|
||||
} ?: applicationEntity?.permissions?.firstOrNull {
|
||||
it.pkKey == key && it.type == type.toString() && it.kind == 22242 && it.relay == "*"
|
||||
}
|
||||
|
||||
val acceptUntil = permission?.acceptUntil ?: 0
|
||||
val rejectUntil = permission?.rejectUntil ?: 0
|
||||
|
||||
val acceptOrReject = if (rejectUntil == 0L && acceptUntil == 0L) {
|
||||
null
|
||||
} else if (rejectUntil > TimeUtils.now() && rejectUntil > 0 && permission?.acceptable == false) {
|
||||
false
|
||||
} else if (acceptUntil > TimeUtils.now() && acceptUntil > 0 && permission?.acceptable == true) {
|
||||
true
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
BunkerRelayAuthScreen(
|
||||
modifier = modifier,
|
||||
appName = appName,
|
||||
relayUrl = relayUrl,
|
||||
shouldAcceptOrReject = acceptOrReject,
|
||||
defaultScope = RelayAuthScope.SPECIFIC,
|
||||
account = account,
|
||||
onAccept = { rememberType, scope ->
|
||||
if (event.pubKey != account.hexKey && !isPrivateEvent(event.kind, event.tags)) {
|
||||
coroutineScope.launch {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.event_pubkey_is_not_equal_to_current_logged_in_user),
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
}
|
||||
return@BunkerRelayAuthScreen
|
||||
}
|
||||
|
||||
val relayPermission = if (scope == RelayAuthScope.ALL) "*" else relayUrl
|
||||
BunkerRequestUtils.sendResult(
|
||||
context = context,
|
||||
account = account,
|
||||
key = key,
|
||||
response = event.toJson(),
|
||||
bunkerRequest = bunkerRequest,
|
||||
kind = event.kind,
|
||||
onLoading = onLoading,
|
||||
permissions = null,
|
||||
appName = appName,
|
||||
signPolicy = null,
|
||||
shouldCloseApplication = bunkerRequest.closeApplication,
|
||||
rememberType = rememberType,
|
||||
relay = relayPermission,
|
||||
)
|
||||
},
|
||||
onReject = { rememberType, scope ->
|
||||
val relayPermission = if (scope == RelayAuthScope.ALL) "*" else relayUrl
|
||||
BunkerRequestUtils.sendRejection(
|
||||
key = key,
|
||||
account = account,
|
||||
bunkerRequest = bunkerRequest,
|
||||
appName = appName,
|
||||
rememberType = rememberType,
|
||||
signerType = type,
|
||||
kind = event.kind,
|
||||
onLoading = onLoading,
|
||||
relay = relayPermission,
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
val permission =
|
||||
applicationEntity?.permissions?.firstOrNull {
|
||||
|
||||
+46
-1
@@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
@@ -41,6 +42,7 @@ import com.greenart7c3.nostrsigner.models.TagArrayEncryptedDataKind
|
||||
import com.greenart7c3.nostrsigner.service.AmberUtils
|
||||
import com.greenart7c3.nostrsigner.service.ApplicationNameCache
|
||||
import com.greenart7c3.nostrsigner.service.MultiEventScreenIntents
|
||||
import com.greenart7c3.nostrsigner.service.model.AmberEvent
|
||||
import com.greenart7c3.nostrsigner.service.toShortenHex
|
||||
import com.greenart7c3.nostrsigner.ui.RememberType
|
||||
import com.greenart7c3.nostrsigner.ui.navigation.Route
|
||||
@@ -105,6 +107,8 @@ fun IntentMultiEventHomeScreen(
|
||||
var localAccount by remember { mutableStateOf("") }
|
||||
val key = "$packageName"
|
||||
var rememberType by remember { mutableStateOf(RememberType.NEVER) }
|
||||
var relayAuthScope by remember { mutableStateOf(RelayAuthScope.SPECIFIC) }
|
||||
val hasRelayAuthEvents = groupedEvents.keys.contains(22242)
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
launch(Dispatchers.IO) {
|
||||
@@ -232,6 +236,34 @@ fun IntentMultiEventHomeScreen(
|
||||
}
|
||||
}
|
||||
|
||||
if (hasRelayAuthEvents) {
|
||||
LabeledBorderBox(
|
||||
label = stringResource(R.string.relay_auth_scope),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 4.dp, vertical = 8.dp),
|
||||
) {
|
||||
AmberToggles(
|
||||
selectedIndex = if (relayAuthScope == RelayAuthScope.SPECIFIC) 0 else 1,
|
||||
count = 2,
|
||||
segmentWidth = 120.dp,
|
||||
) {
|
||||
ToggleOption(
|
||||
modifier = Modifier.width(120.dp),
|
||||
text = stringResource(R.string.for_this_relay_only),
|
||||
isSelected = relayAuthScope == RelayAuthScope.SPECIFIC,
|
||||
onClick = { relayAuthScope = RelayAuthScope.SPECIFIC },
|
||||
)
|
||||
ToggleOption(
|
||||
modifier = Modifier.width(120.dp),
|
||||
text = stringResource(R.string.for_all_relays),
|
||||
isSelected = relayAuthScope == RelayAuthScope.ALL,
|
||||
onClick = { relayAuthScope = RelayAuthScope.ALL },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RememberMyChoice(
|
||||
alwaysShow = true,
|
||||
shouldRunAcceptOrReject = null,
|
||||
@@ -298,14 +330,21 @@ fun IntentMultiEventHomeScreen(
|
||||
)
|
||||
|
||||
if (intentData.rememberType.value != RememberType.NEVER && intentData.checked.value) {
|
||||
val rejectKind = if (intentData.type == SignerType.SIGN_EVENT) intentData.event?.kind else null
|
||||
val rejectRelay = if (intentData.type == SignerType.SIGN_EVENT && intentData.event?.kind == 22242) {
|
||||
if (relayAuthScope == RelayAuthScope.ALL) "*" else (intentData.event?.let { AmberEvent.relay(it) } ?: "")
|
||||
} else {
|
||||
""
|
||||
}
|
||||
AmberUtils.acceptOrRejectPermission(
|
||||
application,
|
||||
localKey,
|
||||
intentData.type,
|
||||
null,
|
||||
rejectKind,
|
||||
false,
|
||||
intentData.rememberType.value,
|
||||
thisAccount,
|
||||
relay = rejectRelay,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -388,6 +427,11 @@ fun IntentMultiEventHomeScreen(
|
||||
val localEvent = intentData.event!!
|
||||
|
||||
if (intentData.rememberType.value != RememberType.NEVER && intentData.checked.value) {
|
||||
val signRelay = if (localEvent.kind == 22242) {
|
||||
if (relayAuthScope == RelayAuthScope.ALL) "*" else (AmberEvent.relay(localEvent) ?: "")
|
||||
} else {
|
||||
""
|
||||
}
|
||||
AmberUtils.acceptOrRejectPermission(
|
||||
application,
|
||||
localKey,
|
||||
@@ -396,6 +440,7 @@ fun IntentMultiEventHomeScreen(
|
||||
true,
|
||||
intentData.rememberType.value,
|
||||
thisAccount,
|
||||
relay = signRelay,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+70
@@ -30,6 +30,7 @@ import com.greenart7c3.nostrsigner.models.SignerType
|
||||
import com.greenart7c3.nostrsigner.models.kindToNip
|
||||
import com.greenart7c3.nostrsigner.service.IntentUtils
|
||||
import com.greenart7c3.nostrsigner.service.isPrivateEvent
|
||||
import com.greenart7c3.nostrsigner.service.model.AmberEvent
|
||||
import com.greenart7c3.nostrsigner.service.toShortenHex
|
||||
import com.greenart7c3.nostrsigner.ui.ToastManager
|
||||
import com.vitorpamplona.quartz.nip01Core.core.toHexKey
|
||||
@@ -242,6 +243,75 @@ fun IntentSingleEventHomeScreen(
|
||||
Spacer(Modifier.size(8.dp))
|
||||
Text("Not logged in")
|
||||
}
|
||||
} else if (event.kind == 22242) {
|
||||
// Kind 22242 = relay client authentication (NIP-42)
|
||||
// Permission is per-relay URL extracted from the event's "relay" tag
|
||||
val relayUrl = AmberEvent.relay(event) ?: ""
|
||||
|
||||
// Check for relay-specific permission first, then wildcard "*" (all relays)
|
||||
val permission = applicationEntity?.permissions?.firstOrNull {
|
||||
it.pkKey == key && it.type == intentData.type.toString() && it.kind == 22242 && it.relay == relayUrl
|
||||
} ?: applicationEntity?.permissions?.firstOrNull {
|
||||
it.pkKey == key && it.type == intentData.type.toString() && it.kind == 22242 && it.relay == "*"
|
||||
}
|
||||
|
||||
val acceptOrReject = if (permission == null) {
|
||||
IntentUtils.isRemembered(applicationEntity?.application?.signPolicy, null)
|
||||
} else {
|
||||
IntentUtils.isRemembered(applicationEntity?.application?.signPolicy, permission)
|
||||
}
|
||||
|
||||
BunkerRelayAuthScreen(
|
||||
modifier = modifier,
|
||||
appName = appName,
|
||||
relayUrl = relayUrl,
|
||||
shouldAcceptOrReject = acceptOrReject,
|
||||
defaultScope = RelayAuthScope.SPECIFIC,
|
||||
account = account,
|
||||
onAccept = { rememberType, scope ->
|
||||
if (intentData.unsignedEventKey.isNotBlank() && intentData.unsignedEventKey != account.hexKey && !isPrivateEvent(event.kind, event.tags)) {
|
||||
ToastManager.toast(
|
||||
title = context.getString(R.string.warning),
|
||||
message = context.getString(R.string.event_pubkey_is_not_equal_to_current_logged_in_user),
|
||||
)
|
||||
return@BunkerRelayAuthScreen
|
||||
}
|
||||
|
||||
val relayPermission = if (scope == RelayAuthScope.ALL) "*" else relayUrl
|
||||
IntentUtils.sendResult(
|
||||
context = context,
|
||||
packageName = packageName,
|
||||
account = account,
|
||||
key = key,
|
||||
clipboardManager = clipboardManager,
|
||||
event = event.toJson(),
|
||||
value = event.sig,
|
||||
intentData = intentData,
|
||||
kind = event.kind,
|
||||
onLoading = onLoading,
|
||||
onRemoveIntentData = onRemoveIntentData,
|
||||
signPolicy = null,
|
||||
appName = applicationName ?: appName,
|
||||
permissions = null,
|
||||
rememberType = rememberType,
|
||||
relay = relayPermission,
|
||||
)
|
||||
},
|
||||
onReject = { rememberType, scope ->
|
||||
val relayPermission = if (scope == RelayAuthScope.ALL) "*" else relayUrl
|
||||
IntentUtils.sendRejection(
|
||||
key = key,
|
||||
account = account,
|
||||
intentData = intentData,
|
||||
appName = appName,
|
||||
rememberType = rememberType,
|
||||
onLoading = onLoading,
|
||||
onRemoveIntentData = onRemoveIntentData,
|
||||
kind = event.kind,
|
||||
relay = relayPermission,
|
||||
)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
val permission =
|
||||
applicationEntity?.permissions?.firstOrNull {
|
||||
|
||||
@@ -645,4 +645,9 @@
|
||||
<string name="account_picture">Account picture</string>
|
||||
<string name="encrypt_and_copy_to_clipboard">Encrypt and copy to clipboard</string>
|
||||
<string name="encrypt_and_show_qr_code">Encrypt and show QR Code</string>
|
||||
<string name="relay_authentication">Relay authentication</string>
|
||||
<string name="relay_auth_request">%1$s wants to authenticate to relay</string>
|
||||
<string name="for_this_relay_only">This relay only</string>
|
||||
<string name="for_all_relays">All relays</string>
|
||||
<string name="relay_auth_scope">Authentication scope</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user