diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index f3c62dc1..f5108298 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -92,6 +92,7 @@ DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193742862F6E600E59241 /* ExternalNotificationConfig.swift */; }; DD6193772862F90F00E59241 /* CannedMessagesConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */; }; DD6193792863875F00E59241 /* SerialConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193782863875F00E59241 /* SerialConfig.swift */; }; + DD6F65722C6AB8EC0053C113 /* SecureInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F65712C6AB8EC0053C113 /* SecureInput.swift */; }; DD73FD1128750779000852D6 /* PositionLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD73FD1028750779000852D6 /* PositionLog.swift */; }; DD769E0328D18BF1001A3F05 /* DeviceMetricsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD769E0228D18BF0001A3F05 /* DeviceMetricsLog.swift */; }; DD77093B2AA1ABB8007A8BF0 /* BluetoothTips.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD77093A2AA1ABB8007A8BF0 /* BluetoothTips.swift */; }; @@ -345,6 +346,7 @@ DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CannedMessagesConfig.swift; sourceTree = ""; }; DD6193782863875F00E59241 /* SerialConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerialConfig.swift; sourceTree = ""; }; DD68BAE72C417A74004C01A0 /* MeshtasticDataModelV 40.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 40.xcdatamodel"; sourceTree = ""; }; + DD6F65712C6AB8EC0053C113 /* SecureInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureInput.swift; sourceTree = ""; }; DD73FD1028750779000852D6 /* PositionLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionLog.swift; sourceTree = ""; }; DD769E0228D18BF0001A3F05 /* DeviceMetricsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceMetricsLog.swift; sourceTree = ""; }; DD77093A2AA1ABB8007A8BF0 /* BluetoothTips.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BluetoothTips.swift; sourceTree = ""; }; @@ -912,6 +914,7 @@ DD97E96528EFD9820056DDA4 /* MeshtasticLogo.swift */, DDF45C332BC1A48E005ED5F2 /* MQTTIcon.swift */, DD5E523D298F5A7D00D21B61 /* Weather */, + DD6F65712C6AB8EC0053C113 /* SecureInput.swift */, ); path = Helpers; sourceTree = ""; @@ -1281,6 +1284,7 @@ DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */, DD1BD0F32C63C65E008C0C70 /* SecurityConfig.swift in Sources */, DD2160AF28C5552500C17253 /* MQTTConfig.swift in Sources */, + DD6F65722C6AB8EC0053C113 /* SecureInput.swift in Sources */, DD13AA492AB73BF400BA0C98 /* PositionPopover.swift in Sources */, 6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */, DDDB444229F8A88700EE2349 /* Double.swift in Sources */, diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 963465b9..ceefb253 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -842,6 +842,8 @@ func textMessageAppPacket( } if fetchedUsers.first(where: { $0.num == packet.from }) != nil { newMessage.fromUser = fetchedUsers.first(where: { $0.num == packet.from }) + newMessage.fromUser?.publicKey = packet.publicKey + newMessage.fromUser?.pkiEncrypted = packet.pkiEncrypted if packet.rxTime > 0 { newMessage.fromUser?.userNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) } diff --git a/Meshtastic/Views/Helpers/SecureInput.swift b/Meshtastic/Views/Helpers/SecureInput.swift new file mode 100644 index 00000000..b4fa54eb --- /dev/null +++ b/Meshtastic/Views/Helpers/SecureInput.swift @@ -0,0 +1,57 @@ +// +// SecureInput.swift +// Meshtastic +// +// Copyright(c) Garth Vander Houwen 8/12/24. +// + +import SwiftUI + +struct SecureInput: View { + + private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } + @Binding private var text: String + @State private var isSecure: Bool = true + private var title: String + + init(_ title: String, text: Binding) { + self.title = title + self._text = text + } + + var body: some View { + ZStack(alignment: .trailing) { + Group { + if isSecure { + SecureField(title, text: $text) + .font(idiom == .phone ? .caption : .callout) + .allowsTightening(true) + .monospaced() + .keyboardType(.alphabet) + .foregroundStyle(.tertiary) + .disableAutocorrection(true) + .textSelection(.enabled) + } else { + TextField(title, text: $text, axis: .vertical) + .font(idiom == .phone ? .caption : .callout) + .allowsTightening(true) + .monospaced() + .keyboardType(.alphabet) + .foregroundStyle(.tertiary) + .disableAutocorrection(true) + .textSelection(.enabled) + .lineLimit(...3) + } + }.padding(.trailing, 36) + + if !text.isEmpty { + Button(action: { + isSecure.toggle() + }) { + Image(systemName: self.isSecure ? "eye.slash" : "eye") + .accentColor(.secondary) + } + } + } + } +} diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 9877bb3a..d031306b 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -38,70 +38,21 @@ struct SecurityConfig: View { Section(header: Text("Admin & Direct Message Keys")) { VStack(alignment: .leading) { Label("Public Key", systemImage: "key") - - TextField( - "Public Key", - text: $publicKey, - axis: .vertical - ) - .font(idiom == .phone ? .caption : .callout) - .allowsTightening(true) - .monospaced() - .keyboardType(.alphabet) - .foregroundStyle(.tertiary) - .disableAutocorrection(true) - .textSelection(.enabled) - .background( - RoundedRectangle(cornerRadius: 10.0) - .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) - ) - + SecureInput("Public Key", text: $publicKey) Text("Sent out to other nodes on the mesh to allow them to compute a shared secret key.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) } VStack(alignment: .leading) { Label("Private Key", systemImage: "key.fill") - - TextField( - "Private Key", - text: $privateKey, - axis: .vertical - ) - .font(idiom == .phone ? .caption : .callout) - .allowsTightening(true) - .monospaced() - .disableAutocorrection(true) - .keyboardType(.alphabet) - .foregroundStyle(.tertiary) - .textSelection(.enabled) - .background( - RoundedRectangle(cornerRadius: 10.0) - .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) - ) + SecureInput("Private Key", text: $privateKey) Text("Used to create a shared key with a remote device.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) } VStack(alignment: .leading) { Label("Admin Key", systemImage: "key.viewfinder") - - TextField( - "Admin Key", - text: $adminKey, - axis: .vertical - ) - .font(idiom == .phone ? .caption : .callout) - .allowsTightening(true) - .monospaced() - .disableAutocorrection(true) - .keyboardType(.alphabet) - .foregroundStyle(.tertiary) - .textSelection(.enabled) - .background( - RoundedRectangle(cornerRadius: 10.0) - .stroke(true ? Color.clear : Color.red, lineWidth: 2.0) - ) + SecureInput("Private Key", text: $adminKey) Text("The public key authorized to send admin messages to this node.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout)