diff --git a/itou/static/js/gps.js b/itou/static/js/gps.js
index b8e582d743..0c99d937b3 100644
--- a/itou/static/js/gps.js
+++ b/itou/static/js/gps.js
@@ -6,6 +6,20 @@ htmx.onLoad((target) => {
const amdRequire = jQuery.fn.select2.amd.require;
const Translation = amdRequire("select2/translation");
const frTranslations = Translation.loadPath("./i18n/fr");
+ const select2Utils = amdRequire('select2/utils');
+
+ function format_result(data) {
+ if (data.name) {
+ return $(`
+
+
${select2Utils.escapeMarkup(data.title)}
+
${select2Utils.escapeMarkup(data.name)}
+
${data.birthdate}
+
+ `);
+ }
+ return data.text
+ }
searchUserInputField.select2({
placeholder: 'Jean DUPONT',
language: {
@@ -24,6 +38,8 @@ htmx.onLoad((target) => {
ajax: {
delay: 250 // wait 250 milliseconds before triggering the request
},
+ templateResult: format_result,
+ templateSelection: format_result,
});
searchUserInputField.on("select2:select", function (e) {
const submit_button = $("#join_group_form .btn-primary.disabled");
diff --git a/itou/www/autocomplete/views.py b/itou/www/autocomplete/views.py
index a8076b9560..b7def5a1e7 100644
--- a/itou/www/autocomplete/views.py
+++ b/itou/www/autocomplete/views.py
@@ -155,21 +155,19 @@ def gps_users_autocomplete(request):
users_qs = users_qs.filter(full_name_search_vector=search_query)
users_qs = users_qs.annotate(rank=SearchRank("full_name_search_vector", search_query)).order_by("-rank")
- def format_user_name(user):
- res = ""
+ def format_data(user):
+ data = {
+ "title": "",
+ "name": user.get_full_name(),
+ "birthdate": "",
+ }
if user.title:
- res += f"{user.title.capitalize()}. "
- res += user.get_full_name()
+ # only add a . after M, not Mme
+ data["title"] = f"{user.title.capitalize()}."[:3] + " "
if getattr(user.jobseeker_profile, "birthdate", None):
- res += f" ({user.jobseeker_profile.birthdate})"
- return res
+ data["birthdate"] = user.jobseeker_profile.birthdate.strftime("%d/%m/%Y")
+ return data
- users = [
- {
- "text": format_user_name(user),
- "id": user.pk,
- }
- for user in users_qs[:10]
- ]
+ users = [{"id": user.pk} | format_data(user) for user in users_qs[:10]]
return JsonResponse({"results": users})
diff --git a/tests/gps/test_views.py b/tests/gps/test_views.py
index 3e1d90cb5b..5d9760e5ed 100644
--- a/tests/gps/test_views.py
+++ b/tests/gps/test_views.py
@@ -80,6 +80,15 @@ def get_autocomplete_results(user, term="gps"):
assert results == [second_beneficiary.pk]
+def test_user_autocomplete_XSS(client):
+ # The javascript code return a jquery object that will not be escaped, we need to escape the user name
+ # to prevent xss
+ with open("itou/static/js/gps.js") as f:
+ script_content = f.read()
+ assert "${select2Utils.escapeMarkup(data.name)}" in script_content
+ assert "${select2Utils.escapeMarkup(data.title)}" in script_content
+
+
@pytest.mark.parametrize(
"is_referent",
[