FIX: Properly handle quotes and backslash in `Search.set_tsquery_weight_filter`

This commit is contained in:
Guo Xiang Tan 2020-10-19 14:18:04 +08:00 committed by Alan Guo Xiang Tan
parent 500d22bf32
commit 68fc2a18b1
2 changed files with 31 additions and 12 deletions

View File

@ -188,7 +188,7 @@ class Search
if term.present?
@term = Search.prepare_data(term, Topic === @search_context ? :topic : nil)
@original_term = PG::Connection.escape_string(@term)
@original_term = Search.escape_string(@term)
end
if @search_pms || @opts[:type_filter] == 'private_messages'
@ -1100,14 +1100,17 @@ class Search
def self.to_tsquery(ts_config: nil, term:, joiner: nil)
ts_config = ActiveRecord::Base.connection.quote(ts_config) if ts_config
tsquery = "TO_TSQUERY(#{ts_config || default_ts_config}, '#{term}')"
tsquery = "REPLACE(#{tsquery}::text, '&', '#{PG::Connection.escape_string(joiner)}')::tsquery" if joiner
tsquery = "TO_TSQUERY(#{ts_config || default_ts_config}, '#{self.escape_string(term)}')"
tsquery = "REPLACE(#{tsquery}::text, '&', '#{self.escape_string(joiner)}')::tsquery" if joiner
tsquery
end
def self.set_tsquery_weight_filter(term, weight_filter)
term = term.gsub("'", "''")
"''#{PG::Connection.escape_string(term)}'':*#{weight_filter}"
"'#{self.escape_string(term)}':*#{weight_filter}"
end
def self.escape_string(term)
PG::Connection.escape_string(term).gsub('\\', '\\\\\\')
end
def ts_query(ts_config = nil, weight_filter: nil)
@ -1237,7 +1240,7 @@ class Search
def posts_scope(default_scope = Post.all)
if SiteSetting.use_pg_headlines_for_excerpt
search_term = @term.present? ? PG::Connection.escape_string(@term) : nil
search_term = @term.present? ? Search.escape_string(@term) : nil
ts_config = default_ts_config
default_scope

View File

@ -134,12 +134,20 @@ describe Search do
expect(search.term).to eq('a b c okaylength')
end
it 'escapes non alphanumeric characters' do
expect(Search.execute('foo :!$);}]>@\#\"\'').posts.length).to eq(0) # There are at least three levels of sanitation for Search.query!
end
context 'query sanitizaton' do
let!(:post) { Fabricate(:post, raw: 'hello world') }
it "doesn't raise an error when single quotes are present" do
expect(Search.execute("'hello' world").posts.length).to eq(0) # There are at least three levels of sanitation for Search.query!
it 'escapes backslash' do
expect(Search.execute('hello\\').posts).to contain_exactly(post)
end
it 'escapes single quote' do
expect(Search.execute("hello'").posts).to contain_exactly(post)
end
it 'escapes non-alphanumeric characters' do
expect(Search.execute('hello :!$);}]>@\#\"\'').posts).to contain_exactly(post)
end
end
it 'works when given two terms with spaces' do
@ -755,7 +763,7 @@ describe Search do
let(:result) { Search.execute('запись') }
it 'finds something when given cyrillic query' do
expect(result.posts).to be_present
expect(result.posts).to contain_exactly(post)
end
end
@ -1622,6 +1630,14 @@ describe Search do
expect { DB.exec(+"SELECT to_tsvector('bbb') @@ " << ts_query) }.to_not raise_error
expect(ts_query).to include("baz")
end
it 'esacpes the term correctly' do
expect(Search.ts_query(term: 'Title with trailing backslash\\'))
.to eq("TO_TSQUERY('english', '''Title with trailing backslash\\\\\\\\'':*')")
expect(Search.ts_query(term: "Title with trailing quote'"))
.to eq("TO_TSQUERY('english', '''Title with trailing quote'''''':*')")
end
end
context '#word_to_date' do