From 4cc6c476698e7c28e3e49e45006fd4ec10df0b81 Mon Sep 17 00:00:00 2001 From: Galen Charlton Date: Wed, 14 Apr 2021 14:30:39 -0400 Subject: [PATCH] LP#1923225: have search highlighting stored procedure do HTML-escaping This patch builds on the previous work to have the stored procedures that produced highlighted and unhighlighted versions of display attributes HTML-escape the source values, then adjusts the TPAC and Bootstrap templates to avoid double-escaping. Signed-off-by: Galen Charlton --- Open-ILS/src/sql/Pg/300.schema.staged_search.sql | 6 +- .../XXXX.schema.search_highlight_escape_html.sql | 118 +++++++++++++++++++++ .../opac/parts/record/subjects.tt2 | 2 +- .../opac/parts/record/summary.tt2 | 6 +- 4 files changed, 125 insertions(+), 7 deletions(-) create mode 100644 Open-ILS/src/sql/Pg/upgrade/XXXX.schema.search_highlight_escape_html.sql diff --git a/Open-ILS/src/sql/Pg/300.schema.staged_search.sql b/Open-ILS/src/sql/Pg/300.schema.staged_search.sql index 57bc7a4ed7..eba7b96d46 100644 --- a/Open-ILS/src/sql/Pg/300.schema.staged_search.sql +++ b/Open-ILS/src/sql/Pg/300.schema.staged_search.sql @@ -1385,7 +1385,7 @@ BEGIN SELECT de.id, de.source, de.field, - de.value AS value, + evergreen.escape_for_html(de.value) AS value, ts_headline( ts_config::REGCONFIG, evergreen.escape_for_html(de.value), @@ -1462,8 +1462,8 @@ BEGIN SELECT id, source, field, - value, - value AS highlight + evergreen.escape_for_html(value) AS value, + evergreen.escape_for_html(value) AS highlight FROM metabib.display_entry WHERE source = rid AND NOT (field = ANY (seen)); diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.search_highlight_escape_html.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.search_highlight_escape_html.sql new file mode 100644 index 0000000000..14f7788e63 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.search_highlight_escape_html.sql @@ -0,0 +1,118 @@ +BEGIN; + +-- SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +CREATE OR REPLACE FUNCTION search.highlight_display_fields_impl( + rid BIGINT, + tsq TEXT, + field_list INT[] DEFAULT '{}'::INT[], + css_class TEXT DEFAULT 'oils_SH', + hl_all BOOL DEFAULT TRUE, + minwords INT DEFAULT 5, + maxwords INT DEFAULT 25, + shortwords INT DEFAULT 0, + maxfrags INT DEFAULT 0, + delimiter TEXT DEFAULT ' ... ' +) RETURNS SETOF search.highlight_result AS $f$ +DECLARE + opts TEXT := ''; + v_css_class TEXT := css_class; + v_delimiter TEXT := delimiter; + v_field_list INT[] := field_list; + hl_query TEXT; +BEGIN + IF v_delimiter LIKE $$%'%$$ OR v_delimiter LIKE '%"%' THEN --" + v_delimiter := ' ... '; + END IF; + + IF NOT hl_all THEN + opts := opts || 'MinWords=' || minwords; + opts := opts || ', MaxWords=' || maxwords; + opts := opts || ', ShortWords=' || shortwords; + opts := opts || ', MaxFragments=' || maxfrags; + opts := opts || ', FragmentDelimiter="' || delimiter || '"'; + ELSE + opts := opts || 'HighlightAll=TRUE'; + END IF; + + IF v_css_class LIKE $$%'%$$ OR v_css_class LIKE '%"%' THEN -- " + v_css_class := 'oils_SH'; + END IF; + + opts := opts || $$, StopSel=, StartSel=""$xx$ -- "' + ) AS highlight + FROM metabib.display_entry de + JOIN config.metabib_field mf ON (mf.id = de.field) + JOIN search.best_tsconfig t ON (t.id = de.field) + WHERE de.source = $2 + AND field = ANY ($3) + ORDER BY de.id;$$; + + RETURN QUERY EXECUTE hl_query USING opts, rid, v_field_list; +END; +$f$ LANGUAGE PLPGSQL; + +CREATE OR REPLACE FUNCTION search.highlight_display_fields( + rid BIGINT, + tsq_map TEXT, -- { '(a | b) & c' => '1,2,3,4', ...} + css_class TEXT DEFAULT 'oils_SH', + hl_all BOOL DEFAULT TRUE, + minwords INT DEFAULT 5, + maxwords INT DEFAULT 25, + shortwords INT DEFAULT 0, + maxfrags INT DEFAULT 0, + delimiter TEXT DEFAULT ' ... ' +) RETURNS SETOF search.highlight_result AS $f$ +DECLARE + tsq_hstore TEXT; + tsq TEXT; + fields TEXT; + afields INT[]; + seen INT[]; +BEGIN + IF (tsq_map ILIKE 'hstore%') THEN + EXECUTE 'SELECT ' || tsq_map INTO tsq_hstore; + ELSE + tsq_hstore := tsq_map::HSTORE; + END IF; + + FOR tsq, fields IN SELECT key, value FROM each(tsq_hstore::HSTORE) LOOP + SELECT ARRAY_AGG(unnest::INT) INTO afields + FROM unnest(regexp_split_to_array(fields,',')); + seen := seen || afields; + + RETURN QUERY + SELECT * FROM search.highlight_display_fields_impl( + rid, tsq, afields, css_class, hl_all,minwords, + maxwords, shortwords, maxfrags, delimiter + ); + END LOOP; + + RETURN QUERY + SELECT id, + source, + field, + evergreen.escape_for_html(value) AS value, + evergreen.escape_for_html(value) AS highlight + FROM metabib.display_entry + WHERE source = rid + AND NOT (field = ANY (seen)); +END; +$f$ LANGUAGE PLPGSQL ROWS 10; + +COMMIT; diff --git a/Open-ILS/src/templates-bootstrap/opac/parts/record/subjects.tt2 b/Open-ILS/src/templates-bootstrap/opac/parts/record/subjects.tt2 index 9128190245..7f0f58e11f 100755 --- a/Open-ILS/src/templates-bootstrap/opac/parts/record/subjects.tt2 +++ b/Open-ILS/src/templates-bootstrap/opac/parts/record/subjects.tt2 @@ -91,7 +91,7 @@ ''; %][% s.$f | html %] [%- + -%]">[% s.$f %] [%- ''; END; %] diff --git a/Open-ILS/src/templates-bootstrap/opac/parts/record/summary.tt2 b/Open-ILS/src/templates-bootstrap/opac/parts/record/summary.tt2 index ecdeebfa7a..851e3bdde4 100755 --- a/Open-ILS/src/templates-bootstrap/opac/parts/record/summary.tt2 +++ b/Open-ILS/src/templates-bootstrap/opac/parts/record/summary.tt2 @@ -56,7 +56,7 @@ ctx.metalinks.push('
-

[% IF attrs.hl.title; attrs.hl.title | html; ELSE; attrs.title_extended | html; END %]

+

[% IF attrs.hl.title; attrs.hl.title; ELSE; attrs.title_extended | html; END %]

[%- FOR link880 IN attrs.graphic_titles; FOR alt IN link880.graphic; @@ -127,7 +127,7 @@ ctx.metalinks.push(' [%- IF attrs.hl.edition %]
  • [% l("Edition:") %] - [% attrs.hl.edition | html %] + [% attrs.hl.edition %] [%- ELSIF attrs.edition %]
  • [% l("Edition:") %] @@ -152,7 +152,7 @@ ctx.metalinks.push(' [%- IF attrs.hl.publisher %]
  • [% l("Publisher:") %] - [% attrs.hl.publisher | html %] + [% attrs.hl.publisher %]
  • [%- ELSIF attrs.publisher %]
  • -- 2.11.0