commit 852609ee30a861caa67ffdc7dc73882897254f15
parent 1e44d97a97fbcf50097650527d4d096b2efad7ed
Author: Terry Yiu <963907+tyiu@users.noreply.github.com>
Date:   Thu,  2 Feb 2023 23:27:37 -0500
Add alert to warn against posting nsec1 private keys
Changelog-Added: Warn when attempting to post an nsec key
Closes: #498
Diffstat:
4 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/damus/Components/TranslateView.swift b/damus/Components/TranslateView.swift
@@ -92,7 +92,7 @@ struct TranslateView: View {
                 if #available(iOS 16, *) {
                     noteLanguage = Locale.LanguageCode(stringLiteral: lang).identifier(.alpha2)
                 } else {
-                    noteLanguage = Locale.canonicalLanguageIdentifier(from: lang)
+                    noteLanguage = NSLocale(localeIdentifier: lang).languageCode
                 }
             }
             
diff --git a/damus/Util/Keys.swift b/damus/Util/Keys.swift
@@ -158,6 +158,20 @@ func get_saved_privkey() -> String? {
     return mkey.map { $0.trimmingCharacters(in: .whitespaces) }
 }
 
+/**
+ Detects whether a string might contain an nsec1 prefixed private key.
+ It does not determine if it's the current user's private key and does not verify if it is properly encoded or has the right length.
+ */
+func contentContainsPrivateKey(_ content: String) -> Bool {
+    if #available(iOS 16.0, *) {
+        return content.contains(/nsec1[02-9ac-z]+/)
+    } else {
+        let regex = try! NSRegularExpression(pattern: "nsec1[02-9ac-z]+")
+        return (regex.firstMatch(in: content, range: NSRange(location: 0, length: content.count)) != nil)
+    }
+
+}
+
 fileprivate func removePrivateKeyFromUserDefaults() throws {
     guard let privKey = UserDefaults.standard.string(forKey: "privkey") else { return }
     try save_privkey(privkey: privKey)
diff --git a/damus/Views/DMChatView.swift b/damus/Views/DMChatView.swift
@@ -12,6 +12,7 @@ struct DMChatView: View {
     let pubkey: String
     @EnvironmentObject var dms: DirectMessageModel
     @State var message: String = ""
+    @State var showPrivateKeyWarning: Bool = false
 
     var Messages: some View {
         ScrollViewReader { scroller in
@@ -93,7 +94,16 @@ struct DMChatView: View {
                 InputField
 
                 if !message.isEmpty {
-                    Button(role: .none, action: send_message) {
+                    Button(
+                        role: .none,
+                        action: {
+                            showPrivateKeyWarning = contentContainsPrivateKey(message)
+
+                            if !showPrivateKeyWarning {
+                                send_message()
+                            }
+                        }
+                    ) {
                         Label("", systemImage: "arrow.right.circle")
                             .font(.title)
                     }
@@ -147,6 +157,14 @@ struct DMChatView: View {
         }
         .navigationTitle(NSLocalizedString("DMs", comment: "Navigation title for DMs view, where DM is the English abbreviation for Direct Message."))
         .toolbar { Header }
+        .alert(NSLocalizedString("Note contains \"nsec1\" private key. Are you sure?", comment: "Alert user that they might be attempting to paste a private key and ask them to confirm."), isPresented: $showPrivateKeyWarning, actions: {
+            Button(NSLocalizedString("No", comment: "Button to cancel out of posting a note after being alerted that it looks like they might be posting a private key."), role: .cancel) {
+                showPrivateKeyWarning = false
+            }
+            Button(NSLocalizedString("Yes, Post with Private Key", comment: "Button to proceed with posting a note even though it looks like they might be posting a private key."), role: .destructive) {
+                send_message()
+            }
+        })
     }
 }
 
diff --git a/damus/Views/PostView.swift b/damus/Views/PostView.swift
@@ -17,6 +17,7 @@ let POST_PLACEHOLDER = NSLocalizedString("Type your post here...", comment: "Tex
 struct PostView: View {
     @State var post: String = ""
     @FocusState var focus: Bool
+    @State var showPrivateKeyWarning: Bool = false
     
     let replying_to: NostrEvent?
     let references: [ReferencedId]
@@ -65,7 +66,11 @@ struct PostView: View {
 
                 if !is_post_empty {
                     Button(NSLocalizedString("Post", comment: "Button to post a note.")) {
-                        self.send_post()
+                        showPrivateKeyWarning = contentContainsPrivateKey(self.post)
+
+                        if !showPrivateKeyWarning {
+                            self.send_post()
+                        }
                     }
                 }
             }
@@ -99,6 +104,14 @@ struct PostView: View {
             }
         }
         .padding()
+        .alert(NSLocalizedString("Note contains \"nsec1\" private key. Are you sure?", comment: "Alert user that they might be attempting to paste a private key and ask them to confirm."), isPresented: $showPrivateKeyWarning, actions: {
+            Button(NSLocalizedString("No", comment: "Button to cancel out of posting a note after being alerted that it looks like they might be posting a private key."), role: .cancel) {
+                showPrivateKeyWarning = false
+            }
+            Button(NSLocalizedString("Yes, Post with Private Key", comment: "Button to proceed with posting a note even though it looks like they might be posting a private key."), role: .destructive) {
+                self.send_post()
+            }
+        })
     }
 }