diff --git a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/AdvancedNetworkSettings.swift b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/AdvancedNetworkSettings.swift index 55f2e837b8..fa698f8b7c 100644 --- a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/AdvancedNetworkSettings.swift +++ b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/AdvancedNetworkSettings.swift @@ -209,11 +209,16 @@ struct AdvancedNetworkSettings: View { } Section { - Toggle("Use web port", isOn: $netCfg.smpWebPort) + Picker("Use web port", selection: $netCfg.smpWebPortServers) { + ForEach(SMPWebPortServers.allCases, id: \.self) { Text($0.text) } + } + .frame(height: 36) } header: { Text("TCP port for messaging") } footer: { - Text("Use TCP port \(netCfg.smpWebPort ? "443" : "5223") when no port is specified.") + netCfg.smpWebPortServers == .preset + ? Text("Use TCP port 443 for preset servers only.") + : Text("Use TCP port \(netCfg.smpWebPortServers == .all ? "443" : "5223") when no port is specified.") } Section("TCP connection") { diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index a9de0df01b..05fc4ff87b 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -1796,7 +1796,7 @@ public struct NetCfg: Codable, Equatable { public var sessionMode = TransportSessionMode.user public var smpProxyMode: SMPProxyMode = .always public var smpProxyFallback: SMPProxyFallback = .allowProtected - public var smpWebPort = false + public var smpWebPortServers: SMPWebPortServers = .preset public var tcpConnectTimeout: Int // microseconds public var tcpTimeout: Int // microseconds public var tcpTimeoutPerKb: Int // microseconds @@ -1892,6 +1892,20 @@ public enum SMPProxyFallback: String, Codable, SelectableItem { public static let values: [SMPProxyFallback] = [.allow, .allowProtected, .prohibit] } +public enum SMPWebPortServers: String, Codable, CaseIterable { + case all = "all" + case preset = "preset" + case off = "off" + + public var text: LocalizedStringKey { + switch self { + case .all: "All servers" + case .preset: "Preset servers" + case .off: "Off" + } + } +} + public enum OnionHosts: String, Identifiable { case no case prefer diff --git a/apps/ios/SimpleXChat/AppGroup.swift b/apps/ios/SimpleXChat/AppGroup.swift index 45a05a1cd6..75bb537b94 100644 --- a/apps/ios/SimpleXChat/AppGroup.swift +++ b/apps/ios/SimpleXChat/AppGroup.swift @@ -40,7 +40,7 @@ let GROUP_DEFAULT_NETWORK_USE_ONION_HOSTS = "networkUseOnionHosts" let GROUP_DEFAULT_NETWORK_SESSION_MODE = "networkSessionMode" let GROUP_DEFAULT_NETWORK_SMP_PROXY_MODE = "networkSMPProxyMode" let GROUP_DEFAULT_NETWORK_SMP_PROXY_FALLBACK = "networkSMPProxyFallback" -let GROUP_DEFAULT_NETWORK_SMP_WEB_PORT = "networkSMPWebPort" +let GROUP_DEFAULT_NETWORK_SMP_WEB_PORT_SERVERS = "networkSMPWebPortServers" let GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT = "networkTCPConnectTimeout" let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT = "networkTCPTimeout" let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb" @@ -72,7 +72,7 @@ public func registerGroupDefaults() { GROUP_DEFAULT_NETWORK_SESSION_MODE: TransportSessionMode.session.rawValue, GROUP_DEFAULT_NETWORK_SMP_PROXY_MODE: SMPProxyMode.unknown.rawValue, GROUP_DEFAULT_NETWORK_SMP_PROXY_FALLBACK: SMPProxyFallback.allowProtected.rawValue, - GROUP_DEFAULT_NETWORK_SMP_WEB_PORT: false, + GROUP_DEFAULT_NETWORK_SMP_WEB_PORT_SERVERS: SMPWebPortServers.preset.rawValue, GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT: NetCfg.defaults.tcpConnectTimeout, GROUP_DEFAULT_NETWORK_TCP_TIMEOUT: NetCfg.defaults.tcpTimeout, GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB: NetCfg.defaults.tcpTimeoutPerKb, @@ -251,6 +251,12 @@ public let networkSMPProxyFallbackGroupDefault = EnumDefault( withDefault: .allowProtected ) +public let networkSMPWebPortServersDefault = EnumDefault( + defaults: groupDefaults, + forKey: GROUP_DEFAULT_NETWORK_SMP_WEB_PORT_SERVERS, + withDefault: .preset +) + public let storeDBPassphraseGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_STORE_DB_PASSPHRASE) public let initialRandomDBPassphraseGroupDefault = BoolDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_INITIAL_RANDOM_DB_PASSPHRASE) @@ -338,7 +344,7 @@ public func getNetCfg() -> NetCfg { let sessionMode = networkSessionModeGroupDefault.get() let smpProxyMode = networkSMPProxyModeGroupDefault.get() let smpProxyFallback = networkSMPProxyFallbackGroupDefault.get() - let smpWebPort = groupDefaults.bool(forKey: GROUP_DEFAULT_NETWORK_SMP_WEB_PORT) + let smpWebPortServers = networkSMPWebPortServersDefault.get() let tcpConnectTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT) let tcpTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT) let tcpTimeoutPerKb = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB) @@ -362,7 +368,7 @@ public func getNetCfg() -> NetCfg { sessionMode: sessionMode, smpProxyMode: smpProxyMode, smpProxyFallback: smpProxyFallback, - smpWebPort: smpWebPort, + smpWebPortServers: smpWebPortServers, tcpConnectTimeout: tcpConnectTimeout, tcpTimeout: tcpTimeout, tcpTimeoutPerKb: tcpTimeoutPerKb, @@ -381,7 +387,7 @@ public func setNetCfg(_ cfg: NetCfg, networkProxy: NetworkProxy?) { networkSMPProxyFallbackGroupDefault.set(cfg.smpProxyFallback) let socksProxy = networkProxy?.toProxyString() groupDefaults.set(socksProxy, forKey: GROUP_DEFAULT_NETWORK_SOCKS_PROXY) - groupDefaults.set(cfg.smpWebPort, forKey: GROUP_DEFAULT_NETWORK_SMP_WEB_PORT) + networkSMPWebPortServersDefault.set(cfg.smpWebPortServers) groupDefaults.set(cfg.tcpConnectTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT) groupDefaults.set(cfg.tcpTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT) groupDefaults.set(cfg.tcpTimeoutPerKb, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index a557cf93cf..bfb587820a 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -20,6 +20,8 @@ import chat.simplex.common.model.ChatController.getNetCfg import chat.simplex.common.model.ChatController.setNetCfg import chat.simplex.common.model.ChatModel.changingActiveUserMutex import chat.simplex.common.model.MsgContent.MCUnknown +import chat.simplex.common.model.SMPProxyFallback.AllowProtected +import chat.simplex.common.model.SMPProxyMode.Always import dev.icerock.moko.resources.compose.painterResource import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* @@ -86,18 +88,7 @@ class AppPreferences { val backgroundServiceBatteryNoticeShown = mkBoolPreference(SHARED_PREFS_SERVICE_BATTERY_NOTICE_SHOWN, false) val autoRestartWorkerVersion = mkIntPreference(SHARED_PREFS_AUTO_RESTART_WORKER_VERSION, 0) val webrtcPolicyRelay = mkBoolPreference(SHARED_PREFS_WEBRTC_POLICY_RELAY, true) - private val _callOnLockScreen = mkStrPreference(SHARED_PREFS_WEBRTC_CALLS_ON_LOCK_SCREEN, CallOnLockScreen.default.name) - val callOnLockScreen: SharedPreference = SharedPreference( - get = fun(): CallOnLockScreen { - val value = _callOnLockScreen.get() ?: return CallOnLockScreen.default - return try { - CallOnLockScreen.valueOf(value) - } catch (e: Throwable) { - CallOnLockScreen.default - } - }, - set = fun(action: CallOnLockScreen) { _callOnLockScreen.set(action.name) } - ) + val callOnLockScreen: SharedPreference = mkSafeEnumPreference(SHARED_PREFS_WEBRTC_CALLS_ON_LOCK_SCREEN, CallOnLockScreen.default) val performLA = mkBoolPreference(SHARED_PREFS_PERFORM_LA, false) val laMode = mkEnumPreference(SHARED_PREFS_LA_MODE, LAMode.default) { LAMode.values().firstOrNull { it.name == this } } val laLockDelay = mkIntPreference(SHARED_PREFS_LA_LOCK_DELAY, 30) @@ -107,18 +98,7 @@ class AppPreferences { val privacyAcceptImages = mkBoolPreference(SHARED_PREFS_PRIVACY_ACCEPT_IMAGES, true) val privacyLinkPreviews = mkBoolPreference(SHARED_PREFS_PRIVACY_LINK_PREVIEWS, true) val privacyChatListOpenLinks = mkEnumPreference(SHARED_PREFS_PRIVACY_CHAT_LIST_OPEN_LINKS, PrivacyChatListOpenLinksMode.ASK) { PrivacyChatListOpenLinksMode.values().firstOrNull { it.name == this } } - private val _simplexLinkMode = mkStrPreference(SHARED_PREFS_PRIVACY_SIMPLEX_LINK_MODE, SimplexLinkMode.default.name) - val simplexLinkMode: SharedPreference = SharedPreference( - get = fun(): SimplexLinkMode { - val value = _simplexLinkMode.get() ?: return SimplexLinkMode.default - return try { - SimplexLinkMode.valueOf(value) - } catch (e: Throwable) { - SimplexLinkMode.default - } - }, - set = fun(mode: SimplexLinkMode) { _simplexLinkMode.set(mode.name) } - ) + val simplexLinkMode: SharedPreference = mkSafeEnumPreference(SHARED_PREFS_PRIVACY_SIMPLEX_LINK_MODE, SimplexLinkMode.default) val privacyShowChatPreviews = mkBoolPreference(SHARED_PREFS_PRIVACY_SHOW_CHAT_PREVIEWS, true) val privacySaveLastDraft = mkBoolPreference(SHARED_PREFS_PRIVACY_SAVE_LAST_DRAFT, true) val privacyShortLinks = mkBoolPreference(SHARED_PREFS_PRIVACY_SHORT_LINKS, false) @@ -158,23 +138,12 @@ class AppPreferences { }, set = fun(proxy: NetworkProxy) { _networkProxy.set(json.encodeToString(proxy)) } ) - private val _networkSessionMode = mkStrPreference(SHARED_PREFS_NETWORK_SESSION_MODE, TransportSessionMode.default.name) - val networkSessionMode: SharedPreference = SharedPreference( - get = fun(): TransportSessionMode { - val value = _networkSessionMode.get() ?: return TransportSessionMode.default - return try { - TransportSessionMode.valueOf(value) - } catch (e: Throwable) { - TransportSessionMode.default - } - }, - set = fun(mode: TransportSessionMode) { _networkSessionMode.set(mode.name) } - ) - val networkSMPProxyMode = mkStrPreference(SHARED_PREFS_NETWORK_SMP_PROXY_MODE, NetCfg.defaults.smpProxyMode.name) - val networkSMPProxyFallback = mkStrPreference(SHARED_PREFS_NETWORK_SMP_PROXY_FALLBACK, NetCfg.defaults.smpProxyFallback.name) - val networkHostMode = mkStrPreference(SHARED_PREFS_NETWORK_HOST_MODE, HostMode.OnionViaSocks.name) + val networkSessionMode: SharedPreference = mkSafeEnumPreference(SHARED_PREFS_NETWORK_SESSION_MODE, TransportSessionMode.default) + val networkSMPProxyMode: SharedPreference = mkSafeEnumPreference(SHARED_PREFS_NETWORK_SMP_PROXY_MODE, SMPProxyMode.default) + val networkSMPProxyFallback: SharedPreference = mkSafeEnumPreference(SHARED_PREFS_NETWORK_SMP_PROXY_FALLBACK, SMPProxyFallback.default) + val networkHostMode: SharedPreference = mkSafeEnumPreference(SHARED_PREFS_NETWORK_HOST_MODE, HostMode.default) val networkRequiredHostMode = mkBoolPreference(SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE, false) - val networkSMPWebPort = mkBoolPreference(SHARED_PREFS_NETWORK_SMP_WEB_PORT, false) + val networkSMPWebPortServers: SharedPreference = mkSafeEnumPreference(SHARED_PREFS_NETWORK_SMP_WEB_PORT_SERVERS, SMPWebPortServers.default) val networkTCPConnectTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT, NetCfg.defaults.tcpConnectTimeout, NetCfg.proxyDefaults.tcpConnectTimeout) val networkTCPTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_TIMEOUT, NetCfg.defaults.tcpTimeout, NetCfg.proxyDefaults.tcpTimeout) val networkTCPTimeoutPerKb = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_TIMEOUT_PER_KB, NetCfg.defaults.tcpTimeoutPerKb, NetCfg.proxyDefaults.tcpTimeoutPerKb) @@ -329,7 +298,19 @@ class AppPreferences { set = fun(value) = settings.putString(prefName, value.toString()) ) - // LALAL + private inline fun > mkSafeEnumPreference(key: String, default: T): SharedPreference = SharedPreference( + get = { + val value = settings.getString(key, "") + if (value == "") return@SharedPreference default + try { + enumValueOf(value) + } catch (e: IllegalArgumentException) { + default + } + }, + set = { value -> settings.putString(key, value.name) } + ) + private fun mkDatePreference(prefName: String, default: Instant?): SharedPreference = SharedPreference( get = { @@ -414,7 +395,7 @@ class AppPreferences { private const val SHARED_PREFS_NETWORK_SMP_PROXY_FALLBACK = "NetworkSMPProxyFallback" private const val SHARED_PREFS_NETWORK_HOST_MODE = "NetworkHostMode" private const val SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE = "NetworkRequiredHostMode" - private const val SHARED_PREFS_NETWORK_SMP_WEB_PORT = "NetworkSMPWebPort" + private const val SHARED_PREFS_NETWORK_SMP_WEB_PORT_SERVERS = "NetworkSMPWebPortServers" private const val SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT = "NetworkTCPConnectTimeout" private const val SHARED_PREFS_NETWORK_TCP_TIMEOUT = "NetworkTCPTimeout" private const val SHARED_PREFS_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb" @@ -3309,12 +3290,12 @@ object ChatController { } else { null } - val hostMode = HostMode.valueOf(appPrefs.networkHostMode.get()!!) + val hostMode = appPrefs.networkHostMode.get() val requiredHostMode = appPrefs.networkRequiredHostMode.get() val sessionMode = appPrefs.networkSessionMode.get() - val smpProxyMode = SMPProxyMode.valueOf(appPrefs.networkSMPProxyMode.get()!!) - val smpProxyFallback = SMPProxyFallback.valueOf(appPrefs.networkSMPProxyFallback.get()!!) - val smpWebPort = appPrefs.networkSMPWebPort.get() + val smpProxyMode = appPrefs.networkSMPProxyMode.get() + val smpProxyFallback = appPrefs.networkSMPProxyFallback.get() + val smpWebPortServers = appPrefs.networkSMPWebPortServers.get() val tcpConnectTimeout = appPrefs.networkTCPConnectTimeout.get() val tcpTimeout = appPrefs.networkTCPTimeout.get() val tcpTimeoutPerKb = appPrefs.networkTCPTimeoutPerKb.get() @@ -3337,7 +3318,7 @@ object ChatController { sessionMode = sessionMode, smpProxyMode = smpProxyMode, smpProxyFallback = smpProxyFallback, - smpWebPort = smpWebPort, + smpWebPortServers = smpWebPortServers, tcpConnectTimeout = tcpConnectTimeout, tcpTimeout = tcpTimeout, tcpTimeoutPerKb = tcpTimeoutPerKb, @@ -3353,12 +3334,12 @@ object ChatController { * */ fun setNetCfg(cfg: NetCfg) { appPrefs.networkUseSocksProxy.set(cfg.useSocksProxy) - appPrefs.networkHostMode.set(cfg.hostMode.name) + appPrefs.networkHostMode.set(cfg.hostMode) appPrefs.networkRequiredHostMode.set(cfg.requiredHostMode) appPrefs.networkSessionMode.set(cfg.sessionMode) - appPrefs.networkSMPProxyMode.set(cfg.smpProxyMode.name) - appPrefs.networkSMPProxyFallback.set(cfg.smpProxyFallback.name) - appPrefs.networkSMPWebPort.set(cfg.smpWebPort) + appPrefs.networkSMPProxyMode.set(cfg.smpProxyMode) + appPrefs.networkSMPProxyFallback.set(cfg.smpProxyFallback) + appPrefs.networkSMPWebPortServers.set(cfg.smpWebPortServers) appPrefs.networkTCPConnectTimeout.set(cfg.tcpConnectTimeout) appPrefs.networkTCPTimeout.set(cfg.tcpTimeout) appPrefs.networkTCPTimeoutPerKb.set(cfg.tcpTimeoutPerKb) @@ -4460,13 +4441,13 @@ data class ParsedServerAddress ( @Serializable data class NetCfg( val socksProxy: String?, - val socksMode: SocksMode = SocksMode.Always, - val hostMode: HostMode = HostMode.OnionViaSocks, + val socksMode: SocksMode = SocksMode.default, + val hostMode: HostMode = HostMode.default, val requiredHostMode: Boolean = false, val sessionMode: TransportSessionMode = TransportSessionMode.default, - val smpProxyMode: SMPProxyMode = SMPProxyMode.Always, - val smpProxyFallback: SMPProxyFallback = SMPProxyFallback.AllowProtected, - val smpWebPort: Boolean = false, + val smpProxyMode: SMPProxyMode = SMPProxyMode.default, + val smpProxyFallback: SMPProxyFallback = SMPProxyFallback.default, + val smpWebPortServers: SMPWebPortServers = SMPWebPortServers.default, val tcpConnectTimeout: Long, // microseconds val tcpTimeout: Long, // microseconds val tcpTimeoutPerKb: Long, // microseconds @@ -4564,12 +4545,20 @@ enum class HostMode { @SerialName("onionViaSocks") OnionViaSocks, @SerialName("onion") Onion, @SerialName("public") Public; + + companion object { + val default = OnionViaSocks + } } @Serializable enum class SocksMode { @SerialName("always") Always, @SerialName("onion") Onion; + + companion object { + val default = Always + } } @Serializable @@ -4578,6 +4567,10 @@ enum class SMPProxyMode { @SerialName("unknown") Unknown, @SerialName("unprotected") Unprotected, @SerialName("never") Never; + + companion object { + val default = Always + } } @Serializable @@ -4585,6 +4578,27 @@ enum class SMPProxyFallback { @SerialName("allow") Allow, @SerialName("allowProtected") AllowProtected, @SerialName("prohibit") Prohibit; + + companion object { + val default = AllowProtected + } +} + +@Serializable +enum class SMPWebPortServers { + @SerialName("all") All, + @SerialName("preset") Preset, + @SerialName("off") Off; + + val text get(): StringResource = when (this) { + All -> MR.strings.network_smp_web_port_all + Preset -> MR.strings.network_smp_web_port_preset + Off -> MR.strings.network_smp_web_port_off + } + + companion object { + val default = Preset + } } @Serializable diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/AdvancedNetworkSettings.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/AdvancedNetworkSettings.kt index e85d88c5f8..0c38b0c045 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/AdvancedNetworkSettings.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/AdvancedNetworkSettings.kt @@ -19,6 +19,7 @@ import dev.icerock.moko.resources.compose.painterResource import dev.icerock.moko.resources.compose.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import chat.simplex.common.model.* import chat.simplex.common.model.ChatController.appPrefs import chat.simplex.common.ui.theme.* @@ -45,7 +46,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U val sessionMode = remember { mutableStateOf(currentCfgVal.sessionMode) } val smpProxyMode = remember { mutableStateOf(currentCfgVal.smpProxyMode) } val smpProxyFallback = remember { mutableStateOf(currentCfgVal.smpProxyFallback) } - val smpWebPort = remember { mutableStateOf(currentCfgVal.smpWebPort) } + val smpWebPortServers = remember { mutableStateOf(currentCfgVal.smpWebPortServers) } val networkTCPConnectTimeout = remember { mutableStateOf(currentCfgVal.tcpConnectTimeout) } val networkTCPTimeout = remember { mutableStateOf(currentCfgVal.tcpTimeout) } @@ -84,7 +85,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U sessionMode = sessionMode.value, smpProxyMode = smpProxyMode.value, smpProxyFallback = smpProxyFallback.value, - smpWebPort = smpWebPort.value, + smpWebPortServers = smpWebPortServers.value, tcpConnectTimeout = networkTCPConnectTimeout.value, tcpTimeout = networkTCPTimeout.value, tcpTimeoutPerKb = networkTCPTimeoutPerKb.value, @@ -99,7 +100,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U sessionMode.value = cfg.sessionMode smpProxyMode.value = cfg.smpProxyMode smpProxyFallback.value = cfg.smpProxyFallback - smpWebPort.value = cfg.smpWebPort + smpWebPortServers.value = cfg.smpWebPortServers networkTCPConnectTimeout.value = cfg.tcpConnectTimeout networkTCPTimeout.value = cfg.tcpTimeout networkTCPTimeoutPerKb.value = cfg.tcpTimeoutPerKb @@ -154,7 +155,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U sessionMode = sessionMode, smpProxyMode = smpProxyMode, smpProxyFallback = smpProxyFallback, - smpWebPort, + smpWebPortServers, networkTCPConnectTimeout, networkTCPTimeout, networkTCPTimeoutPerKb, @@ -187,7 +188,7 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U sessionMode: MutableState, smpProxyMode: MutableState, smpProxyFallback: MutableState, - smpWebPort: MutableState, + smpWebPortServers: MutableState, networkTCPConnectTimeout: MutableState, networkTCPTimeout: MutableState, networkTCPTimeoutPerKb: MutableState, @@ -226,11 +227,16 @@ fun ModalData.AdvancedNetworkSettingsView(showModal: (ModalData.() -> Unit) -> U } SectionDividerSpaced() SectionView(stringResource(MR.strings.network_smp_web_port_section_title).uppercase()) { - PreferenceToggle(stringResource(MR.strings.network_smp_web_port_toggle), checked = smpWebPort.value) { - smpWebPort.value = it - } + ExposedDropDownSettingRow( + stringResource(MR.strings.network_smp_web_port_toggle), + SMPWebPortServers.entries.map { it to stringResource(it.text) }, + smpWebPortServers + ) { smpWebPortServers.value = it } } - SectionTextFooter(String.format(stringResource(MR.strings.network_smp_web_port_footer), if (smpWebPort.value) "443" else "5223")) + SectionTextFooter( + if (smpWebPortServers.value == SMPWebPortServers.Preset) stringResource(MR.strings.network_smp_web_port_preset_footer) + else String.format(stringResource(MR.strings.network_smp_web_port_footer), if (smpWebPortServers.value == SMPWebPortServers.All) "443" else "5223") + ) SectionDividerSpaced(maxTopPadding = true) SectionView(stringResource(MR.strings.network_option_tcp_connection).uppercase()) { @@ -320,7 +326,7 @@ private fun SMPProxyModePicker( ) { val density = LocalDensity.current val values = remember { - SMPProxyMode.values().map { + SMPProxyMode.entries.map { when (it) { SMPProxyMode.Always -> ValueTitleDesc(SMPProxyMode.Always, generalGetString(MR.strings.network_smp_proxy_mode_always), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_always_description), density)) SMPProxyMode.Unknown -> ValueTitleDesc(SMPProxyMode.Unknown, generalGetString(MR.strings.network_smp_proxy_mode_unknown), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_mode_unknown_description), density)) @@ -355,7 +361,7 @@ private fun SMPProxyFallbackPicker( ) { val density = LocalDensity.current val values = remember { - SMPProxyFallback.values().map { + SMPProxyFallback.entries.map { when (it) { SMPProxyFallback.Allow -> ValueTitleDesc(SMPProxyFallback.Allow, generalGetString(MR.strings.network_smp_proxy_fallback_allow), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_fallback_allow_description), density)) SMPProxyFallback.AllowProtected -> ValueTitleDesc(SMPProxyFallback.AllowProtected, generalGetString(MR.strings.network_smp_proxy_fallback_allow_protected), escapedHtmlToAnnotatedString(generalGetString(MR.strings.network_smp_proxy_fallback_allow_protected_description), density)) @@ -548,7 +554,7 @@ fun PreviewAdvancedNetworkSettingsLayout() { sessionMode = remember { mutableStateOf(TransportSessionMode.User) }, smpProxyMode = remember { mutableStateOf(SMPProxyMode.Never) }, smpProxyFallback = remember { mutableStateOf(SMPProxyFallback.Allow) }, - smpWebPort = remember { mutableStateOf(false) }, + smpWebPortServers = remember { mutableStateOf(SMPWebPortServers.Preset) }, networkTCPConnectTimeout = remember { mutableStateOf(10_000000) }, networkTCPTimeout = remember { mutableStateOf(10_000000) }, networkTCPTimeoutPerKb = remember { mutableStateOf(10_000) }, diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 90a176658d..1bea4c18d4 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -964,6 +964,10 @@ TCP port for messaging Use web port Use TCP port %1$s when no port is specified. + Use TCP port 443 for preset servers only. + All servers + Preset servers + Off Appearance Customize theme INTERFACE COLORS diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml index dafa22dfa9..97742f82a8 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/ru/strings.xml @@ -2440,6 +2440,10 @@ Пожаловаться: увидят только модераторы группы. Выключить уведомления для всех Использовать TCP-порт %1$s, когда порт не указан. + Использовать TCP-порт 443 только для серверов по умолчанию. + Все серверы + Серверы по умолчанию + Нет Использовать веб-порт Нет Пожаловаться на сообщение: увидят только модераторы группы. diff --git a/cabal.project b/cabal.project index 28403c9fff..4a95ae3cfe 100644 --- a/cabal.project +++ b/cabal.project @@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd source-repository-package type: git location: https://github.com/simplex-chat/simplexmq.git - tag: ec5a60430d6e2b1b4f33fa1790effbb6060bf7b8 + tag: 08b84deba458407ae97d55debd98b872cb6c4d79 source-repository-package type: git diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index e71a13b22a..c945d72656 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."ec5a60430d6e2b1b4f33fa1790effbb6060bf7b8" = "0q238j7w976f9nx7r3gd61yhj557zwcxvrbci5lq7fib0v4ja7aw"; + "https://github.com/simplex-chat/simplexmq.git"."08b84deba458407ae97d55debd98b872cb6c4d79" = "0b4n7d81spl1r7zppr0lc40ls9m1i93g4l3hzg2996pi3bxmafrr"; "https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38"; "https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d"; "https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl"; diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 02a765bb19..6b554d29c4 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -89,6 +89,7 @@ defaultChatConfig = -- to have a different set of servers on the receiving end and on the sending end. -- To preserve backward compatibility receiving end should update before the sending. shortLinkPresetServers = allPresetServers, + presetDomains = [".simplex.im", ".simplexonflux.com"], tbqSize = 1024, fileChunkSize = 15780, -- do not change xftpDescrPartSize = 14000, @@ -240,12 +241,12 @@ newChatController randomServerCfgs name p opDomains rndSrvs = toJustOrError name $ L.nonEmpty $ agentServerCfgs p opDomains $ concatMap (pServers p) rndSrvs agentServers :: DB.Connection -> ChatConfig -> NonEmpty PresetOperator -> RandomAgentServers -> IO InitialAgentServers - agentServers db ChatConfig {presetServers = PresetServers {ntf, netCfg}} presetOps as = do + agentServers db ChatConfig {presetServers = PresetServers {ntf, netCfg}, presetDomains} presetOps as = do users <- getUsers db ops <- getUpdateServerOperators db presetOps (null users) let opDomains = operatorDomains $ mapMaybe snd ops (smp', xftp') <- unzip <$> mapM (getServers ops opDomains) users - pure InitialAgentServers {smp = M.fromList (optServers smp' smpServers), xftp = M.fromList (optServers xftp' xftpServers), ntf, netCfg} + pure InitialAgentServers {smp = M.fromList (optServers smp' smpServers), xftp = M.fromList (optServers xftp' xftpServers), ntf, netCfg, presetDomains} where optServers :: [(UserId, NonEmpty (ServerCfg p))] -> [ProtoServerWithAuth p] -> [(UserId, NonEmpty (ServerCfg p))] optServers srvs overrides_ = case L.nonEmpty overrides_ of diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index 21d5f1041b..bd4d418158 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -50,6 +50,7 @@ import Data.Time.Clock.System (SystemTime (..), systemToUTCTime) import Data.Version (showVersion) import Data.Word (Word16) import Language.Haskell.TH (Exp, Q, runIO) +import Network.Socket (HostName) import Numeric.Natural import qualified Paths_simplex_chat as SC import Simplex.Chat.AppSettings @@ -77,7 +78,7 @@ import Simplex.Messaging.Agent.Protocol import Simplex.Messaging.Agent.Store.Common (DBStore, withTransaction, withTransactionPriority) import Simplex.Messaging.Agent.Store.Shared (MigrationConfirmation, UpMigration) import qualified Simplex.Messaging.Agent.Store.DB as DB -import Simplex.Messaging.Client (HostMode (..), SMPProxyFallback (..), SMPProxyMode (..), SocksMode (..)) +import Simplex.Messaging.Client (HostMode (..), SMPProxyFallback (..), SMPProxyMode (..), SMPWebPortServers (..), SocksMode (..)) import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Crypto.File (CryptoFile (..)) import qualified Simplex.Messaging.Crypto.File as CF @@ -139,6 +140,7 @@ data ChatConfig = ChatConfig confirmMigrations :: MigrationConfirmation, presetServers :: PresetServers, shortLinkPresetServers :: NonEmpty SMPServer, + presetDomains :: [HostName], tbqSize :: Natural, fileChunkSize :: Integer, xftpDescrPartSize :: Int, @@ -1053,7 +1055,7 @@ data SimpleNetCfg = SimpleNetCfg requiredHostMode :: Bool, smpProxyMode_ :: Maybe SMPProxyMode, smpProxyFallback_ :: Maybe SMPProxyFallback, - smpWebPort :: Bool, + smpWebPortServers :: SMPWebPortServers, tcpTimeout_ :: Maybe Int, logTLSErrors :: Bool } @@ -1068,7 +1070,7 @@ defaultSimpleNetCfg = requiredHostMode = False, smpProxyMode_ = Nothing, smpProxyFallback_ = Nothing, - smpWebPort = False, + smpWebPortServers = SWPPreset, tcpTimeout_ = Nothing, logTLSErrors = False } diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index 5c544e3397..d10959178c 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -91,7 +91,7 @@ import Simplex.Messaging.Agent.Store.Interface (execSQL) import Simplex.Messaging.Agent.Store.Shared (upMigration) import qualified Simplex.Messaging.Agent.Store.DB as DB import Simplex.Messaging.Agent.Store.Interface (getCurrentMigrations) -import Simplex.Messaging.Client (NetworkConfig (..), SocksMode (SMAlways), textToHostMode) +import Simplex.Messaging.Client (NetworkConfig (..), SMPWebPortServers (..), SocksMode (SMAlways), textToHostMode) import qualified Simplex.Messaging.Crypto as C import Simplex.Messaging.Crypto.File (CryptoFile (..), CryptoFileArgs (..)) import qualified Simplex.Messaging.Crypto.File as CF @@ -255,11 +255,11 @@ stopChatController ChatController {smpAgent, agentAsync = s, sndFiles, rcvFiles, atomically $ writeTVar files M.empty updateNetworkConfig :: NetworkConfig -> SimpleNetCfg -> NetworkConfig -updateNetworkConfig cfg SimpleNetCfg {socksProxy, socksMode, hostMode, requiredHostMode, smpProxyMode_, smpProxyFallback_, smpWebPort, tcpTimeout_, logTLSErrors} = +updateNetworkConfig cfg SimpleNetCfg {socksProxy, socksMode, hostMode, requiredHostMode, smpProxyMode_, smpProxyFallback_, smpWebPortServers, tcpTimeout_, logTLSErrors} = let cfg1 = maybe cfg (\smpProxyMode -> cfg {smpProxyMode}) smpProxyMode_ cfg2 = maybe cfg1 (\smpProxyFallback -> cfg1 {smpProxyFallback}) smpProxyFallback_ cfg3 = maybe cfg2 (\tcpTimeout -> cfg2 {tcpTimeout, tcpConnectTimeout = (tcpTimeout * 3) `div` 2}) tcpTimeout_ - in cfg3 {socksProxy, socksMode, hostMode, requiredHostMode, smpWebPort, logTLSErrors} + in cfg3 {socksProxy, socksMode, hostMode, requiredHostMode, smpWebPortServers, logTLSErrors} useServers :: Foldable f => RandomAgentServers -> [(Text, ServerOperator)] -> f UserOperatorServers -> (NonEmpty (ServerCfg 'PSMP), NonEmpty (ServerCfg 'PXFTP)) useServers as opDomains uss = @@ -4383,11 +4383,11 @@ chatCommandP = requiredHostMode <- (" required-host-mode" $> True) <|> pure False smpProxyMode_ <- optional $ " smp-proxy=" *> strP smpProxyFallback_ <- optional $ " smp-proxy-fallback=" *> strP - smpWebPort <- (" smp-web-port" $> True) <|> pure False + smpWebPortServers <- (" smp-web-port-servers=" *> strP) <|> (" smp-web-port" $> SWPAll) <|> pure SWPPreset t_ <- optional $ " timeout=" *> A.decimal logTLSErrors <- " log=" *> onOffP <|> pure False let tcpTimeout_ = (1000000 *) <$> t_ - pure $ SimpleNetCfg {socksProxy, socksMode, hostMode, requiredHostMode, smpProxyMode_, smpProxyFallback_, smpWebPort, tcpTimeout_, logTLSErrors} + pure $ SimpleNetCfg {socksProxy, socksMode, hostMode, requiredHostMode, smpProxyMode_, smpProxyFallback_, smpWebPortServers, tcpTimeout_, logTLSErrors} #if !defined(dbPostgres) dbKeyP = nonEmptyKey <$?> strP nonEmptyKey k@(DBEncryptionKey s) = if BA.null s then Left "empty key" else Right k diff --git a/src/Simplex/Chat/Operators/Presets.hs b/src/Simplex/Chat/Operators/Presets.hs index 4aa0903d3c..06c2e19fab 100644 --- a/src/Simplex/Chat/Operators/Presets.hs +++ b/src/Simplex/Chat/Operators/Presets.hs @@ -46,7 +46,7 @@ operatorFlux = -- so that option used for restoring links is updated earlier, for backward/forward compatibility. allPresetServers :: NonEmpty SMPServer allPresetServers = enabledSimplexChatSMPServers <> disabledSimplexChatSMPServers <> fluxSMPServers_ - -- TODO [short links] remove, added for testing + -- added for testing, not preset in the clients <> ["smp://8Af90NX2TTkKEJAF1RCg69P_Odg2Z-6_J6DOKUqK3rQ=@smp7.simplex.im,dbxqutskmmbkbrs7ofi7pmopeyhgi5cxbjbh4ummgmep4r6bz4cbrcid.onion"] simplexChatSMPServers :: [NewUserServer 'PSMP] @@ -87,7 +87,7 @@ disabledSimplexChatSMPServers = ] fluxSMPServers :: [NewUserServer 'PSMP] -fluxSMPServers = map (presetServer' True) $ L.toList fluxSMPServers_ +fluxSMPServers = map (presetServer' True) (L.toList fluxSMPServers_) -- Please note: if any servers are removed from this list, they MUST be added to allPresetServers. -- Otherwise previously created short links won't work. diff --git a/src/Simplex/Chat/Options.hs b/src/Simplex/Chat/Options.hs index de657a9d74..ff2af56b85 100644 --- a/src/Simplex/Chat/Options.hs +++ b/src/Simplex/Chat/Options.hs @@ -29,7 +29,7 @@ import Numeric.Natural (Natural) import Options.Applicative import Simplex.Chat.Controller (ChatLogLevel (..), SimpleNetCfg (..), updateStr, versionNumber, versionString) import Simplex.FileTransfer.Description (mb) -import Simplex.Messaging.Client (HostMode (..), SocksMode (..), textToHostMode) +import Simplex.Messaging.Client (HostMode (..), SMPWebPortServers (..), SocksMode (..), textToHostMode) import Simplex.Messaging.Encoding.String import Simplex.Messaging.Parsers (parseAll) import Simplex.Messaging.Protocol (ProtoServerWithAuth, ProtocolTypeI, SMPServerWithAuth, XFTPServerWithAuth) @@ -153,11 +153,17 @@ coreChatOptsP appDir defaultDbName = do <> metavar "SMP_PROXY_FALLBACK_MODE" <> help "Allow downgrade and connect directly: no, [when IP address is] protected (default), yes" ) - smpWebPort <- - switch + smpWebPortServers <- + flag' SWPAll ( long "smp-web-port" <> help "Use port 443 with SMP servers when not specified" ) + <|> option + strParse + ( long "smp-web-port-servers" + <> help "Use port 443 with SMP servers when not specified: all, preset (default), off" + <> value SWPPreset + ) t <- option auto @@ -243,7 +249,7 @@ coreChatOptsP appDir defaultDbName = do requiredHostMode, smpProxyMode_, smpProxyFallback_, - smpWebPort, + smpWebPortServers, tcpTimeout_ = Just $ useTcpTimeout socksProxy t, logTLSErrors },