From 722d9efc137defbe67f892f46fa1bf7eb2fa83d0 Mon Sep 17 00:00:00 2001
From: HackerNCoder <hackerncoder@encryptionin.space>
Date: Tue, 24 Oct 2023 14:57:40 +0000
Subject: [PATCH] Use starts_with for forbidden unicode (Fix #3888) (#4079)

* Use starts_with for forbidden unicode (Fix #3888)

* Require 3 visible chars in display name

* Run cargo fmt and scripts/lint

* Undo invisibly_starts_with_at

* Remove 3 min chars.count() check for display name
---
 crates/utils/src/utils/validation.rs | 31 ++++++++++++++++++++++++----
 1 file changed, 27 insertions(+), 4 deletions(-)

diff --git a/crates/utils/src/utils/validation.rs b/crates/utils/src/utils/validation.rs
index 33c78b654..46fe9e2d0 100644
--- a/crates/utils/src/utils/validation.rs
+++ b/crates/utils/src/utils/validation.rs
@@ -99,13 +99,29 @@ pub fn is_valid_actor_name(name: &str, actor_name_max_length: usize) -> LemmyRes
   }
 }
 
+fn has_3_permitted_display_chars(name: &str) -> bool {
+  let mut num_non_fdc: i8 = 0;
+  for c in name.chars() {
+    if !FORBIDDEN_DISPLAY_CHARS.contains(&c) {
+      num_non_fdc += 1;
+      if num_non_fdc >= 3 {
+        break;
+      }
+    }
+  }
+  if num_non_fdc >= 3 {
+    return true;
+  }
+  false
+}
+
 // Can't do a regex here, reverse lookarounds not supported
 pub fn is_valid_display_name(name: &str, actor_name_max_length: usize) -> LemmyResult<()> {
-  let check = !name.contains(FORBIDDEN_DISPLAY_CHARS)
-    && !name.starts_with('@')
-    && name.chars().count() >= 3
+  let check = !name.starts_with('@')
+    && !name.starts_with(FORBIDDEN_DISPLAY_CHARS)
     && name.chars().count() <= actor_name_max_length
-    && !has_newline(name);
+    && !has_newline(name)
+    && has_3_permitted_display_chars(name);
   if !check {
     Err(LemmyErrorType::InvalidDisplayName.into())
   } else {
@@ -323,6 +339,13 @@ mod tests {
     let actor_name_max_length = 20;
     assert!(is_valid_display_name("hello @there", actor_name_max_length).is_ok());
     assert!(is_valid_display_name("@hello there", actor_name_max_length).is_err());
+    assert!(is_valid_display_name("\u{200d}hello", actor_name_max_length).is_err());
+    assert!(is_valid_display_name(
+      "\u{1f3f3}\u{fe0f}\u{200d}\u{26a7}\u{fe0f}Name",
+      actor_name_max_length
+    )
+    .is_ok());
+    assert!(is_valid_display_name("\u{2003}1\u{ffa0}2\u{200d}", actor_name_max_length).is_err());
 
     // Make sure zero-space with an @ doesn't work
     assert!(
-- 
GitLab