From a58f564d1e1554f813e0e6ad31fd0eec0ebc1218 Mon Sep 17 00:00:00 2001 From: Alan Evans Date: Fri, 9 Aug 2019 12:49:57 -0400 Subject: [PATCH] Escape string within Full Text Search. Fixes #8975 --- .../securesms/database/SearchDatabase.java | 48 ++++++++++++------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/org/thoughtcrime/securesms/database/SearchDatabase.java b/src/org/thoughtcrime/securesms/database/SearchDatabase.java index 0c3cc4ce23..329f4d8cfd 100644 --- a/src/org/thoughtcrime/securesms/database/SearchDatabase.java +++ b/src/org/thoughtcrime/securesms/database/SearchDatabase.java @@ -1,6 +1,8 @@ package org.thoughtcrime.securesms.database; import android.content.Context; +import android.text.TextUtils; + import androidx.annotation.NonNull; import com.annimon.stream.Stream; @@ -9,9 +11,6 @@ import net.sqlcipher.Cursor; import net.sqlcipher.database.SQLiteDatabase; import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; -import org.thoughtcrime.securesms.util.Util; - -import java.util.List; /** * Contains all databases necessary for full-text search (FTS). @@ -112,31 +111,48 @@ public class SearchDatabase extends Database { } public Cursor queryMessages(@NonNull String query) { - SQLiteDatabase db = databaseHelper.getReadableDatabase(); - String prefixQuery = adjustQuery(query); + SQLiteDatabase db = databaseHelper.getReadableDatabase(); + String fullTextSearchQuery = createFullTextSearchQuery(query); + + if (TextUtils.isEmpty(fullTextSearchQuery)) { + return null; + } + + Cursor cursor = db.rawQuery(MESSAGES_QUERY, new String[] { fullTextSearchQuery, + fullTextSearchQuery }); - Cursor cursor = db.rawQuery(MESSAGES_QUERY, new String[] { prefixQuery, prefixQuery }); setNotifyConverationListListeners(cursor); return cursor; } public Cursor queryMessages(@NonNull String query, long threadId) { - SQLiteDatabase db = databaseHelper.getReadableDatabase(); - String prefixQuery = adjustQuery(query); + SQLiteDatabase db = databaseHelper.getReadableDatabase(); + String fullTextSearchQuery = createFullTextSearchQuery(query); + + if (TextUtils.isEmpty(fullTextSearchQuery)) { + return null; + } + + Cursor cursor = db.rawQuery(MESSAGES_FOR_THREAD_QUERY, new String[] { fullTextSearchQuery, + String.valueOf(threadId), + fullTextSearchQuery, + String.valueOf(threadId) }); - Cursor cursor = db.rawQuery(MESSAGES_FOR_THREAD_QUERY, new String[] { prefixQuery, String.valueOf(threadId), prefixQuery, String.valueOf(threadId) }); setNotifyConverationListListeners(cursor); return cursor; - } - private String adjustQuery(@NonNull String query) { - List tokens = Stream.of(query.split(" ")).filter(s -> s.trim().length() > 0).toList(); - String prefixQuery = Util.join(tokens, "* "); + private static String createFullTextSearchQuery(@NonNull String query) { + return Stream.of(query.split(" ")) + .map(String::trim) + .filter(s -> s.length() > 0) + .map(SearchDatabase::fullTextSearchEscape) + .collect(StringBuilder::new, (sb, s) -> sb.append(s).append("* ")) + .toString(); + } - prefixQuery += "*"; - - return prefixQuery; + private static String fullTextSearchEscape(String s) { + return "\"" + s.replace("\"", "\"\"") + "\""; } }