Skip to content

Commit 8b720c8

Browse files
authored
Merge pull request #137 from dtinit/sanitize-html-clickable-links-feedback
Sanitize html clickable links feedback
2 parents c6e017e + 22e8fc2 commit 8b720c8

2 files changed

Lines changed: 48 additions & 9 deletions

File tree

portmap/core/views.py

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from functools import wraps
2+
import re
23
import json
4+
import bleach
35
import markdown2
46
import pycmarkgfm
57
from allauth.account.views import LoginView as AllAuthLoginView
@@ -183,27 +185,63 @@ def find_articles(request):
183185
form = QueryIndexForm(data=None, datatypes=datatypes)
184186
return TemplateResponse(request, "core/index.html", {'form': form, 'datatypes': datatypes})
185187

188+
def break_url(url_text):
189+
"""
190+
Break down URLs into segments to avoid linkification
191+
and then wrap them in double quotes.
192+
193+
Examples:
194+
"http://example.com" -> "http:// example .com"
195+
"example.com" -> "example .com"
196+
197+
The pattern captures:
198+
1. Optional protocol (http:// or https://)
199+
2. Followed by a domain name (including letters, digits, dots, hyphens)
200+
3. A period, and one of the listed TLDs
201+
4. Followed by zero or more non-space characters (e.g., /path)
202+
"""
203+
pattern = r'((https?:\/\/)?[A-Za-z0-9.-]+\.(?:com|net|org|io|gov|edu)\b\S*)'
204+
205+
def replacer(match):
206+
original_url = match.group(1)
207+
# Insert a space after protocol (if present)
208+
spaced_protocol = re.sub(r'(https?:\/\/)', r'\1 ', original_url)
209+
# Insert a space before the TLD
210+
space_tld = re.sub(r'\.(com|net|org|io|gov|edu)', r' .\1', spaced_protocol)
211+
# Wrap result in double quotes
212+
return f'"{space_tld}"'
213+
214+
# Replace all occurences of the pattern with the split/wrapped version
215+
return re.sub(pattern, replacer, url_text)
216+
186217

187218
@ux_requires_post
188219
def article_feedback(request, article_name):
189220
form = ArticleFeedbackForm(data=request.POST)
190-
Feedback.objects.create(article=Article.objects.get(name=article_name),
191-
reaction=form.data['reaction'],
192-
explanation=form.data['explanation'])
193-
message = "*New article feedback for \"" + article_name + "\"*:\n\nReaction: " + form.data['reaction'] + "\n\n" + form.data['explanation']
194-
notify(message)
221+
if form.is_valid():
222+
# Sanitize for database storage
223+
sanitized_explanation = bleach.clean(form.cleaned_data['explanation'], tags=[], attributes={}, strip=True)
224+
Feedback.objects.create(article=Article.objects.get(name=article_name),
225+
reaction=form.cleaned_data['reaction'],
226+
explanation=sanitized_explanation)
227+
message = f"*Article feedback for \"{article_name}\"*:\n\nReaction: {form.cleaned_data['reaction']}"
228+
notify(message)
195229
referer = request.META.get('HTTP_REFERER', '/')
196230
return TemplateResponse(request, "core/thankyou.html", {'referer': referer})
197231

198232

199233
@ux_requires_post
200234
def usecase_feedback(request):
201-
feedback = UseCaseFeedbackForm(data=request.POST);
235+
feedback = UseCaseFeedbackForm(data=request.POST)
202236
if feedback.is_valid():
237+
# Sanitize for database storage
238+
sanitized_explanation = bleach.clean(feedback.cleaned_data['explanation'], tags=[], attributes={}, strip=True)
239+
feedback.instance.explanation = sanitized_explanation
203240
feedback.save()
204-
message = "*New use case feedback:*\n\n" + feedback.data['explanation']
241+
# Break URLs into segments and wrap in double quotes
242+
safe_for_slack = break_url(sanitized_explanation)
243+
message = f"*New use case feedback:*\n\n{safe_for_slack}"
205244
notify(message)
206-
207245
referer = request.META.get('HTTP_REFERER', '/')
208246
return TemplateResponse(request, "core/thankyou.html", {'referer': referer})
209247

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ pytest-django==4.7.0
1919
django-environ==0.11.2
2020
pytest-playwright==0.4.4
2121
pycmarkgfm==1.2.1
22-
markdown2==2.4.13
22+
markdown2==2.4.13
23+
bleach==6.2.0

0 commit comments

Comments
 (0)