From e2f223b30a0b9f9c580fbf5a781c8e18a2581e0e Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Mon, 19 Aug 2024 21:50:28 -0700 Subject: [PATCH 1/4] Initial validation --- Meshtastic/Views/Helpers/SecureInput.swift | 8 +++- .../Settings/Config/SecurityConfig.swift | 40 +++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Meshtastic/Views/Helpers/SecureInput.swift b/Meshtastic/Views/Helpers/SecureInput.swift index b4fa54eb..663e847c 100644 --- a/Meshtastic/Views/Helpers/SecureInput.swift +++ b/Meshtastic/Views/Helpers/SecureInput.swift @@ -11,12 +11,14 @@ struct SecureInput: View { private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } @Binding private var text: String + @Binding private var isValid: Bool @State private var isSecure: Bool = true private var title: String - init(_ title: String, text: Binding) { + init(_ title: String, text: Binding, isValid: Binding) { self.title = title self._text = text + self._isValid = isValid } var body: some View { @@ -41,6 +43,10 @@ struct SecureInput: View { .disableAutocorrection(true) .textSelection(.enabled) .lineLimit(...3) + .background( + RoundedRectangle(cornerRadius: 10.0) + .stroke(isValid ? Color.clear : Color.red, lineWidth: 2.0) + ) } }.padding(.trailing, 36) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index caf64e57..5e6dbb18 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -22,8 +22,11 @@ struct SecurityConfig: View { @State var hasChanges = false @State var publicKey = "" + @State var hasValidPublicKey: Bool = false @State var privateKey = "" + @State var hasValidPrivateKey: Bool = false @State var adminKey = "" + @State var hasValidAdminKey: Bool = true @State var isManaged = false @State var serialEnabled = false @State var debugLogApiEnabled = false @@ -38,21 +41,29 @@ struct SecurityConfig: View { Section(header: Text("Admin & Direct Message Keys")) { VStack(alignment: .leading) { Label("Public Key", systemImage: "key") - SecureInput("Public Key", text: $publicKey) + SecureInput("Public Key", text: $publicKey, isValid: $hasValidPublicKey) + .background( + RoundedRectangle(cornerRadius: 10.0) + .stroke(hasValidPublicKey ? Color.clear : Color.red, lineWidth: 2.0) + ) 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") - SecureInput("Private Key", text: $privateKey) + SecureInput("Private Key", text: $privateKey, isValid: $hasValidPrivateKey) + .background( + RoundedRectangle(cornerRadius: 10.0) + .stroke(hasValidPrivateKey ? Color.clear : Color.red, lineWidth: 2.0) + ) 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") - SecureInput("Private Key", text: $adminKey) + SecureInput("Admin Key", text: $adminKey, isValid: $hasValidAdminKey) Text("The public key authorized to send admin messages to this node.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) @@ -121,12 +132,30 @@ struct SecurityConfig: View { if $0 != node?.securityConfig?.adminChannelEnabled { hasChanges = true } } .onChange(of: publicKey) { _ in + let tempKey = Data(base64Encoded: publicKey) ?? Data() + if tempKey.count == 32 { + hasValidPublicKey = true + } else { + hasValidPublicKey = false + } hasChanges = true } .onChange(of: privateKey) { _ in + let tempKey = Data(base64Encoded: privateKey) ?? Data() + if tempKey.count == 32 { + hasValidPrivateKey = true + } else { + hasValidPrivateKey = false + } hasChanges = true } .onChange(of: adminKey) { _ in + let tempAdminKey = Data(base64Encoded: adminKey) ?? Data() + if tempAdminKey.count == 0 || tempAdminKey.count == 32 { + hasValidAdminKey = true + } else { + hasValidAdminKey = false + } hasChanges = true } .onFirstAppear { @@ -140,6 +169,11 @@ struct SecurityConfig: View { } SaveConfigButton(node: node, hasChanges: $hasChanges) { + + if !hasValidAdminKey || !hasValidPrivateKey || !hasValidAdminKey { + return + } + guard let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context), let fromUser = connectedNode.user, let toUser = node?.user else { From b8861c0e0f13664486e8e36c8fa3dcf9125487aa Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 20 Aug 2024 07:33:29 -0700 Subject: [PATCH 2/4] Fix weird validation bug --- Meshtastic/Views/Settings/Config/SecurityConfig.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 5e6dbb18..e0e501c5 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -149,9 +149,11 @@ struct SecurityConfig: View { } hasChanges = true } - .onChange(of: adminKey) { _ in - let tempAdminKey = Data(base64Encoded: adminKey) ?? Data() - if tempAdminKey.count == 0 || tempAdminKey.count == 32 { + .onChange(of: adminKey) { key in + let tempKey = Data(base64Encoded: key) ?? Data() + if key.isEmpty { + hasValidAdminKey = true + } else if tempKey.count == 32 { hasValidAdminKey = true } else { hasValidAdminKey = false From 7657a2c669d80e6d81bc2e0cd61e25cb1b5eff78 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 20 Aug 2024 07:37:02 -0700 Subject: [PATCH 3/4] Clean up secure input control --- Meshtastic/Views/Helpers/SecureInput.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Meshtastic/Views/Helpers/SecureInput.swift b/Meshtastic/Views/Helpers/SecureInput.swift index 663e847c..a2994747 100644 --- a/Meshtastic/Views/Helpers/SecureInput.swift +++ b/Meshtastic/Views/Helpers/SecureInput.swift @@ -32,7 +32,6 @@ struct SecureInput: View { .keyboardType(.alphabet) .foregroundStyle(.tertiary) .disableAutocorrection(true) - .textSelection(.enabled) } else { TextField(title, text: $text, axis: .vertical) .font(idiom == .phone ? .caption : .callout) From eb3efd88adf1b72c157f8768aacfcf2d2166c561 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Tue, 20 Aug 2024 07:40:20 -0700 Subject: [PATCH 4/4] fix return statement --- Meshtastic/Views/Settings/Config/SecurityConfig.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index e0e501c5..597324e0 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -172,7 +172,7 @@ struct SecurityConfig: View { SaveConfigButton(node: node, hasChanges: $hasChanges) { - if !hasValidAdminKey || !hasValidPrivateKey || !hasValidAdminKey { + if !hasValidPublicKey || !hasValidPrivateKey || !hasValidAdminKey { return }