Skip to content

Commit 2dd8889

Browse files
committed
Ensure strings rendered into query templates are sql escaped
1 parent 6728701 commit 2dd8889

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

src/trgm_search_service.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from qwc_services_core.database import DatabaseEngine
99
from qwc_services_core.permissions_reader import PermissionsReader
1010
from qwc_services_core.runtime_config import RuntimeConfig
11-
from sqlalchemy.sql import text as sql_text
11+
from sqlalchemy.sql import text as sql_text, literal
1212

1313
from search_resources import SearchResources
1414

@@ -57,6 +57,12 @@ def __init__(self, tenant, logger):
5757
self.layer_query_template = config.get('trgm_layer_query_template')
5858
self.similarity_threshold = config.get('trgm_similarity_threshold', 0.3)
5959

60+
def sql_escape(self, string):
61+
return str(literal(str(string)).compile(
62+
dialect=self.db_engine.db_engine(self.db_url).dialect,
63+
compile_kwargs={"literal_binds": True}
64+
))[1:-1]
65+
6066
def search(self, identity, searchtext, searchfilter, limit):
6167
(filterword, tokens) = self.tokenize(searchtext)
6268
if not tokens:
@@ -65,13 +71,13 @@ def search(self, identity, searchtext, searchfilter, limit):
6571
searchfilter = [self.filterwords.get(filterword)]
6672

6773
# Determine permitted facets and dataproducts
68-
solr_facets = self.resources.solr_facets(identity)
74+
search_facets = self.resources.solr_facets(identity)
6975
permitted_dataproducts = self.resources.dataproducts(identity)
7076
if not searchfilter:
7177
# use all permitted facets if filter is empty
72-
search_facets = list(solr_facets.keys())
78+
search_facets = list(search_facets.keys())
7379
else:
74-
search_facets = [facet for facet in searchfilter if facet in solr_facets]
80+
search_facets = [facet for facet in searchfilter if facet in search_facets]
7581

7682
search_ds = list(filter(lambda facet: facet not in ["foreground", "background"], search_facets))
7783
search_dp = list(filter(lambda facet: facet in ["foreground", "background"], search_facets))
@@ -85,7 +91,9 @@ def search(self, identity, searchtext, searchfilter, limit):
8591
layer_query = self.layer_query
8692
if self.layer_query_template:
8793
layer_query = Template(self.layer_query_template).render(
88-
searchtext=searchtext, words=tokens, facets=search_dp
94+
searchtext=self.sql_escape(searchtext),
95+
words=list(map(self.sql_escape, tokens)),
96+
facets=search_dp
8997
)
9098
self.logger.debug("Generated layer query from template")
9199

@@ -94,7 +102,10 @@ def search(self, identity, searchtext, searchfilter, limit):
94102
# NOTE: facet_search_limit + 1: we limit results to facet_search_limit below, but pass + 1 here to
95103
# be able to detect whether there were actually more results than facet_search_limit
96104
feature_query = Template(self.feature_query_template).render(
97-
searchtext=searchtext, words=tokens, facets=search_ds, facetlimit=self.facet_search_limit + 1
105+
searchtext=self.sql_escape(searchtext),
106+
words=list(map(self.sql_escape, tokens)),
107+
facets=search_ds,
108+
facetlimit=self.facet_search_limit + 1
98109
)
99110
self.logger.debug("Generated feature query from template")
100111

0 commit comments

Comments
 (0)