From fcb58e8a17bb64e7cbd52e57eb6a179520eda1f1 Mon Sep 17 00:00:00 2001 From: GGThed Date: Fri, 7 Aug 2026 21:03:31 -0400 Subject: [PATCH] feat(csp): retirer unsafe-inline de script-src SEC-WEB-001 / OPS-010, ferme. C'est cette directive qui laissait s'executer le XSS stocke de SEC-XSS-001 au lieu de le bloquer. Les cinq derniers gabarits sont migres : match_form 13, calendar 11, teams 11, evaluate_player 9, view_tryout 8. Total sur le chantier : 82 gestionnaires en ligne retires dans 17 gabarits. Il n'en reste aucun. Deux motifs generiques de plus dans main.js data-mirror affichage direct de la valeur d'un curseur. evaluate_player repetait le meme oninput="this.nextElementSibling.textContent = ..." sur ses neuf curseurs de note. data-submit-on-change remplace onchange="this.form.submit()" Markup genere dans des chaines JavaScript match_form construisait sept gestionnaires par concatenation, en y injectant l'identifiant du joueur. Le markup portait deja data-player-id : returnToPool et assignToTeam lisent desormais leurs arguments depuis l'element clique. Cela supprime a la fois l'attribut en ligne et la concatenation qui l'alimentait. Meme motif que dans coach_availability. Bascule CSP_ALLOW_INLINE_SCRIPT passe a false. script-src vaut maintenant 'self' 'nonce-' https://cdn.jsdelivr.net. La variable d'environnement reste, comme issue de secours si un deploiement rencontrait un gestionnaire oublie -- mais la laisser active revient a renoncer a la protection. Le cliquet devient une garde Le budget par gabarit est vide et les tests deviennent absolus : aucun gestionnaire en ligne, et tout bloc {% endblock %} \ No newline at end of file diff --git a/app/templates/pages/evaluate_player.html b/app/templates/pages/evaluate_player.html index b5bedfa..30faae2 100644 --- a/app/templates/pages/evaluate_player.html +++ b/app/templates/pages/evaluate_player.html @@ -32,21 +32,21 @@
- + {{ existing_eval.mecanics_score or 5 }}
- + {{ existing_eval.cohesion_score or 5 }}
- + {{ existing_eval.communication_score or 5 }}
@@ -56,21 +56,21 @@
- + {{ existing_eval.gamesense_score or 5 }}
- + {{ existing_eval.versatility_score or 5 }}
- + {{ existing_eval.discipline_score or 5 }}
@@ -80,21 +80,21 @@
- + {{ existing_eval.analysis_score or 5 }}
- + {{ existing_eval.sport_ethics_score or 5 }}
- + {{ existing_eval.mental_score or 5 }}
diff --git a/app/templates/pages/match_form.html b/app/templates/pages/match_form.html index 7b5074e..30ebb5d 100644 --- a/app/templates/pages/match_form.html +++ b/app/templates/pages/match_form.html @@ -32,7 +32,7 @@ {% if not match %}
- @@ -77,7 +77,7 @@

Select Match Time

Click time slots consecutively to set match duration. Players available in all selected time blocks are shown below.

-
@@ -154,7 +154,7 @@ {{ '✅ Confirmed' if pdata.attendance_confirmed else '⏳ Pending' }} @@ -180,7 +180,7 @@ {{ '✅ Confirmed' if pdata.attendance_confirmed else '⏳ Pending' }} @@ -204,10 +204,10 @@
- + vs 0 -
@@ -554,7 +554,7 @@ document.addEventListener('DOMContentLoaded', function() { var teamDiv = document.getElementById('team1-selection'); var playerName = playerDataById.player_data[pid]; if (playerName) { - var html = '
'; + var html = '
'; html += playerName; html += ''; html += '
'; @@ -567,7 +567,7 @@ document.addEventListener('DOMContentLoaded', function() { var teamDiv = document.getElementById('team2-selection'); var playerName = playerDataById.player_data[pid]; if (playerName) { - var html = '
'; + var html = '
'; html += playerName; html += ''; html += '
'; @@ -922,8 +922,8 @@ function updatePlayerPool() { html += '
'; html += '' + playerName + ''; html += '
'; - html += ''; - html += ''; + html += ''; + html += ''; html += '
'; html += '
'; }); @@ -942,7 +942,7 @@ function assignToTeam(playerId, teamSide) { var playerName = playerDataById.player_data[playerId]; if (!playerName) return; - var html = '
'; + var html = '
'; html += playerName; html += ''; html += '
'; @@ -952,8 +952,12 @@ function assignToTeam(playerId, teamSide) { updatePlayerPool(); } -function returnToPool(playerId, event) { +function returnToPool(element, event) { + // The clicked element already carries data-player-id: the generated + // markup sets it, so the value no longer has to be baked into an + // onclick attribute. if (event) event.stopPropagation(); + var playerId = element.getAttribute('data-player-id'); document.querySelectorAll('[data-player-id="' + playerId + '"]').forEach(function(el) { el.remove(); }); @@ -1057,7 +1061,7 @@ function randomizeTeams() { var teamDiv = document.getElementById('team1-selection'); var playerName = playerDataById.player_data[pid]; if (playerName) { - var html = '
'; + var html = '
'; html += playerName; html += ''; html += '
'; @@ -1069,7 +1073,7 @@ function randomizeTeams() { var teamDiv = document.getElementById('team2-selection'); var playerName = playerDataById.player_data[pid]; if (playerName) { - var html = '
'; + var html = '
'; html += playerName; html += ''; html += '
'; @@ -1110,5 +1114,27 @@ function togglePresence(matchId, participantId, badgeEl) { console.error('Error toggling presence:', error); }); } + +// Behaviours declared in the markup, dispatched by the delegated listener +// in main.js. Inline onclick attributes cannot be authorised by a CSP nonce. +registerActions({ + 'toggle-match-type': toggleMatchType, + 'clear-time-selection': clearTimeSelection, + 'update-randomize-preview': updateRandomizePreview, + 'randomize-teams': randomizeTeams, + 'return-to-pool': returnToPool, + 'assign-team': function (element) { + var item = element.closest('[data-player-id]'); + if (item) { + assignToTeam(item.getAttribute('data-player-id'), + element.getAttribute('data-team-side')); + } + }, + 'toggle-presence': function (element) { + togglePresence(element.getAttribute('data-match-id'), + element.getAttribute('data-participant-id'), + element); + }, +}); {% endblock %} diff --git a/app/templates/pages/one_on_one.html b/app/templates/pages/one_on_one.html index 5b58f3d..ba8b98e 100644 --- a/app/templates/pages/one_on_one.html +++ b/app/templates/pages/one_on_one.html @@ -170,7 +170,7 @@ {% if coach %} - {% endif %} diff --git a/app/templates/pages/teams.html b/app/templates/pages/teams.html index efdbe1a..682d2e6 100644 --- a/app/templates/pages/teams.html +++ b/app/templates/pages/teams.html @@ -5,7 +5,7 @@ {% block header_actions %} {% if can_manage %} - {% endif %} @@ -45,7 +45,7 @@
- +
@@ -63,7 +63,7 @@ -
+ @@ -111,7 +111,7 @@ {{ m.username }} {% if can_manage %} - + @@ -166,7 +166,7 @@ {% else %} @@ -180,7 +180,7 @@ {{ entry.player.phone or '-' }} {% if can_manage_team %} - + + {% else %}

There are no teams to display.

{% endif %} @@ -251,11 +251,11 @@