desktop: add reset bunker to the app detail screen

Port the Android "Reset Bunker" (EditConfigurationScreen): the app
detail screen gains a reset button that regenerates the app's local
key and secret (new UUID secret, fresh local key, marked
disconnected), keeps the permission rules, deletes the old record with
its history, and refreshes filters — invalidating the old pairing so
the app must reconnect with the new connection string, which the
connection string section then shows. A confirm dialog explains the
consequence before anything is replaced (Android resets directly);
like Android, the screen returns to the Applications list afterwards.

The reset_bunker label reuses the translations bundled from the
Android strings; the confirm message is translated in all 14 locales.
This commit is contained in:
greenart7c3
2026-09-28 15:47:09 -03:00
parent 0dc58ccf20
commit e2eddb7189
15 changed files with 135 additions and 0 deletions
@@ -30,20 +30,28 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.greenart7c3.nostrsigner.desktop.core.AmberDesktop
import com.greenart7c3.nostrsigner.desktop.core.AppPermissionRecord
import com.greenart7c3.nostrsigner.desktop.core.AppWithPermissions
import com.greenart7c3.nostrsigner.desktop.core.DesktopAccount
import com.greenart7c3.nostrsigner.desktop.core.RememberType
import com.greenart7c3.nostrsigner.desktop.core.SignerDescriptions
import com.greenart7c3.nostrsigner.desktop.core.Strings
import com.greenart7c3.nostrsigner.desktop.core.generateBunkerPrivKey
import com.greenart7c3.nostrsigner.desktop.core.localPubKeyFromPrivKey
import com.greenart7c3.nostrsigner.desktop.core.toShortenHex
import java.text.DateFormat
import java.util.Date
import java.util.UUID
import kotlinx.coroutines.launch
@Composable
@@ -56,6 +64,7 @@ fun ApplicationDetailScreen(
val apps by store.apps.collectAsState()
val history by store.history.collectAsState()
val language by Strings.currentLanguage.collectAsState()
val scope = rememberCoroutineScope()
val app = apps.firstOrNull { it.app.key == appKey }
var tab by remember { mutableStateOf(0) }
@@ -114,6 +123,90 @@ fun ApplicationDetailScreen(
)
Spacer(Modifier.height(8.dp))
// Mirrors the Android app-detail connection string (EditPermission):
// the bunker:// URI the client app can re-paste to reconnect.
val connectionPubKey = if (app.app.localKey.isNotEmpty()) {
localPubKeyFromPrivKey(app.app.localKey)
} else {
account.hexKey
}
val bunkerUri = remember(connectionPubKey, app.app.relays, app.app.useSecret, app.app.secret) {
val relayParams = app.app.relays.joinToString(separator = "&") { "relay=$it" }
val localSecret = if (app.app.useSecret) "&secret=${app.app.secret}" else ""
"bunker://$connectionPubKey?$relayParams$localSecret"
}
val clipboard = LocalClipboardManager.current
Spacer(Modifier.height(16.dp))
Text(Strings.get("d_connection_string", language), style = MaterialTheme.typography.titleSmall)
Spacer(Modifier.height(4.dp))
Text(
bunkerUri,
style = MaterialTheme.typography.bodySmall,
fontFamily = FontFamily.Monospace,
modifier = Modifier
.fillMaxWidth()
.border(BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant), RoundedCornerShape(8.dp))
.padding(8.dp),
)
AmberTextButton(
text = Strings.get("copy", language).trim(),
onClick = {
clipboard.setText(AnnotatedString(bunkerUri))
Toaster.toast(Strings.get("d_connection_string_copied", language))
},
)
Spacer(Modifier.height(12.dp))
// Mirrors the Android "Reset Bunker" (EditConfigurationScreen): a new
// key and secret invalidate the old pairing; permission rules stay.
var showResetBunker by remember { mutableStateOf(false) }
if (showResetBunker) {
AlertDialog(
onDismissRequest = { showResetBunker = false },
title = { Text(Strings.get("reset_bunker", language)) },
text = { Text(Strings.get("d_reset_bunker_message", language)) },
confirmButton = {
AmberTextButton(
text = Strings.get("reset_bunker", language),
onClick = {
showResetBunker = false
val oldKey = app.app.key
val newSecret = UUID.randomUUID().toString()
store.upsert(
AppWithPermissions(
app = app.app.copy(
key = newSecret,
isConnected = false,
secret = newSecret,
useSecret = true,
localKey = generateBunkerPrivKey(),
),
permissions = app.permissions,
),
)
store.delete(oldKey)
scope.launch {
AmberDesktop.engine.updateFilter()
AmberDesktop.client.connect()
}
Toaster.toast(Strings.get("d_saved", language))
},
)
},
dismissButton = {
AmberTextButton(
text = Strings.get("cancel", language),
onClick = { showResetBunker = false },
)
},
)
}
AmberOutlinedButton(
text = Strings.get("reset_bunker", language),
onClick = { showResetBunker = true },
)
Spacer(Modifier.height(12.dp))
var showRemoveAll by remember { mutableStateOf(false) }
if (showRemoveAll) {
AlertDialog(
@@ -52,6 +52,7 @@
<string name="permissions">Berechtigungen</string>
<string name="delete_application">Anwendung löschen</string>
<string name="reset_bunker">Bunker zurücksetzen</string>
<string name="d_reset_bunker_message">Dadurch werden ein neuer Schlüssel und ein neues Secret für diese App erzeugt. Die Berechtigungsregeln bleiben erhalten, aber die App muss sich mit dem neuen Verbindungs-String neu verbinden.</string>
<string name="copy_to_clipboard">In Zwischenablage kopieren</string>
<string name="nothing_to_approve_yet">Noch nichts zu genehmigen</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">Warum nicht deine Lieblings-Nostr-App ein wenig erkunden?</string>
@@ -810,6 +811,8 @@
<string name="d_seed_words">Seed-Wörter</string>
<string name="d_show">Anzeigen</string>
<string name="d_copy_nsec">nsec kopieren</string>
<string name="d_connection_string">Verbindungs-String</string>
<string name="d_connection_string_copied">In die Zwischenablage kopiert</string>
<string name="d_nsec_copied">Geheimer Schlüssel kopiert. Leere deine Zwischenablage nach dem Einfügen!</string>
<string name="d_encrypted_backup">Verschlüsselte Sicherung (ncryptsec)</string>
<string name="d_password">Passwort</string>
@@ -77,6 +77,7 @@
<string name="permissions">Permissions</string>
<string name="delete_application">Delete Application</string>
<string name="reset_bunker">Reset Bunker</string>
<string name="d_reset_bunker_message">This generates a new key and secret for this app. Its permission rules are kept, but the app must reconnect with the new connection string.</string>
<string name="copy_to_clipboard">Copy to clipboard</string>
<string name="nothing_to_approve_yet">Nothing to approve yet</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">Why not explore your favorite nostr app a bit?</string>
@@ -821,6 +822,8 @@
<string name="d_seed_words">Seed words</string>
<string name="d_show">Show</string>
<string name="d_copy_nsec">Copy nsec</string>
<string name="d_connection_string">Connection string</string>
<string name="d_connection_string_copied">Copied to clipboard</string>
<string name="d_nsec_copied">Secret key copied. Clear your clipboard after pasting it!</string>
<string name="d_encrypted_backup">Encrypted backup (ncryptsec)</string>
<string name="d_password">Password</string>
@@ -54,6 +54,7 @@
<string name="permissions">Permisos</string>
<string name="delete_application">Eliminar aplicación</string>
<string name="reset_bunker">Restablecer Bunker</string>
<string name="d_reset_bunker_message">Esto genera una nueva clave y un nuevo secreto para esta aplicación. Sus reglas de permisos se conservan, pero la aplicación deberá reconectarse con la nueva cadena de conexión.</string>
<string name="copy_to_clipboard">Copiar al portapapeles</string>
<string name="nothing_to_approve_yet">Nada que aprobar aún</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">¿Por qué no explorar un poco tu app favorita de nostr?</string>
@@ -813,6 +814,8 @@
<string name="d_seed_words">Palabras semilla</string>
<string name="d_show">Mostrar</string>
<string name="d_copy_nsec">Copiar nsec</string>
<string name="d_connection_string">Cadena de conexión</string>
<string name="d_connection_string_copied">Copiado al portapapeles</string>
<string name="d_nsec_copied">Clave secreta copiada. ¡Borra el portapapeles después de pegarla!</string>
<string name="d_encrypted_backup">Copia de seguridad cifrada (ncryptsec)</string>
<string name="d_password">Contraseña</string>
@@ -52,6 +52,7 @@
<string name="permissions">Autorisations</string>
<string name="delete_application">Supprimer l\'application</string>
<string name="reset_bunker">Réinitialiser le Bunker</string>
<string name="d_reset_bunker_message">Cette action génère une nouvelle clé et un nouveau secret pour cette application. Ses règles d'autorisation sont conservées, mais l'application devra se reconnecter avec la nouvelle chaîne de connexion.</string>
<string name="copy_to_clipboard">Copier dans le presse-papiers</string>
<string name="nothing_to_approve_yet">Rien à approuver pour l\'instant</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">Pourquoi ne pas explorer un peu votre application Nostr préférée ?</string>
@@ -810,6 +811,8 @@
<string name="d_seed_words">Mots de récupération</string>
<string name="d_show">Afficher</string>
<string name="d_copy_nsec">Copier la nsec</string>
<string name="d_connection_string">Chaîne de connexion</string>
<string name="d_connection_string_copied">Copié dans le presse-papiers</string>
<string name="d_nsec_copied">Clé secrète copiée. Videz votre presse-papiers après l'avoir collée !</string>
<string name="d_encrypted_backup">Sauvegarde chiffrée (ncryptsec)</string>
<string name="d_password">Mot de passe</string>
@@ -54,6 +54,7 @@
<string name="permissions">Izin</string>
<string name="delete_application">Hapus Aplikasi</string>
<string name="reset_bunker">Atur Ulang Bunker</string>
<string name="d_reset_bunker_message">Ini menghasilkan kunci dan rahasia baru untuk aplikasi ini. Aturan izinnya dipertahankan, tetapi aplikasi harus tersambung kembali dengan string koneksi yang baru.</string>
<string name="copy_to_clipboard">Salin ke clipboard</string>
<string name="nothing_to_approve_yet">Belum ada yang perlu disetujui</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">Mengapa tidak menjelajahi aplikasi nostr favorit Anda sebentar?</string>
@@ -813,6 +814,8 @@
<string name="d_seed_words">Kata benih</string>
<string name="d_show">Tampilkan</string>
<string name="d_copy_nsec">Salin nsec</string>
<string name="d_connection_string">String koneksi</string>
<string name="d_connection_string_copied">Disalin ke papan klip</string>
<string name="d_nsec_copied">Kunci rahasia disalin. Bersihkan papan klip setelah menempelkannya!</string>
<string name="d_encrypted_backup">Cadangan terenkripsi (ncryptsec)</string>
<string name="d_password">Kata sandi</string>
@@ -54,6 +54,7 @@
<string name="permissions">Permessi</string>
<string name="delete_application">Elimina applicazione</string>
<string name="reset_bunker">Reimposta Bunker</string>
<string name="d_reset_bunker_message">Questo genera una nuova chiave e un nuovo segreto per questa app. Le regole di permesso vengono conservate, ma l'app deve riconnettersi con la nuova stringa di connessione.</string>
<string name="copy_to_clipboard">Copia negli appunti</string>
<string name="nothing_to_approve_yet">Niente da approvare per ora</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">Perché non esplori un po\' la tua app Nostr preferita?</string>
@@ -813,6 +814,8 @@
<string name="d_seed_words">Seed words</string>
<string name="d_show">Mostra</string>
<string name="d_copy_nsec">Copia nsec</string>
<string name="d_connection_string">Stringa di connessione</string>
<string name="d_connection_string_copied">Copiato negli appunti</string>
<string name="d_nsec_copied">Chiave segreta copiata. Svuota gli appunti dopo averla incollata!</string>
<string name="d_encrypted_backup">Backup cifrato (ncryptsec)</string>
<string name="d_password">Password</string>
@@ -45,6 +45,7 @@
<string name="permissions">権限</string>
<string name="delete_application">アプリケーションを削除</string>
<string name="reset_bunker">Bunker をリセット</string>
<string name="d_reset_bunker_message">このアプリの新しい鍵とシークレットを生成します。権限ルールは保持されますが、アプリは新しい接続文字列で再接続する必要があります。</string>
<string name="copy_to_clipboard">クリップボードにコピー</string>
<string name="nothing_to_approve_yet">まだ承認するものはありません</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">お気に入りの Nostr アプリを少し探索してみませんか?</string>
@@ -789,6 +790,8 @@
<string name="d_seed_words">シードワード</string>
<string name="d_show">表示</string>
<string name="d_copy_nsec">nsec をコピー</string>
<string name="d_connection_string">接続文字列</string>
<string name="d_connection_string_copied">クリップボードにコピーしました</string>
<string name="d_nsec_copied">秘密鍵をコピーしました。貼り付けた後はクリップボードを消去してください!</string>
<string name="d_encrypted_backup">暗号化バックアップ (ncryptsec)</string>
<string name="d_password">パスワード</string>
@@ -54,6 +54,7 @@
<string name="permissions">권한</string>
<string name="delete_application">애플리케이션 삭제</string>
<string name="reset_bunker">Bunker 초기화</string>
<string name="d_reset_bunker_message">이 앱의 새 키와 시크릿을 생성합니다. 권한 규칙은 유지되지만 앱은 새 연결 문자열로 다시 연결해야 합니다.</string>
<string name="copy_to_clipboard">클립보드에 복사</string>
<string name="nothing_to_approve_yet">아직 승인할 항목이 없습니다</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">즐겨 사용하는 Nostr 앱을 조금 더 탐색해 보세요.</string>
@@ -813,6 +814,8 @@
<string name="d_seed_words">시드 단어</string>
<string name="d_show">표시</string>
<string name="d_copy_nsec">nsec 복사</string>
<string name="d_connection_string">연결 문자열</string>
<string name="d_connection_string_copied">클립보드에 복사되었습니다</string>
<string name="d_nsec_copied">비밀 키가 복사되었습니다. 붙여넣은 후 클립보드를 지우세요!</string>
<string name="d_encrypted_backup">암호화된 백업 (ncryptsec)</string>
<string name="d_password">비밀번호</string>
@@ -50,6 +50,7 @@
<string name="permissions">Permissões</string>
<string name="delete_application">Excluir aplicativo</string>
<string name="reset_bunker">Redefinir Bunker</string>
<string name="d_reset_bunker_message">Isso gera uma nova chave e um novo segredo para este aplicativo. As regras de permissão são mantidas, mas o aplicativo precisa reconectar com a nova string de conexão.</string>
<string name="copy_to_clipboard">Copiar para área de transferência</string>
<string name="nothing_to_approve_yet">Nada para aprovar ainda</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">Por que não explorar um pouco seu aplicativo nostr favorito?</string>
@@ -808,6 +809,8 @@
<string name="d_seed_words">Palavras-semente</string>
<string name="d_show">Mostrar</string>
<string name="d_copy_nsec">Copiar nsec</string>
<string name="d_connection_string">String de conexão</string>
<string name="d_connection_string_copied">Copiado para a área de transferência</string>
<string name="d_nsec_copied">Chave secreta copiada. Limpe sua área de transferência depois de colá-la!</string>
<string name="d_encrypted_backup">Backup criptografado (ncryptsec)</string>
<string name="d_password">Senha</string>
@@ -54,6 +54,7 @@
<string name="permissions">Разрешения</string>
<string name="delete_application">Удалить приложение</string>
<string name="reset_bunker">Сбросить Bunker</string>
<string name="d_reset_bunker_message">Будут созданы новый ключ и секрет для этого приложения. Правила разрешений сохранятся, но приложению потребуется переподключиться с новой строкой подключения.</string>
<string name="copy_to_clipboard">Копировать в буфер обмена</string>
<string name="nothing_to_approve_yet">Пока нечего подтверждать</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">Почему бы немного не изучить ваше любимое Nostr-приложение?</string>
@@ -813,6 +814,8 @@
<string name="d_seed_words">Сид-слова</string>
<string name="d_show">Показать</string>
<string name="d_copy_nsec">Копировать nsec</string>
<string name="d_connection_string">Строка подключения</string>
<string name="d_connection_string_copied">Скопировано в буфер обмена</string>
<string name="d_nsec_copied">Секретный ключ скопирован. Очистите буфер обмена после вставки!</string>
<string name="d_encrypted_backup">Зашифрованная резервная копия (ncryptsec)</string>
<string name="d_password">Пароль</string>
@@ -45,6 +45,7 @@
<string name="permissions">สิทธิ์</string>
<string name="delete_application">ลบแอปพลิเคชัน</string>
<string name="reset_bunker">รีเซ็ต Bunker</string>
<string name="d_reset_bunker_message">การกระทำนี้จะสร้างกุญแจและรหัสลับใหม่ให้แอปนี้ กฎการอนุญาตจะยังคงอยู่ แต่แอปจะต้องเชื่อมต่อใหม่ด้วยสตริงการเชื่อมต่อใหม่</string>
<string name="copy_to_clipboard">คัดลอกไปยังคลิปบอร์ด</string>
<string name="nothing_to_approve_yet">ยังไม่มีรายการที่ต้องอนุมัติ</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">ลองสำรวจแอป Nostr ที่คุณชื่นชอบสักหน่อยดีไหม?</string>
@@ -789,6 +790,8 @@
<string name="d_seed_words">คำกู้คืน</string>
<string name="d_show">แสดง</string>
<string name="d_copy_nsec">คัดลอก nsec</string>
<string name="d_connection_string">สตริงการเชื่อมต่อ</string>
<string name="d_connection_string_copied">คัดลอกไปยังคลิปบอร์ดแล้ว</string>
<string name="d_nsec_copied">คัดลอกกุญแจลับแล้ว ล้างคลิปบอร์ดของคุณหลังจากวางเสร็จ!</string>
<string name="d_encrypted_backup">ข้อมูลสำรองที่เข้ารหัส (ncryptsec)</string>
<string name="d_password">รหัสผ่าน</string>
@@ -52,6 +52,7 @@
<string name="permissions">İzinler</string>
<string name="delete_application">Uygulamayı Sil</string>
<string name="reset_bunker">Bunker\'ı Sıfırla</string>
<string name="d_reset_bunker_message">Bu, uygulama için yeni bir anahtar ve gizli anahtar oluşturur. İzin kuralları korunur ancak uygulamanın yeni bağlantı dizesiyle yeniden bağlanması gerekir.</string>
<string name="copy_to_clipboard">Panoya kopyala</string>
<string name="nothing_to_approve_yet">Henüz onaylanacak bir şey yok</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">Neden favori Nostr uygulamanızı biraz keşfetmiyorsunuz?</string>
@@ -809,6 +810,8 @@
<string name="d_seed_words">Tohum kelimeleri</string>
<string name="d_show">Göster</string>
<string name="d_copy_nsec">nsec'i kopyala</string>
<string name="d_connection_string">Bağlantı dizesi</string>
<string name="d_connection_string_copied">Panoya kopyalandı</string>
<string name="d_nsec_copied">Gizli anahtar kopyalandı. Yapıştırdıktan sonra panonuzu temizleyin!</string>
<string name="d_encrypted_backup">Şifreli yedek (ncryptsec)</string>
<string name="d_password">Parola</string>
@@ -45,6 +45,7 @@
<string name="permissions">Quyền</string>
<string name="delete_application">Xóa Ứng Dụng</string>
<string name="reset_bunker">Đặt lại Bunker</string>
<string name="d_reset_bunker_message">Thao tác này sẽ tạo khóa và bí mật mới cho ứng dụng này. Các quy tắc quyền được giữ nguyên, nhưng ứng dụng phải kết nối lại bằng chuỗi kết nối mới.</string>
<string name="copy_to_clipboard">Sao chép vào khay nhớ tạm</string>
<string name="nothing_to_approve_yet">Chưa có gì để phê duyệt</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">Tại sao không khám phá ứng dụng Nostr yêu thích của bạn một chút?</string>
@@ -789,6 +790,8 @@
<string name="d_seed_words">Các từ khôi phục</string>
<string name="d_show">Hiện</string>
<string name="d_copy_nsec">Sao chép nsec</string>
<string name="d_connection_string">Chuỗi kết nối</string>
<string name="d_connection_string_copied">Đã sao chép vào bộ nhớ tạm</string>
<string name="d_nsec_copied">Đã sao chép khóa bí mật. Hãy xóa bộ nhớ tạm sau khi dán!</string>
<string name="d_encrypted_backup">Bản sao lưu đã mã hóa (ncryptsec)</string>
<string name="d_password">Mật khẩu</string>
@@ -50,6 +50,7 @@
<string name="permissions">权限</string>
<string name="delete_application">删除应用</string>
<string name="reset_bunker">重置 Bunker</string>
<string name="d_reset_bunker_message">将为该应用生成新的密钥和秘密。权限规则会保留,但该应用需要使用新的连接字符串重新连接。</string>
<string name="copy_to_clipboard">复制到剪贴板</string>
<string name="nothing_to_approve_yet">暂无批复请求</string>
<string name="why_not_explore_your_favorite_nostr_app_a_bit">为什么不去探索一下你喜欢的 Nostr 应用呢?</string>
@@ -794,6 +795,8 @@
<string name="d_seed_words">助记词</string>
<string name="d_show">显示</string>
<string name="d_copy_nsec">复制 nsec</string>
<string name="d_connection_string">连接字符串</string>
<string name="d_connection_string_copied">已复制到剪贴板</string>
<string name="d_nsec_copied">私钥已复制。粘贴后请清除剪贴板!</string>
<string name="d_encrypted_backup">加密备份(ncryptsec)</string>
<string name="d_password">密码</string>