fix(concord): leave even when the signer won't sign the Guestbook LEAVE

Only the publish was guarded. Building the LEAVE signs its seal, and a
remote signer (NIP-46/55) that refuses or times out threw past the List
write, so the user could not leave the community at all. The whole
announcement is best-effort now; cancellation still propagates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Vitor Pamplona
2026-09-30 10:11:19 -04:00
co-authored by Claude Opus 5.5
parent 6fdbe44288
commit c0c671663c
@@ -721,9 +721,20 @@ class AccountConcordActions(
if (entry != null && account.isWriteable()) {
val relays = entry.relays.mapNotNullTo(mutableSetOf()) { RelayUrlNormalizer.normalizeOrNull(it) }
if (relays.isNotEmpty()) {
val guestbook = ConcordActions.guestbookPlane(entry.root.hexToByteArray(), entry.id.hexToByteArray(), entry.rootEpoch)
val leave = ConcordActions.buildGuestbookLeave(account.signer, guestbook, TimeUtils.now())
if (!runCatching { account.client.publishAndConfirm(leave, relays, LEAVE_CONFIRM_SECS) }.getOrDefault(false)) {
// Best-effort from signing on: a remote signer that refuses or times out must not
// keep the user in a community they asked to leave.
val announced =
try {
val guestbook = ConcordActions.guestbookPlane(entry.root.hexToByteArray(), entry.id.hexToByteArray(), entry.rootEpoch)
val leave = ConcordActions.buildGuestbookLeave(account.signer, guestbook, TimeUtils.now())
account.client.publishAndConfirm(leave, relays, LEAVE_CONFIRM_SECS)
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
Log.w("Concord", "Leaving $communityId: could not sign or publish the Guestbook LEAVE", e)
false
}
if (!announced) {
Log.w("Concord") { "Leaving $communityId: no relay accepted the Guestbook LEAVE; members keep listing us" }
}
}