From cb81a9f7836c51653b05cb2df6550d5e12b73030 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Wed, 1 Jul 2020 15:30:39 -0400 Subject: [PATCH] Disallow 'visually empty' profile names. --- .../profiles/edit/EditProfileViewModel.java | 3 +- .../securesms/util/StringUtil.java | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileViewModel.java index b9da8c6d2a..c2de06b4ff 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/edit/EditProfileViewModel.java @@ -12,6 +12,7 @@ import androidx.lifecycle.ViewModelProvider; import org.thoughtcrime.securesms.groups.GroupId; import org.thoughtcrime.securesms.profiles.ProfileName; +import org.thoughtcrime.securesms.util.StringUtil; import org.thoughtcrime.securesms.util.livedata.LiveDataPair; import org.whispersystems.libsignal.util.guava.Optional; @@ -27,7 +28,7 @@ class EditProfileViewModel extends ViewModel { private final MutableLiveData originalAvatar = new MutableLiveData<>(); private final MutableLiveData> internalUsername = new MutableLiveData<>(); private final MutableLiveData originalDisplayName = new MutableLiveData<>(); - private final LiveData isFormValid = Transformations.map(givenName, name -> !name.isEmpty()); + private final LiveData isFormValid = Transformations.map(givenName, name -> !StringUtil.isVisuallyEmpty(name)); private final EditProfileRepository repository; private final GroupId groupId; diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/StringUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/StringUtil.java index b12cb581c8..addaded2ee 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/StringUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/StringUtil.java @@ -3,10 +3,17 @@ package org.thoughtcrime.securesms.util; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.google.android.collect.Sets; + import java.nio.charset.StandardCharsets; +import java.util.Set; public final class StringUtil { + private static final Set WHITESPACE = Sets.newHashSet('\u200E', // left-to-right mark + '\u200F', // right-to-left mark + '\u2007'); // figure space + private StringUtil() { } @@ -28,4 +35,30 @@ public final class StringUtil { return name; } + + /** + * @return True if the string is empty, or if it contains nothing but whitespace characters. + * Accounts for various unicode whitespace characters. + */ + public static boolean isVisuallyEmpty(@Nullable String value) { + if (value == null || value.length() == 0) { + return true; + } + + for (int i = 0; i < value.length(); i++) { + if (!isVisuallyEmpty(value.charAt(i))) { + return false; + } + } + + return true; + } + + /** + * @return True if the character is invisible or whitespace. Accounts for various unicode + * whitespace characters. + */ + public static boolean isVisuallyEmpty(char c) { + return Character.isWhitespace(c) || WHITESPACE.contains(c); + } }