Bunker proxy: enforce signPolicy 2 on proxy accounts

This commit is contained in:
greenart7c3
2026-09-25 05:11:21 -03:00
parent 5c47a36dce
commit 7fec24b1bc
3 changed files with 62 additions and 1 deletions
@@ -69,6 +69,11 @@ class Account(
val saveable = _saveable.asStateFlow() val saveable = _saveable.asStateFlow()
init { init {
// Proxy accounts always sign silently: signPolicy 2 ("always accept") matches
// the proxy path, where requests bypass per-app permissions and are forwarded
// to the remote bunker. Also self-heals accounts persisted with the older
// default of 1; no UI changes account.signPolicy after construction.
if (proxy != null && signPolicy != 2) this.signPolicy = 2
scope.launch { scope.launch {
combine(name, picture) { _, _ -> }.drop(1).collect { combine(name, picture) { _, _ -> }.drop(1).collect {
_saveable.value = AccountState(this@Account) _saveable.value = AccountState(this@Account)
@@ -230,7 +230,7 @@ class AccountStateViewModel(npub: String?) : ViewModel() {
npub = remotePubkeyHex.hexToByteArray().toNpub(), npub = remotePubkeyHex.hexToByteArray().toNpub(),
name = MutableStateFlow(bunkerName), name = MutableStateFlow(bunkerName),
picture = MutableStateFlow(""), picture = MutableStateFlow(""),
signPolicy = 1, signPolicy = 2,
didBackup = true, didBackup = true,
signer = NostrSignerInternal(localKeyPair), signer = NostrSignerInternal(localKeyPair),
proxy = proxyMetadata, proxy = proxyMetadata,
@@ -0,0 +1,56 @@
package com.greenart7c3.nostrsigner
import com.greenart7c3.nostrsigner.models.Account
import com.greenart7c3.nostrsigner.models.ProxyAccountMetadata
import com.vitorpamplona.quartz.nip01Core.core.hexToByteArray
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
/**
* Proxy accounts must always run with signPolicy 2 ("always accept"): proxy
* requests bypass per-app permissions and are forwarded to the remote bunker.
* The clamp in [Account.init] also self-heals accounts that were persisted with
* the older default of 1 before this rule existed.
*/
class AccountTest {
private fun buildAccount(signPolicy: Int, proxy: ProxyAccountMetadata?): Account = Account(
signer = NostrSignerInternal(KeyPair(pubKey = "11".repeat(32).hexToByteArray())),
hexKey = "22".repeat(32),
npub = "npub1test",
name = MutableStateFlow("test"),
picture = MutableStateFlow(""),
signPolicy = signPolicy,
didBackup = true,
scope = CoroutineScope(Dispatchers.Unconfined),
proxy = proxy,
)
@Test
fun `proxy account forces signPolicy 2 regardless of stored value`() {
val account = buildAccount(
signPolicy = 1,
proxy = ProxyAccountMetadata(
remotePubkey = "ab".repeat(32),
relays = emptyList(),
bunkerName = "bunker",
nostrConnectSecret = "",
),
)
assertTrue(account.isProxy)
assertEquals(2, account.signPolicy)
}
@Test
fun `regular account keeps its signPolicy`() {
val account = buildAccount(signPolicy = 1, proxy = null)
assertEquals(1, account.signPolicy)
}
}