mirror of
https://github.com/greenart7c3/Amber.git
synced 2026-10-05 19:08:23 +00:00
Finish implementing sign policy
This commit is contained in:
@@ -2,11 +2,11 @@
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 4,
|
||||
"identityHash": "5074b7c061015dc0f49005f018955d21",
|
||||
"identityHash": "ffb55f8c910a34676fa829322921d260",
|
||||
"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, PRIMARY KEY(`key`))",
|
||||
"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, PRIMARY KEY(`key`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "key",
|
||||
@@ -67,6 +67,12 @@
|
||||
"columnName": "useSecret",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "signPolicy",
|
||||
"columnName": "signPolicy",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
@@ -335,7 +341,7 @@
|
||||
"views": [],
|
||||
"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, '5074b7c061015dc0f49005f018955d21')"
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ffb55f8c910a34676fa829322921d260')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,347 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 5,
|
||||
"identityHash": "ffb55f8c910a34676fa829322921d260",
|
||||
"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, 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
|
||||
}
|
||||
],
|
||||
"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`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"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, PRIMARY KEY(`id`), FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "pkKey",
|
||||
"columnName": "pkKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "kind",
|
||||
"columnName": "kind",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "acceptable",
|
||||
"columnName": "acceptable",
|
||||
"affinity": "INTEGER",
|
||||
"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"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `permissions_unique` ON `${TABLE_NAME}` (`pkKey`, `type`, `kind`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "application",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"pkKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"key"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "notification",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `eventId` TEXT NOT NULL, `time` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "eventId",
|
||||
"columnName": "eventId",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "time",
|
||||
"columnName": "time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "history",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `pkKey` TEXT NOT NULL, `type` TEXT NOT NULL, `kind` INTEGER, `time` INTEGER NOT NULL, `accepted` INTEGER NOT NULL, FOREIGN KEY(`pkKey`) REFERENCES `application`(`key`) ON UPDATE NO ACTION ON DELETE CASCADE )",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "pkKey",
|
||||
"columnName": "pkKey",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "kind",
|
||||
"columnName": "kind",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "time",
|
||||
"columnName": "time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "accepted",
|
||||
"columnName": "accepted",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [
|
||||
{
|
||||
"name": "history_by_pk_key",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"pkKey"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_pk_key` ON `${TABLE_NAME}` (`pkKey`)"
|
||||
},
|
||||
{
|
||||
"name": "history_by_id",
|
||||
"unique": false,
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"orders": [],
|
||||
"createSql": "CREATE INDEX IF NOT EXISTS `history_by_id` ON `${TABLE_NAME}` (`id`)"
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"table": "application",
|
||||
"onDelete": "CASCADE",
|
||||
"onUpdate": "NO ACTION",
|
||||
"columns": [
|
||||
"pkKey"
|
||||
],
|
||||
"referencedColumns": [
|
||||
"key"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tableName": "amber_log",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `url` TEXT NOT NULL, `type` TEXT NOT NULL, `message` TEXT NOT NULL, `time` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "url",
|
||||
"columnName": "url",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "type",
|
||||
"columnName": "type",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "message",
|
||||
"columnName": "message",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "time",
|
||||
"columnName": "time",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"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, 'ffb55f8c910a34676fa829322921d260')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -333,6 +333,7 @@ object LocalPreferences {
|
||||
true,
|
||||
"",
|
||||
false,
|
||||
1,
|
||||
),
|
||||
)
|
||||
database.applicationDao().insertPermissions(
|
||||
|
||||
@@ -58,6 +58,7 @@ class SignerProvider : ContentProvider() {
|
||||
val account = LocalPreferences.loadFromEncryptedStorage(context!!, npub) ?: return null
|
||||
val currentSelection = selection ?: "0"
|
||||
val database = NostrSigner.getInstance().getDatabase(account.keyPair.pubKey.toNpub())
|
||||
val signPolicy = database.applicationDao().getSignPolicy(sortOrder ?: packageName)
|
||||
val permission =
|
||||
database
|
||||
.applicationDao()
|
||||
@@ -65,7 +66,7 @@ class SignerProvider : ContentProvider() {
|
||||
sortOrder ?: packageName,
|
||||
"SIGN_MESSAGE",
|
||||
)
|
||||
val isRemembered = permission?.acceptable ?: return null
|
||||
val isRemembered = if (signPolicy == 2) true else permission?.acceptable ?: return null
|
||||
if (!isRemembered) {
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
@@ -136,7 +137,8 @@ class SignerProvider : ContentProvider() {
|
||||
)
|
||||
}
|
||||
}
|
||||
val isRemembered = permission?.acceptable ?: return null
|
||||
val signPolicy = database.applicationDao().getSignPolicy(sortOrder ?: packageName)
|
||||
val isRemembered = if (signPolicy == 2) true else permission?.acceptable ?: return null
|
||||
if (!isRemembered) {
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
@@ -240,8 +242,8 @@ class SignerProvider : ContentProvider() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val isRemembered = permission?.acceptable ?: return null
|
||||
val signPolicy = database.applicationDao().getSignPolicy(sortOrder ?: packageName)
|
||||
val isRemembered = if (signPolicy == 2) true else permission?.acceptable ?: return null
|
||||
if (!isRemembered) {
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
@@ -317,7 +319,8 @@ class SignerProvider : ContentProvider() {
|
||||
"GET_PUBLIC_KEY",
|
||||
)
|
||||
|
||||
val isRemembered = permission?.acceptable ?: return null
|
||||
val signPolicy = database.applicationDao().getSignPolicy(sortOrder ?: packageName)
|
||||
val isRemembered = if (signPolicy == 2) true else permission?.acceptable ?: return null
|
||||
if (!isRemembered) {
|
||||
database.applicationDao().addHistory(
|
||||
HistoryEntity(
|
||||
|
||||
@@ -33,6 +33,13 @@ val MIGRATION_3_4 =
|
||||
}
|
||||
}
|
||||
|
||||
val MIGRATION_4_5 =
|
||||
object : Migration(4, 5) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL("ALTER TABLE `application` ADD COLUMN `signPolicy` INTEGER NOT NULL DEFAULT 1")
|
||||
}
|
||||
}
|
||||
|
||||
@Database(
|
||||
entities = [
|
||||
ApplicationEntity::class,
|
||||
@@ -41,7 +48,7 @@ val MIGRATION_3_4 =
|
||||
HistoryEntity::class,
|
||||
LogEntity::class,
|
||||
],
|
||||
version = 4,
|
||||
version = 5,
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
@@ -62,6 +69,7 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
.addMigrations(MIGRATION_1_2)
|
||||
.addMigrations(MIGRATION_2_3)
|
||||
.addMigrations(MIGRATION_3_4)
|
||||
.addMigrations(MIGRATION_4_5)
|
||||
.build()
|
||||
instance
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface ApplicationDao {
|
||||
@Query("SELECT signPolicy FROM application WHERE `key` = :key")
|
||||
fun getSignPolicy(key: String): Int?
|
||||
|
||||
@Query("SELECT MAX(time) FROM notification")
|
||||
fun getLatestNotification(): Long?
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ data class ApplicationEntity(
|
||||
var isConnected: Boolean,
|
||||
val secret: String,
|
||||
val useSecret: Boolean,
|
||||
var signPolicy: Int,
|
||||
)
|
||||
|
||||
data class ApplicationWithPermissions(
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
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("decrypt_zap_event", null),
|
||||
Permission("sign_event", 0),
|
||||
Permission("sign_event", 1),
|
||||
Permission("sign_event", 3),
|
||||
Permission("sign_event", 4),
|
||||
Permission("sign_event", 5),
|
||||
Permission("sign_event", 6),
|
||||
Permission("sign_event", 7),
|
||||
Permission("sign_event", 9734),
|
||||
Permission("sign_event", 9735),
|
||||
Permission("sign_event", 10000),
|
||||
Permission("sign_event", 10002),
|
||||
Permission("sign_event", 10003),
|
||||
Permission("sign_event", 10013),
|
||||
Permission("sign_event", 31234),
|
||||
Permission("sign_event", 30078),
|
||||
Permission("sign_event", 22242),
|
||||
Permission("sign_event", 27235),
|
||||
Permission("sign_event", 30023),
|
||||
)
|
||||
@@ -166,6 +166,7 @@ object AmberUtils {
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
account.signPolicy,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
|
||||
@@ -87,7 +87,7 @@ fun EditPermission(
|
||||
mutableStateListOf<ApplicationPermissionsEntity>()
|
||||
}
|
||||
var applicationData by remember {
|
||||
mutableStateOf(ApplicationEntity(selectedPackage, "", emptyList(), "", "", "", "", true, "", false))
|
||||
mutableStateOf(ApplicationEntity(selectedPackage, "", emptyList(), "", "", "", "", true, "", false, 1))
|
||||
}
|
||||
var textFieldvalue by remember(applicationData.name) {
|
||||
mutableStateOf(TextFieldValue(applicationData.name))
|
||||
|
||||
@@ -94,6 +94,7 @@ import com.greenart7c3.nostrsigner.models.Permission
|
||||
import com.greenart7c3.nostrsigner.models.ReturnType
|
||||
import com.greenart7c3.nostrsigner.models.SignerType
|
||||
import com.greenart7c3.nostrsigner.models.TimeUtils
|
||||
import com.greenart7c3.nostrsigner.models.basicPermissions
|
||||
import com.greenart7c3.nostrsigner.service.EventNotificationConsumer
|
||||
import com.greenart7c3.nostrsigner.service.IntentUtils
|
||||
import com.greenart7c3.nostrsigner.service.PushNotificationUtils
|
||||
@@ -130,6 +131,7 @@ fun sendResult(
|
||||
onLoading: (Boolean) -> Unit,
|
||||
permissions: List<Permission>? = null,
|
||||
appName: String? = null,
|
||||
signPolicy: Int? = null,
|
||||
) {
|
||||
onLoading(true)
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
@@ -169,25 +171,54 @@ fun sendResult(
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
account.signPolicy,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
application.application.isConnected = true
|
||||
|
||||
permissions?.filter { it.checked }?.forEach {
|
||||
if (application.permissions.any { permission -> permission.type == it.type.toUpperCase(Locale.current) && permission.kind == it.kind }) {
|
||||
return@forEach
|
||||
if (signPolicy != null) {
|
||||
when (signPolicy) {
|
||||
0 -> {
|
||||
application.application.signPolicy = 0
|
||||
basicPermissions.forEach {
|
||||
if (application.permissions.any { permission -> permission.type == it.type.toUpperCase(Locale.current) && permission.kind == it.kind }) {
|
||||
return@forEach
|
||||
}
|
||||
application.permissions.add(
|
||||
ApplicationPermissionsEntity(
|
||||
null,
|
||||
key,
|
||||
it.type.toUpperCase(Locale.current),
|
||||
it.kind,
|
||||
true,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
application.application.signPolicy = 1
|
||||
permissions?.filter { it.checked }?.forEach {
|
||||
if (application.permissions.any { permission -> permission.type == it.type.toUpperCase(Locale.current) && permission.kind == it.kind }) {
|
||||
return@forEach
|
||||
}
|
||||
application.permissions.add(
|
||||
ApplicationPermissionsEntity(
|
||||
null,
|
||||
key,
|
||||
it.type.toUpperCase(Locale.current),
|
||||
it.kind,
|
||||
true,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
2 -> {
|
||||
application.application.signPolicy = 2
|
||||
}
|
||||
}
|
||||
application.permissions.add(
|
||||
ApplicationPermissionsEntity(
|
||||
null,
|
||||
key,
|
||||
it.type.toUpperCase(Locale.current),
|
||||
it.kind,
|
||||
true,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (rememberChoice) {
|
||||
application.permissions.add(
|
||||
ApplicationPermissionsEntity(
|
||||
@@ -594,6 +625,7 @@ fun MainScreen(
|
||||
false,
|
||||
secret,
|
||||
false,
|
||||
account.signPolicy,
|
||||
)
|
||||
|
||||
database.applicationDao().insertApplication(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.greenart7c3.nostrsigner.ui.components
|
||||
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -9,25 +10,25 @@ 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.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Done
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.selection.selectable
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
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.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
@@ -36,22 +37,23 @@ 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.models.Permission
|
||||
import com.greenart7c3.nostrsigner.ui.actions.AdjustPermissionsDialog
|
||||
import com.greenart7c3.nostrsigner.ui.theme.ButtonBorder
|
||||
|
||||
@Composable
|
||||
fun LoginWithPubKey(
|
||||
account: Account,
|
||||
appName: String,
|
||||
applicationName: String?,
|
||||
permissions: List<Permission>?,
|
||||
onAccept: (List<Permission>?) -> Unit,
|
||||
onAccept: (List<Permission>?, Int) -> Unit,
|
||||
onReject: () -> Unit,
|
||||
) {
|
||||
var localPermissions by remember {
|
||||
mutableStateOf(permissions)
|
||||
}
|
||||
val context = LocalContext.current
|
||||
|
||||
var showAdjustDialog by remember {
|
||||
mutableStateOf(false)
|
||||
@@ -75,7 +77,8 @@ fun LoginWithPubKey(
|
||||
Column(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(16.dp),
|
||||
.padding(16.dp)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
) {
|
||||
Text(
|
||||
buildAnnotatedString {
|
||||
@@ -87,43 +90,74 @@ fun LoginWithPubKey(
|
||||
fontSize = 18.sp,
|
||||
)
|
||||
|
||||
Spacer(Modifier.size(4.dp))
|
||||
Spacer(Modifier.size(8.dp))
|
||||
|
||||
localPermissions?.let {
|
||||
LazyColumn(
|
||||
val radioOptions = listOf(
|
||||
TitleExplainer(
|
||||
title = stringResource(R.string.sign_policy_basic),
|
||||
explainer = stringResource(R.string.sign_policy_basic_explainer),
|
||||
),
|
||||
TitleExplainer(
|
||||
title = stringResource(R.string.sign_policy_manual_new_app),
|
||||
explainer = stringResource(R.string.sign_policy_manual_new_app_explainer),
|
||||
),
|
||||
TitleExplainer(
|
||||
title = stringResource(R.string.sign_policy_fully),
|
||||
explainer = stringResource(R.string.sign_policy_fully_explainer),
|
||||
),
|
||||
)
|
||||
var selectedOption by remember { mutableIntStateOf(account.signPolicy) }
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.handle_application_permissions),
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.size(8.dp))
|
||||
|
||||
radioOptions.forEachIndexed { index, option ->
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
itemsIndexed(it.take(3)) { _, item ->
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
) {
|
||||
Icon(
|
||||
if (item.checked) Icons.Default.Done else Icons.Default.Close,
|
||||
item.toLocalizedString(context),
|
||||
tint = if (item.checked) Color.Green else Color.Red,
|
||||
)
|
||||
Text(text = item.toLocalizedString(context))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (it.size > 3) {
|
||||
Row(
|
||||
Modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
) {
|
||||
val isAnyChecked = it.take(3).any { permission -> permission.checked }
|
||||
Icon(
|
||||
if (isAnyChecked) Icons.Default.Done else Icons.Default.Close,
|
||||
stringResource(R.string.and_more),
|
||||
tint = if (isAnyChecked) Color.Green else Color.Red,
|
||||
.selectable(
|
||||
selected = selectedOption == index,
|
||||
onClick = {
|
||||
selectedOption = index
|
||||
},
|
||||
)
|
||||
Text(text = stringResource(R.string.more, it.size - 3))
|
||||
.border(
|
||||
width = 1.dp,
|
||||
color = if (selectedOption == index) {
|
||||
MaterialTheme.colorScheme.primary
|
||||
} else {
|
||||
Color.Transparent
|
||||
},
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
)
|
||||
.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
RadioButton(
|
||||
selected = selectedOption == index,
|
||||
onClick = {
|
||||
selectedOption = index
|
||||
},
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Text(
|
||||
text = option.title,
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
fontWeight = FontWeight.Bold,
|
||||
)
|
||||
option.explainer?.let {
|
||||
Text(
|
||||
text = it,
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,16 +171,18 @@ fun LoginWithPubKey(
|
||||
Arrangement.Center,
|
||||
Alignment.CenterHorizontally,
|
||||
) {
|
||||
localPermissions?.let {
|
||||
if (it.isNotEmpty()) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
showAdjustDialog = true
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(8.dp),
|
||||
) {
|
||||
Text(text = stringResource(R.string.adjust))
|
||||
if (selectedOption == 1) {
|
||||
localPermissions?.let {
|
||||
if (it.isNotEmpty()) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
showAdjustDialog = true
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(8.dp),
|
||||
) {
|
||||
Text(text = stringResource(R.string.adjust))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,7 +193,7 @@ fun LoginWithPubKey(
|
||||
.padding(8.dp),
|
||||
shape = ButtonBorder,
|
||||
onClick = {
|
||||
onAccept(localPermissions)
|
||||
onAccept(localPermissions, selectedOption)
|
||||
},
|
||||
) {
|
||||
Text(stringResource(R.string.grant_permissions))
|
||||
|
||||
@@ -196,6 +196,7 @@ fun MultiEventHomeScreen(
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
localAccount.signPolicy,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
@@ -269,6 +270,7 @@ fun MultiEventHomeScreen(
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
localAccount.signPolicy,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
@@ -335,6 +337,7 @@ fun MultiEventHomeScreen(
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
localAccount.signPolicy,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
|
||||
+6
-1
@@ -93,10 +93,11 @@ fun SingleEventHomeScreen(
|
||||
}
|
||||
|
||||
LoginWithPubKey(
|
||||
account,
|
||||
appName,
|
||||
applicationName,
|
||||
intentData.permissions,
|
||||
{ permissions ->
|
||||
{ permissions, signPolicy ->
|
||||
val sig =
|
||||
if (intentData.type == SignerType.CONNECT) {
|
||||
"ack"
|
||||
@@ -121,6 +122,7 @@ fun SingleEventHomeScreen(
|
||||
appName = applicationName ?: appName,
|
||||
database = database,
|
||||
onLoading = onLoading,
|
||||
signPolicy = signPolicy,
|
||||
)
|
||||
}
|
||||
return@LoginWithPubKey
|
||||
@@ -219,6 +221,7 @@ fun SingleEventHomeScreen(
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
account.signPolicy,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
@@ -348,6 +351,7 @@ fun SingleEventHomeScreen(
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
account.signPolicy,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
@@ -499,6 +503,7 @@ fun SingleEventHomeScreen(
|
||||
true,
|
||||
intentData.bunkerRequest?.secret ?: "",
|
||||
intentData.bunkerRequest?.secret != null,
|
||||
account.signPolicy,
|
||||
),
|
||||
permissions = mutableListOf(),
|
||||
)
|
||||
|
||||
@@ -349,4 +349,9 @@
|
||||
<string name="seed_words_explainer">These words let you recreate your account in case you lose access. Write them down in a safe place</string>
|
||||
<string name="show_seed_words">Show seed words</string>
|
||||
<string name="sign_policy">Sign policy</string>
|
||||
<string name="handle_application_permissions">How to handle this application permissions?</string>
|
||||
<string name="sign_policy_manual_new_app">Manually approve each permission</string>
|
||||
<string name="sign_policy_manual_new_app_explainer">Recommended for privacy-minded people who would like control over each permission. Choosing this will prompt you set a preference every time you receive a new permission.</string>
|
||||
<string name="sign_policy_fully">I fully trust this application</string>
|
||||
<string name="sign_policy_fully_explainer">Sign automatically every request</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user