From debd0a2e1101e543161390fd3ced6bda19030155 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sat, 21 Oct 2023 15:18:00 +0300 Subject: [PATCH] fix(YouTube - Custom filter): Fix app crash if invalid character is used in custom filter (#506) --- .../patches/components/LithoFilterPatch.java | 16 +++- .../integrations/utils/ByteTrieSearch.java | 47 ++++------ .../integrations/utils/StringTrieSearch.java | 46 ++++----- .../integrations/utils/TrieSearch.java | 93 +++++++++++-------- 4 files changed, 98 insertions(+), 104 deletions(-) diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java index a4051c55..5213025d 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java @@ -128,8 +128,20 @@ class StringFilterGroup extends FilterGroup { final class CustomFilterGroup extends StringFilterGroup { - public CustomFilterGroup(final SettingsEnum setting, final SettingsEnum filter) { - super(setting, filter.getString().split("\\s+")); + private static String[] getFilterPatterns(SettingsEnum setting) { + String[] patterns = setting.getString().split("\\s+"); + for (String pattern : patterns) { + if (!StringTrieSearch.isValidPattern(pattern)) { + ReVancedUtils.showToastLong("Invalid custom filter, resetting to default"); + setting.saveValue(setting.defaultValue); + return getFilterPatterns(setting); + } + } + return patterns; + } + + public CustomFilterGroup(SettingsEnum setting, SettingsEnum filter) { + super(setting, getFilterPatterns(filter)); } } diff --git a/app/src/main/java/app/revanced/integrations/utils/ByteTrieSearch.java b/app/src/main/java/app/revanced/integrations/utils/ByteTrieSearch.java index 02a1ff70..4e47d555 100644 --- a/app/src/main/java/app/revanced/integrations/utils/ByteTrieSearch.java +++ b/app/src/main/java/app/revanced/integrations/utils/ByteTrieSearch.java @@ -1,10 +1,5 @@ package app.revanced.integrations.utils; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Objects; - public final class ByteTrieSearch extends TrieSearch { private static final class ByteTrieNode extends TrieNode { @@ -22,35 +17,25 @@ public final class ByteTrieSearch extends TrieSearch { char getCharValue(byte[] text, int index) { return (char) text[index]; } + @Override + int getTextLength(byte[] text) { + return text.length; + } + } + + /** + * @return If the pattern is valid to add to this instance. + */ + public static boolean isValidPattern(byte[] pattern) { + for (byte b : pattern) { + if (TrieNode.isInvalidRange((char) b)) { + return false; + } + } + return true; } public ByteTrieSearch() { super(new ByteTrieNode()); } - - @Override - public void addPattern(@NonNull byte[] pattern) { - super.addPattern(pattern, pattern.length, null); - } - - @Override - public void addPattern(@NonNull byte[] pattern, @NonNull TriePatternMatchedCallback callback) { - super.addPattern(pattern, pattern.length, Objects.requireNonNull(callback)); - } - - @Override - public boolean matches(@NonNull byte[] textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) { - return super.matches(textToSearch, textToSearch.length, startIndex, endIndex, callbackParameter); - } - - @Override - public boolean matches(@NonNull byte[] textToSearch, int startIndex) { - return matches(textToSearch, startIndex, textToSearch.length, null); - } - - @Override - public boolean matches(@NonNull byte[] textToSearch, @Nullable Object callbackParameter) { - return matches(textToSearch,0, textToSearch.length, callbackParameter); - } - } diff --git a/app/src/main/java/app/revanced/integrations/utils/StringTrieSearch.java b/app/src/main/java/app/revanced/integrations/utils/StringTrieSearch.java index 28d960cf..8c7aeeb1 100644 --- a/app/src/main/java/app/revanced/integrations/utils/StringTrieSearch.java +++ b/app/src/main/java/app/revanced/integrations/utils/StringTrieSearch.java @@ -1,10 +1,5 @@ package app.revanced.integrations.utils; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Objects; - /** * Text pattern searching using a prefix tree (trie). */ @@ -25,34 +20,25 @@ public final class StringTrieSearch extends TrieSearch { char getCharValue(String text, int index) { return text.charAt(index); } + @Override + int getTextLength(String text) { + return text.length(); + } + } + + /** + * @return If the pattern is valid to add to this instance. + */ + public static boolean isValidPattern(String pattern) { + for (int i = 0, length = pattern.length(); i < length; i++) { + if (TrieNode.isInvalidRange(pattern.charAt(i))) { + return false; + } + } + return true; } public StringTrieSearch() { super(new StringTrieNode()); } - - @Override - public void addPattern(@NonNull String pattern) { - super.addPattern(pattern, pattern.length(), null); - } - - @Override - public void addPattern(@NonNull String pattern, @NonNull TriePatternMatchedCallback callback) { - super.addPattern(pattern, pattern.length(), Objects.requireNonNull(callback)); - } - - @Override - public boolean matches(@NonNull String textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) { - return super.matches(textToSearch, textToSearch.length(), startIndex, endIndex, callbackParameter); - } - - @Override - public boolean matches(@NonNull String textToSearch, @Nullable Object callbackParameter) { - return matches(textToSearch, 0, textToSearch.length(), callbackParameter); - } - - @Override - public boolean matches(@NonNull String textToSearch, int startIndex) { - return matches(textToSearch, startIndex, textToSearch.length(), null); - } } diff --git a/app/src/main/java/app/revanced/integrations/utils/TrieSearch.java b/app/src/main/java/app/revanced/integrations/utils/TrieSearch.java index d42c305c..437c7916 100644 --- a/app/src/main/java/app/revanced/integrations/utils/TrieSearch.java +++ b/app/src/main/java/app/revanced/integrations/utils/TrieSearch.java @@ -86,7 +86,7 @@ public abstract class TrieSearch { private static final int CHILDREN_ARRAY_INCREASE_SIZE_INCREMENT = 2; private static final int CHILDREN_ARRAY_MAX_SIZE = MAX_VALID_CHAR - MIN_VALID_CHAR + 1; - private static boolean isInvalidRange(char character) { + static boolean isInvalidRange(char character) { return character < MIN_VALID_CHAR || character > MAX_VALID_CHAR; } @@ -227,7 +227,7 @@ public abstract class TrieSearch { } private static int hashIndexForTableSize(int arraySize, char nodeValue) { - return (nodeValue - MIN_VALID_CHAR) % arraySize; + return nodeValue % arraySize; } /** @@ -300,6 +300,7 @@ public abstract class TrieSearch { abstract TrieNode createNode(char nodeValue); abstract char getCharValue(T text, int index); + abstract int getTextLength(T text); } /** @@ -323,6 +324,23 @@ public abstract class TrieSearch { } } + /** + * Adds a pattern that will always return a positive match if found. + * + * @param pattern Pattern to add. Calling this with a zero length pattern does nothing. + */ + public void addPattern(@NonNull T pattern) { + addPattern(pattern, root.getTextLength(pattern), null); + } + + /** + * @param pattern Pattern to add. Calling this with a zero length pattern does nothing. + * @param callback Callback to determine if searching should halt when a match is found. + */ + public void addPattern(@NonNull T pattern, @NonNull TriePatternMatchedCallback callback) { + addPattern(pattern, root.getTextLength(pattern), Objects.requireNonNull(callback)); + } + void addPattern(@NonNull T pattern, int patternLength, @Nullable TriePatternMatchedCallback callback) { if (patternLength == 0) return; // Nothing to match @@ -330,8 +348,38 @@ public abstract class TrieSearch { root.addPattern(pattern, patternLength, 0, callback); } - final boolean matches(@NonNull T textToSearch, int textToSearchLength, int startIndex, int endIndex, - @Nullable Object callbackParameter) { + public final boolean matches(@NonNull T textToSearch) { + return matches(textToSearch, 0); + } + + public boolean matches(@NonNull T textToSearch, @NonNull Object callbackParameter) { + return matches(textToSearch, 0, root.getTextLength(textToSearch), + Objects.requireNonNull(callbackParameter)); + } + + public boolean matches(@NonNull T textToSearch, int startIndex) { + return matches(textToSearch, startIndex, root.getTextLength(textToSearch)); + } + + public final boolean matches(@NonNull T textToSearch, int startIndex, int endIndex) { + return matches(textToSearch, startIndex, endIndex, null); + } + + /** + * Searches through text, looking for any substring that matches any pattern in this tree. + * + * @param textToSearch Text to search through. + * @param startIndex Index to start searching, inclusive value. + * @param endIndex Index to stop matching, exclusive value. + * @param callbackParameter Optional parameter passed to the callbacks. + * @return If any pattern matched, and it's callback halted searching. + */ + public boolean matches(@NonNull T textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter) { + return matches(textToSearch, root.getTextLength(textToSearch), startIndex, endIndex, callbackParameter); + } + + private boolean matches(@NonNull T textToSearch, int textToSearchLength, int startIndex, int endIndex, + @Nullable Object callbackParameter) { if (endIndex > textToSearchLength) { throw new IllegalArgumentException("endIndex: " + endIndex + " is greater than texToSearchLength: " + textToSearchLength); @@ -365,41 +413,4 @@ public abstract class TrieSearch { public List getPatterns() { return Collections.unmodifiableList(patterns); } - - /** - * Adds a pattern that will always return a positive match if found. - * - * @param pattern Pattern to add. Calling this with a zero length pattern does nothing. - */ - public abstract void addPattern(@NonNull T pattern); - - /** - * @param pattern Pattern to add. Calling this with a zero length pattern does nothing. - * @param callback Callback to determine if searching should halt when a match is found. - */ - public abstract void addPattern(@NonNull T pattern, @NonNull TriePatternMatchedCallback callback); - - - /** - * Searches through text, looking for any substring that matches any pattern in this tree. - * - * @param textToSearch Text to search through. - * @param startIndex Index to start searching, inclusive value. - * @param endIndex Index to stop matching, exclusive value. - * @param callbackParameter Optional parameter passed to the callbacks. - * @return If any pattern matched, and it's callback halted searching. - */ - public abstract boolean matches(@NonNull T textToSearch, int startIndex, int endIndex, @Nullable Object callbackParameter); - - public abstract boolean matches(@NonNull T textToSearch, int startIndex); - - public abstract boolean matches(@NonNull T textToSearch, @Nullable Object callbackParameter); - - public final boolean matches(@NonNull T textToSearch, int startIndex, int endIndex) { - return matches(textToSearch, startIndex, endIndex, null); - } - - public final boolean matches(@NonNull T textToSearch) { - return matches(textToSearch, 0); - } }