From 28436a604a65081f81ae8abfe0fc068e9d24f29c Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Tue, 9 Aug 2016 14:48:39 -0400 Subject: [PATCH] FIX: Prevent tricking the search from ignoring minimum lengths --- .../javascripts/discourse/lib/search.js.es6 | 10 +++---- lib/search.rb | 20 ++++++++++++-- spec/components/search_spec.rb | 27 +++++++++++++++++-- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/discourse/lib/search.js.es6 b/app/assets/javascripts/discourse/lib/search.js.es6 index 348fe0f191b..0598515b222 100644 --- a/app/assets/javascripts/discourse/lib/search.js.es6 +++ b/app/assets/javascripts/discourse/lib/search.js.es6 @@ -70,7 +70,7 @@ export function translateResults(results, opts) { return noResults ? null : Em.Object.create(results); } -function searchForTerm(term, opts) { +export function searchForTerm(term, opts) { if (!opts) opts = {}; // Only include the data we have @@ -94,7 +94,7 @@ function searchForTerm(term, opts) { return promise; } -const searchContextDescription = function(type, name){ +export function searchContextDescription(type, name) { if (type) { switch(type) { case 'topic': @@ -109,17 +109,15 @@ const searchContextDescription = function(type, name){ } }; -const getSearchKey = function(args){ +export function getSearchKey(args) { return args.q + "|" + ((args.searchContext && args.searchContext.type) || "") + "|" + ((args.searchContext && args.searchContext.id) || ""); }; -const isValidSearchTerm = function(searchTerm) { +export function isValidSearchTerm(searchTerm) { if (searchTerm) { return searchTerm.trim().length >= Discourse.SiteSettings.min_search_term_length; } else { return false; } }; - -export { searchForTerm, searchContextDescription, getSearchKey, isValidSearchTerm }; diff --git a/lib/search.rb b/lib/search.rb index 84b29700b90..38024cfcde4 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -128,6 +128,8 @@ class Search end end + attr_accessor :term + def initialize(term, opts=nil) @opts = opts || {} @guardian = @opts[:guardian] || Guardian.new @@ -135,6 +137,7 @@ class Search @include_blurbs = @opts[:include_blurbs] || false @blurb_length = @opts[:blurb_length] @limit = Search.per_facet + @valid = true term = process_advanced_search!(term) @@ -155,14 +158,27 @@ class Search @results = GroupedSearchResults.new(@opts[:type_filter], term, @search_context, @include_blurbs, @blurb_length) end + def valid? + @valid + end + def self.execute(term, opts=nil) self.new(term, opts).execute end # Query a term def execute - if @term.blank? || @term.length < (@opts[:min_search_term_length] || SiteSetting.min_search_term_length) - return nil unless @filters.present? + + unless @filters.present? + min_length = @opts[:min_search_term_length] || SiteSetting.min_search_term_length + terms = (@term || '').split(/\s(?=(?:[^"]|"[^"]*")*$)/).reject {|t| t.length < min_length } + + if terms.blank? + @term = '' + @valid = false + return + end + @term = terms.join(' ') end # If the term is a number or url to a topic, just include that topic diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index 91a88719f56..f7dac716706 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -61,8 +61,31 @@ describe Search do end it 'does not search when the search term is too small' do - ActiveRecord::Base.expects(:exec_sql).never - Search.execute('evil', min_search_term_length: 5) + search = Search.new('evil', min_search_term_length: 5) + search.execute + expect(search.valid?).to eq(false) + expect(search.term).to eq('') + end + + it 'does not search for multiple small terms' do + search = Search.new('a b c d', min_search_term_length: 5) + search.execute + expect(search.valid?).to eq(false) + expect(search.term).to eq('') + end + + it 'searches for quoted short terms' do + search = Search.new('"a b c d"', min_search_term_length: 5) + search.execute + expect(search.valid?).to eq(true) + expect(search.term).to eq('"a b c d"') + end + + it 'discards short terms' do + search = Search.new('a b c okaylength', min_search_term_length: 5) + search.execute + expect(search.valid?).to eq(true) + expect(search.term).to eq('okaylength') end it 'escapes non alphanumeric characters' do