Skip to content

Commit

Permalink
fix(surveys): Update html preview for rating and mcq surveys (#18180)
Browse files Browse the repository at this point in the history
  • Loading branch information
neilkakkar authored Oct 26, 2023
1 parent 1d375c0 commit 4c0a619
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 8 deletions.
12 changes: 8 additions & 4 deletions frontend/src/scenes/surveys/SurveyAppearance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -490,8 +490,10 @@ export function SurveyRatingAppearance({
</button>
</div>
)}
<div className="survey-question">{question}</div>
{description && <div className="description">{description}</div>}
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitize(question) }} />
{description && (
<div className="description" dangerouslySetInnerHTML={{ __html: sanitize(description) }} />
)}
<div className="rating-section">
<div className="rating-options">
{ratingSurveyQuestion.display === 'emoji' && (
Expand Down Expand Up @@ -588,8 +590,10 @@ export function SurveyMultipleChoiceAppearance({
</button>
</div>
)}
<div className="survey-question">{question}</div>
{description && <div className="description">{description}</div>}
<div className="survey-question" dangerouslySetInnerHTML={{ __html: sanitize(question) }} />
{description && (
<div className="description" dangerouslySetInnerHTML={{ __html: sanitize(description) }} />
)}
<div className="multiple-choice-options">
{(multipleChoiceQuestion.choices || []).map((choice, idx) => (
<div className="choice-option" key={idx}>
Expand Down
147 changes: 143 additions & 4 deletions posthog/api/survey.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ def validate_appearance(self, value):

thank_you_message = value.get("thankYouMessageHeader")
if thank_you_message and nh3.is_html(thank_you_message):
value["thankYouMessageHeader"] = nh3.clean(thank_you_message)
value["thankYouMessageHeader"] = nh3_clean_with_whitelist(thank_you_message)

thank_you_description = value.get("thankYouMessageDescription")
if thank_you_description and nh3.is_html(thank_you_description):
value["thankYouMessageDescription"] = nh3.clean(thank_you_description)
value["thankYouMessageDescription"] = nh3_clean_with_whitelist(thank_you_description)

return value

Expand All @@ -128,9 +128,9 @@ def validate_questions(self, value):

description = raw_question.get("description")
if nh3.is_html(question_text):
cleaned_question["question"] = nh3.clean(question_text)
cleaned_question["question"] = nh3_clean_with_whitelist(question_text)
if description and nh3.is_html(description):
cleaned_question["description"] = nh3.clean(description)
cleaned_question["description"] = nh3_clean_with_whitelist(description)

cleaned_questions.append(cleaned_question)

Expand Down Expand Up @@ -342,3 +342,142 @@ def surveys(request: Request):
).data

return cors_response(request, JsonResponse({"surveys": surveys}))


def nh3_clean_with_whitelist(to_clean: str):

return nh3.clean(
to_clean,
link_rel="noopener",
tags={
"a",
"abbr",
"acronym",
"area",
"article",
"aside",
"b",
"bdi",
"bdo",
"blockquote",
"br",
"caption",
"center",
"cite",
"code",
"col",
"colgroup",
"data",
"dd",
"del",
"details",
"dfn",
"div",
"dl",
"dt",
"em",
"figcaption",
"figure",
"footer",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"header",
"hgroup",
"hr",
"i",
"img",
"ins",
"kbd",
"kbd",
"li",
"map",
"mark",
"nav",
"ol",
"p",
"pre",
"q",
"rp",
"rt",
"rtc",
"ruby",
"s",
"samp",
"small",
"span",
"strike",
"strong",
"sub",
"summary",
"sup",
"table",
"tbody",
"td",
"th",
"thead",
"time",
"tr",
"tt",
"u",
"ul",
"var",
"wbr",
},
attributes={
"*": {"style", "lang", "title", "width", "height"},
# below are mostly defaults to ammonia, but we need to add them explicitly
# because this python binding doesn't allow additive whitelisting
"a": {"href", "hreflang"},
"bdo": {"dir"},
"blockquote": {"cite"},
"col": {"align", "char", "charoff", "span"},
"colgroup": {"align", "char", "charoff", "span"},
"del": {"cite", "datetime"},
"hr": {"align", "size", "width"},
"img": {"align", "alt", "height", "src", "width"},
"ins": {"cite", "datetime"},
"ol": {"start", "type"},
"q": {"cite"},
"table": {"align", "bgcolor", "border", "cellpadding", "cellspacing", "frame", "rules", "summary", "width"},
"tbody": {"align", "char", "charoff", "valign"},
"td": {
"abbr",
"align",
"axis",
"bgcolor",
"char",
"charoff",
"colspan",
"headers",
"height",
"nowrap",
"rowspan",
"scope",
"valign",
"width",
},
"tfoot": {"align", "char", "charoff", "valign"},
"th": {
"abbr",
"align",
"axis",
"bgcolor",
"char",
"charoff",
"colspan",
"headers",
"height",
"nowrap",
"rowspan",
"scope",
"valign",
"width",
},
"thead": {"align", "char", "charoff", "valign"},
"tr": {"align", "bgcolor", "char", "charoff", "valign"},
},
)
32 changes: 32 additions & 0 deletions posthog/api/test/test_survey.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from datetime import datetime, timedelta

from unittest.mock import ANY
import pytest

from rest_framework import status
from django.core.cache import cache
from django.test.client import Client
from posthog.api.survey import nh3_clean_with_whitelist

from posthog.models.feedback.survey import Survey
from posthog.test.base import (
Expand Down Expand Up @@ -1069,3 +1071,33 @@ def test_responses_count_zero_responses(self):

data = response.json()
self.assertEqual(data, {})


@pytest.mark.parametrize(
"test_input,expected",
[
(
"""
<div style="display: flex; justify-content: center;">
<div style="flex: 1;">
<img src="https://www.gardenhealth.com/wp-content/uploads/2019/09/hedgehog_octobergardeningjobs-768x768.webp" alt="Your Image" style="max-width: 100%; height: auto; opacity: 1;">
</div>
<div style="flex: 3; padding:10px;">
<p>Help us stay sharp.</p>
</div>
""",
"""
<div style="display: flex; justify-content: center;">
<div style="flex: 1;">
<img src="https://www.gardenhealth.com/wp-content/uploads/2019/09/hedgehog_octobergardeningjobs-768x768.webp" alt="Your Image" style="max-width: 100%; height: auto; opacity: 1;">
</div>
<div style="flex: 3; padding:10px;">
<p>Help us stay sharp.</p>
</div>
</div>""",
),
(""" """, """ """),
],
)
def test_nh3_clean_configuration(test_input, expected):
assert nh3_clean_with_whitelist(test_input).replace(" ", "") == expected.replace(" ", "")

0 comments on commit 4c0a619

Please sign in to comment.