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", [