Escape HTML everywhere where html_safe is used (#1114)

* Escape HTML everywhere where html_safe is used
* Mark search results as HTML safe at the attribute
This commit is contained in:
Stanko Krtalić
2025-09-16 11:52:15 +02:00
committed by GitHub
parent 80de91417d
commit 0e2c7f7d4d
6 changed files with 46 additions and 22 deletions
+16 -16
View File
@@ -30,9 +30,9 @@ module EventsHelper
def event_column_title(base_title, count, day)
date_tag = local_datetime_tag day, style: :agoorweekday
if count > 0
"#{base_title} #{date_tag} <span class='font-weight-normal'>(#{count})</span>".html_safe
"#{h base_title} #{date_tag} <span class='font-weight-normal'>(#{h count})</span>".html_safe
else
"#{base_title} #{date_tag}".html_safe
"#{h base_title} #{date_tag}".html_safe
end
end
@@ -72,7 +72,7 @@ module EventsHelper
end
def comment_event_action_sentence(event)
"#{ event_creator_name(event) } commented on <span style='color: var(--card-color)'>#{ event.eventable.card.title }</span>".html_safe
"#{h event_creator_name(event) } commented on <span style='color: var(--card-color)'>#{h event.eventable.card.title }</span>".html_safe
end
def event_creator_name(event)
@@ -86,32 +86,32 @@ module EventsHelper
case event.action
when "card_assigned"
if event.assignees.include?(Current.user)
"#{ event_creator_name(event) } will handle <span style='color: var(--card-color)'>#{ title }</span>".html_safe
"#{h event_creator_name(event) } will handle <span style='color: var(--card-color)'>#{h title }</span>".html_safe
else
"#{ event_creator_name(event) } assigned #{ event.assignees.pluck(:name).to_sentence } to <span style='color: var(--card-color)'>#{ title }</span>".html_safe
"#{h event_creator_name(event) } assigned #{h event.assignees.pluck(:name).to_sentence } to <span style='color: var(--card-color)'>#{h title }</span>".html_safe
end
when "card_unassigned"
"#{ event_creator_name(event) } unassigned #{ event.assignees.include?(Current.user) ? "yourself" : event.assignees.pluck(:name).to_sentence } from <span style='color: var(--card-color)'>#{ title }</span>".html_safe
"#{h event_creator_name(event) } unassigned #{ h(event.assignees.include?(Current.user) ? "yourself" : event.assignees.pluck(:name).to_sentence) } from <span style='color: var(--card-color)'>#{h title }</span>".html_safe
when "card_published"
"#{ event_creator_name(event) } added <span style='color: var(--card-color)'>#{ title }</span>".html_safe
"#{h event_creator_name(event) } added <span style='color: var(--card-color)'>#{h title }</span>".html_safe
when "card_closed"
"#{ event_creator_name(event) } closed <span style='color: var(--card-color)'>#{ title }</span>".html_safe
"#{h event_creator_name(event) } closed <span style='color: var(--card-color)'>#{h title }</span>".html_safe
when "card_reopened"
"#{ event_creator_name(event) } reopened <span style='color: var(--card-color)'>#{ title }</span>".html_safe
"#{h event_creator_name(event) } reopened <span style='color: var(--card-color)'>#{h title }</span>".html_safe
when "card_staged"
"#{event_creator_name(event)} moved <span style='color: var(--card-color)'>#{ title }</span> to the #{event.stage_name} stage".html_safe
"#{h event_creator_name(event)} moved <span style='color: var(--card-color)'>#{h title }</span> to the #{h event.stage_name} stage".html_safe
when "card_unstaged"
"#{event_creator_name(event)} moved <span style='color: var(--card-color)'>#{ title }</span> out ofthe #{event.stage_name} stage".html_safe
"#{h event_creator_name(event)} moved <span style='color: var(--card-color)'>#{h title }</span> out ofthe #{h event.stage_name} stage".html_safe
when "card_due_date_added"
"#{event_creator_name(event)} set the date to #{event.particulars.dig('particulars', 'due_date').to_date.strftime('%B %-d')} on <span style='color: var(--card-color)'>#{ title }</span>".html_safe
"#{h event_creator_name(event)} set the date to #{h event.particulars.dig('particulars', 'due_date').to_date.strftime('%B %-d')} on <span style='color: var(--card-color)'>#{h title }</span>".html_safe
when "card_due_date_changed"
"#{event_creator_name(event)} changed the date to #{event.particulars.dig('particulars', 'due_date').to_date.strftime('%B %-d')} on <span style='color: var(--card-color)'>#{ title }</span>".html_safe
"#{h event_creator_name(event)} changed the date to #{h event.particulars.dig('particulars', 'due_date').to_date.strftime('%B %-d')} on <span style='color: var(--card-color)'>#{h title }</span>".html_safe
when "card_due_date_removed"
"#{event_creator_name(event)} removed the date on <span style='color: var(--card-color)'>#{ title }</span>"
"#{h event_creator_name(event)} removed the date on <span style='color: var(--card-color)'>#{h title }</span>".html_safe
when "card_title_changed"
"#{event_creator_name(event)} renamed <span style='color: var(--card-color)'>#{ title }</span> (was: '#{event.particulars.dig('particulars', 'old_title')})'".html_safe
"#{h event_creator_name(event)} renamed <span style='color: var(--card-color)'>#{h title }</span> (was: '#{h event.particulars.dig('particulars', 'old_title')})'".html_safe
when "card_collection_changed"
"#{event_creator_name(event)} moved <span style='color: var(--card-color)'>#{ title }</span> to '#{event.particulars.dig('particulars', 'new_collection')}'".html_safe
"#{h event_creator_name(event)} moved <span style='color: var(--card-color)'>#{h title }</span> to '#{h event.particulars.dig('particulars', 'new_collection')}'".html_safe
end
end
+24
View File
@@ -3,6 +3,18 @@ class Search::Result < ApplicationRecord
belongs_to :card, foreign_key: :card_id, optional: true
belongs_to :comment, foreign_key: :comment_id, optional: true
def card_title
escape_highlight card_title_in_database
end
def card_description
escape_highlight card_description_in_database
end
def comment_body
escape_highlight comment_body_in_database
end
def source
comment_id.present? ? comment : card
end
@@ -10,4 +22,16 @@ class Search::Result < ApplicationRecord
def readonly?
true
end
private
def escape_highlight(html)
if html
CGI.escapeHTML(html)
.gsub(CGI.escapeHTML(Search::HIGHLIGHT_OPENING_MARK), Search::HIGHLIGHT_OPENING_MARK.html_safe)
.gsub(CGI.escapeHTML(Search::HIGHLIGHT_CLOSING_MARK), Search::HIGHLIGHT_CLOSING_MARK.html_safe)
.html_safe
else
nil
end
end
end
@@ -27,7 +27,7 @@
<span class="card__meta-text card__meta-text--assignees overflow-ellipsis">
<%= icon_tag "arrow-right" if card.assignees.any? %>
<%= card.assignees.any? ? "Assigned to" : "Not assigned" %>
<%= card.assignees.map { |assignee| "<strong>#{assignee.familiar_name}</strong>" }.to_sentence.html_safe %>
<%= card.assignees.map { |assignee| "<strong>#{h assignee.familiar_name}</strong>" }.to_sentence.html_safe %>
</span>
<div class="card__meta-avatars card__meta-avatars--assignees">
@@ -19,7 +19,7 @@
<span class="card__meta-text card__meta-text--assignees overflow-ellipsis">
<%= icon_tag "arrow-right" if card.assignees.any? %>
<%= card.assignees.map { |assignee| assignee.familiar_name }.to_sentence(two_words_connector: " / ", last_word_connector: " / ").html_safe %>
<%= card.assignees.map { |assignee| h assignee.familiar_name }.to_sentence(two_words_connector: " / ", last_word_connector: " / ").html_safe %>
</span>
<div class="card__meta-avatars card__meta-avatars--assignees">
@@ -21,7 +21,7 @@
<span class="card__meta-text card__meta-text--assignees overflow-ellipsis">
<%= "Assigned to" if card.assignees.any? %>
<%= card.assignees.map { |assignee| "<strong>#{assignee.familiar_name}</strong>" }.to_sentence.html_safe %>
<%= card.assignees.map { |assignee| "<strong>#{h assignee.familiar_name}</strong>" }.to_sentence.html_safe %>
</span>
<div class="card__meta-avatars card__meta-avatars--assignees" id="<%= dom_id(card, :assignees) %>">
+3 -3
View File
@@ -2,19 +2,19 @@
<%= link_to result.source, class: "search__result", data: { turbo_frame: "_top" } do %>
<div>
<h3 class="search__title txt--medium margin-none">
# <%= result.card_id %> <%= result.card_title&.html_safe %>
# <%= result.card_id %> <%= result.card_title %>
</h3>
<% if result.card_description.present? %>
<div class="search__excerpt">
<%= result.card_description.html_safe %>
<%= result.card_description %>
</div>
<% else
if result.comment_body.present? %>
<div class="search__excerpt search__excerpt--comment">
<%= avatar_preview_tag result.creator %>
<div>
<%= result.comment_body.html_safe %>
<%= result.comment_body %>
</div>
</div>
<% end %>