From ff09510b09de0f5d6a926bc5f36ec6fd783d349d Mon Sep 17 00:00:00 2001
From: spacedandy-agents-simplex
<342056592+spacedandy-agents-simplex@users.noreply.github.com>
Date: Fri, 23 Oct 2026 10:40:16 +0000
Subject: [PATCH] ui: let channel owners turn on "Sign messages", warning that
earlier messages will show signature missing
The channel preference was hidden while signing was recipient-only. Owners now see the switch; turning it on asks for confirmation, because subscribers who join later receive the earlier posts unsigned through history and see them as "signature missing". The "Signature missing" explanation now says the message may predate signing or have been forwarded by a relay without its signature, instead of only implying tampering.
Run: 001-channel-signing-moderators, slice 3
---
.../Chat/Group/GroupPreferencesView.swift | 17 +++++++++++++++--
apps/ios/SimpleXChat/ChatTypes.swift | 2 +-
.../views/chat/group/GroupPreferences.kt | 19 +++++++++++++++----
.../moko-resources/base/strings.xml | 5 ++++-
4 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift b/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift
index da15ab98a5..d9db16b559 100644
--- a/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift
+++ b/apps/ios/Shared/Views/Chat/Group/GroupPreferencesView.swift
@@ -50,8 +50,21 @@ struct GroupPreferencesView: View {
featureSection(.history, $preferences.history.enable)
featureSection(.support, $preferences.support.enable, disabled: true)
} else {
- // hidden until message signing is user-facing (recipient-only stage)
-// featureSection(.signMessages, $preferences.signMessages.enable)
+ featureSection(.signMessages, $preferences.signMessages.enable)
+ .onChange(of: preferences.signMessages.enable) { enable in
+ if enable == .on {
+ showAlert(
+ NSLocalizedString("Sign messages?", comment: "alert title"),
+ message: NSLocalizedString("Messages sent before will show \"signature missing\" to subscribers who join later.", comment: "alert message"),
+ actions: {[
+ UIAlertAction(title: NSLocalizedString("Enable", comment: "alert button"), style: .default) { _ in },
+ UIAlertAction(title: NSLocalizedString("Cancel", comment: "alert button"), style: .cancel) { _ in
+ preferences.signMessages.enable = .off
+ }
+ ]}
+ )
+ }
+ }
featureSection(.timedMessages, $preferences.timedMessages.enable)
featureSection(.fullDelete, $preferences.fullDelete.enable)
featureSection(.reactions, $preferences.reactions.enable)
diff --git a/apps/ios/SimpleXChat/ChatTypes.swift b/apps/ios/SimpleXChat/ChatTypes.swift
index c77811f969..68300193d5 100644
--- a/apps/ios/SimpleXChat/ChatTypes.swift
+++ b/apps/ios/SimpleXChat/ChatTypes.swift
@@ -3158,7 +3158,7 @@ public enum MsgVerified: Decodable, Equatable, Hashable {
switch self {
case .sigMissing: return (
NSLocalizedString("Signature missing", comment: "alert title"),
- NSLocalizedString("The channel required this message to be signed, but the signature is missing.", comment: "alert message")
+ NSLocalizedString("This channel requires signed messages, but this message has no signature. It may have been sent before signing was required, or a relay may have forwarded it without one.", comment: "alert message")
)
default: return nil
}
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt
index bd3af10c37..2be256d074 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupPreferences.kt
@@ -178,10 +178,14 @@ private fun GroupPreferencesLayout(
}
}
}
- @Composable fun SignMessagesPreference() {
+ @Composable fun SignMessagesPreference(onEnable: ((() -> Unit) -> Unit)? = null) {
val enableSignMessages = remember(preferences) { mutableStateOf(preferences.signMessages.enable) }
FeatureSection(GroupFeature.SignMessages, enableSignMessages, null, groupInfo, preferences, onTTLUpdated) { enable, _ ->
applyPrefs(preferences.copy(signMessages = GroupPreference(enable = enable)))
+ if (enable == GroupFeatureEnabled.ON) onEnable?.invoke {
+ enableSignMessages.value = GroupFeatureEnabled.OFF
+ applyPrefs(preferences.copy(signMessages = GroupPreference(enable = GroupFeatureEnabled.OFF)))
+ }
}
}
ColumnWithScrollBar {
@@ -216,9 +220,16 @@ private fun GroupPreferencesLayout(
SectionDividerSpaced()
SupportPreference(disabled = true)
} else {
- // hidden until message signing is user-facing (recipient-only stage)
-// SignMessagesPreference()
-// SectionDividerSpaced()
+ SignMessagesPreference(onEnable = { revert ->
+ AlertManager.shared.showAlertDialog(
+ title = generalGetString(MR.strings.sign_messages_question),
+ text = generalGetString(MR.strings.sign_messages_alert_desc),
+ confirmText = generalGetString(MR.strings.sign_messages_enable),
+ onDismiss = revert,
+ onDismissRequest = revert,
+ )
+ })
+ SectionDividerSpaced()
TimedMessagesPreference()
SectionDividerSpaced()
FullDeletePreference()
diff --git a/apps/multiplatform/common/src/commonMain/moko-resources/base/strings.xml b/apps/multiplatform/common/src/commonMain/moko-resources/base/strings.xml
index cd80492607..793d72244b 100644
--- a/apps/multiplatform/common/src/commonMain/moko-resources/base/strings.xml
+++ b/apps/multiplatform/common/src/commonMain/moko-resources/base/strings.xml
@@ -787,10 +787,13 @@
Do not require signing messages.
Message signing is required.
Message signing is not required.
+ Sign messages?
+ Messages sent before will show "signature missing" to subscribers who join later.
+ Enable
Show signature
Show encryption
Signature missing
- The channel required this message to be signed, but the signature is missing.
+ This channel requires signed messages, but this message has no signature. It may have been sent before signing was required, or a relay may have forwarded it without one.
Live message!
Send a live message - it will update for the recipient(s) as you type it
Send