diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 1952e0af..87e7edb3 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -3337,6 +3337,12 @@ } } } + }, + "By enabling the map report your node will periodically send a totally unencrypted packet to the configured MQTT server irrigardness of any channel specific uplink and downling MQTT Settings. This report includes short and long name, position, hardware model, role, firmware version, LoRa region, modem preset and primary channel name" : { + + }, + "By enabling this feature, you acknowledge and expressly consent to the transmission of your device’s real-time geographic location over the MQTT protocol without encryption. This location data may be used for purposes such as live map reporting, device tracking, and related telemetry functions." : { + }, "Bytes" : { "localizations" : { @@ -6585,6 +6591,9 @@ } } } + }, + "Consent to Share Unencrypted Location Data via MQTT" : { + }, "contacts" : { "localizations" : { @@ -13647,6 +13656,9 @@ } } } + }, + "I have read and understand the above. I voluntarily consent to the unencrypted transmission of my location data via MQTT for map reporting purposes." : { + }, "IAQ" : { "localizations" : { @@ -24253,6 +24265,9 @@ } } } + }, + "Please be advised that because MQTT transmission is not encrypted by default, your location data may be stored permanently and displayed by third parties. Meshtastic does not assume responsibility for any such unauthorized access or disclosure resulting from unencrypted transmission." : { + }, "Please connect to a radio to configure settings." : { "localizations" : { @@ -24674,22 +24689,6 @@ } } }, - "Power Metrics Log}" : { - "localizations" : { - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Registro delle metriche di potenza}" - } - }, - "sr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Логови метрике снаге}" - } - } - } - }, "Power Off" : { "localizations" : { "it" : { diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 4b7fc483..f88a0721 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -1806,7 +1806,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.22; + MARKETING_VERSION = 2.5.23; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1840,7 +1840,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.22; + MARKETING_VERSION = 2.5.23; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1872,7 +1872,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.22; + MARKETING_VERSION = 2.5.23; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1905,7 +1905,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.22; + MARKETING_VERSION = 2.5.23; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Meshtastic/Assets.xcassets/THINKNODEM1.imageset/Contents.json b/Meshtastic/Assets.xcassets/THINKNODEM1.imageset/Contents.json new file mode 100644 index 00000000..7001ca9b --- /dev/null +++ b/Meshtastic/Assets.xcassets/THINKNODEM1.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "thinknode_m1.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/THINKNODEM1.imageset/thinknode_m1.svg b/Meshtastic/Assets.xcassets/THINKNODEM1.imageset/thinknode_m1.svg new file mode 100644 index 00000000..27e21a0b --- /dev/null +++ b/Meshtastic/Assets.xcassets/THINKNODEM1.imageset/thinknode_m1.svg @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/THINKNODEM2.imageset/Contents.json b/Meshtastic/Assets.xcassets/THINKNODEM2.imageset/Contents.json new file mode 100644 index 00000000..81ee0ac1 --- /dev/null +++ b/Meshtastic/Assets.xcassets/THINKNODEM2.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "thinknode_m2.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/THINKNODEM2.imageset/thinknode_m2.svg b/Meshtastic/Assets.xcassets/THINKNODEM2.imageset/thinknode_m2.svg new file mode 100644 index 00000000..5e5a0e3c --- /dev/null +++ b/Meshtastic/Assets.xcassets/THINKNODEM2.imageset/thinknode_m2.svg @@ -0,0 +1,391 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Meshtastic/Assets.xcassets/XIAONRF52KIT.imageset/Contents.json b/Meshtastic/Assets.xcassets/XIAONRF52KIT.imageset/Contents.json new file mode 100644 index 00000000..08990d2d --- /dev/null +++ b/Meshtastic/Assets.xcassets/XIAONRF52KIT.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "seeed_xiao_nrf52_kit.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/XIAONRF52KIT.imageset/seeed_xiao_nrf52_kit.svg b/Meshtastic/Assets.xcassets/XIAONRF52KIT.imageset/seeed_xiao_nrf52_kit.svg new file mode 100644 index 00000000..95f7211b --- /dev/null +++ b/Meshtastic/Assets.xcassets/XIAONRF52KIT.imageset/seeed_xiao_nrf52_kit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Helpers/Mqtt/MqttClientProxyManager.swift b/Meshtastic/Helpers/Mqtt/MqttClientProxyManager.swift index cac34de8..6dc1854b 100644 --- a/Meshtastic/Helpers/Mqtt/MqttClientProxyManager.swift +++ b/Meshtastic/Helpers/Mqtt/MqttClientProxyManager.swift @@ -8,6 +8,7 @@ import Foundation import CocoaMQTT import OSLog +import Security protocol MqttClientProxyManagerDelegate: AnyObject { func onMqttConnected() @@ -40,8 +41,8 @@ class MqttClientProxyManager { if let host = host { let port = defaultServerPort - var username = node.mqttConfig?.username - var password = node.mqttConfig?.password + let username = node.mqttConfig?.username + let password = node.mqttConfig?.password // if host == defaultServerAddress { //username = ProcessInfo.processInfo.environment["PUBLIC_MQTT_USERNAME"] //password = ProcessInfo.processInfo.environment["PUBLIC_MQTT_PASSWORD"] @@ -130,6 +131,16 @@ extension MqttClientProxyManager: CocoaMQTTDelegate { self.disconnect() } } + func mqtt(_ mqtt: CocoaMQTT, didReceive trust: SecTrust, completionHandler: @escaping (Bool) -> Void) { + let isValid = SecTrustEvaluateWithError(trust, nil) + if isValid { + Logger.mqtt.info("📲 [MQTT Client Proxy] TLS validation succeeded.") + completionHandler(true) + } else { + Logger.mqtt.warning("📲 [MQTT Client Proxy] TLS validation failed.") + completionHandler(true) + } + } func mqttDidDisconnect(_ mqtt: CocoaMQTT, withError err: Error?) { Logger.mqtt.debug("📲 [MQTT Client Proxy] disconnected: \(err?.localizedDescription ?? "", privacy: .public)") if let error = err { diff --git a/Meshtastic/Resources/DeviceHardware.json b/Meshtastic/Resources/DeviceHardware.json index 00b80aea..bbe99f2a 100644 --- a/Meshtastic/Resources/DeviceHardware.json +++ b/Meshtastic/Resources/DeviceHardware.json @@ -543,7 +543,7 @@ "images": [ "t-watch-s3.svg" ], - "partitionScheme": "16MB" + "partitionScheme": "8MB" }, { "hwModel": 52, @@ -845,25 +845,32 @@ "hwModelSlug": "THINKNODE_M1", "platformioTarget": "thinknode_m1", "architecture": "nrf52840", - "activelySupported": false, + "activelySupported": true, "supportLevel": 1, "displayName": "ThinkNode M1", "tags": [ "Elecrow" ], - "requiresDfu": true + "requiresDfu": true, + "images": [ + "thinknode_m1.svg" + ], + "hasInkHud": true }, { "hwModel": 90, "hwModelSlug": "THINKNODE_M2", "platformioTarget": "thinknode_m2", "architecture": "esp32-s3", - "activelySupported": false, + "activelySupported": true, "supportLevel": 1, "displayName": "ThinkNode M2", "tags": [ "Elecrow" ], - "requiresDfu": false + "requiresDfu": false, + "images": [ + "thinknode_m2.svg" + ] } ] diff --git a/Meshtastic/Views/ContentView.swift b/Meshtastic/Views/ContentView.swift index d6b2fd6b..50734893 100644 --- a/Meshtastic/Views/ContentView.swift +++ b/Meshtastic/Views/ContentView.swift @@ -11,6 +11,12 @@ struct ContentView: View { @ObservedObject var router: Router + init(appState: AppState, router: Router) { + self.appState = appState + self.router = router + UITabBar.appearance().scrollEdgeAppearance = UITabBarAppearance(idiom: .unspecified) + } + var body: some View { TabView(selection: $appState.router.navigationState.selectedTab) { Messages( diff --git a/Meshtastic/Views/Messages/ChannelList.swift b/Meshtastic/Views/Messages/ChannelList.swift index a4fd86bf..426cb0c7 100644 --- a/Meshtastic/Views/Messages/ChannelList.swift +++ b/Meshtastic/Views/Messages/ChannelList.swift @@ -24,7 +24,7 @@ struct ChannelList: View { @State private var isPresentingTraceRouteSentAlert = false - var restrictedChannels = ["gpio", "mqtt", "serial"] + var restrictedChannels = ["gpio", "mqtt", "serial", "admin"] @ViewBuilder private func makeChannelRow( diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index 29b06464..046d86aa 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -30,6 +30,7 @@ struct MQTTConfig: View { @State var mqttConnected: Bool = false @State var defaultTopic = "msh/US" @State var nearbyTopics = [String]() + @State var mapReportingOptIn = false @State var mapReportingEnabled = false @State var mapPublishIntervalSecs = 3600 @State var mapPositionPrecision: Double = 14.0 @@ -92,9 +93,17 @@ struct MQTTConfig: View { } Section(header: Text("Map Report")) { + Text("Consent to Share Unencrypted Location Data via MQTT") + .font(.title2) + Text("By enabling this feature, you acknowledge and expressly consent to the transmission of your device’s real-time geographic location over the MQTT protocol without encryption. This location data may be used for purposes such as live map reporting, device tracking, and related telemetry functions.") + Text("Please be advised that because MQTT transmission is not encrypted by default, your location data may be stored permanently and displayed by third parties. Meshtastic does not assume responsibility for any such unauthorized access or disclosure resulting from unencrypted transmission.") + Toggle(isOn: $mapReportingOptIn) { + Label("I have read and understand the above. I voluntarily consent to the unencrypted transmission of my location data via MQTT for map reporting purposes.", systemImage: "hand.raised") + } Toggle(isOn: $mapReportingEnabled) { Label("enabled", systemImage: "map") + Text("By enabling the map report your node will periodically send a totally unencrypted packet to the configured MQTT server irrigardness of any channel specific uplink and downling MQTT Settings. This report includes short and long name, position, hardware model, role, firmware version, LoRa region, modem preset and primary channel name") } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) if mapReportingEnabled {