diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-18 16:30:31 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-18 16:30:31 +0200 |
| commit | 0c6783816e0a7a8acad922296d3eb8cc454fb981 (patch) | |
| tree | 54c59e86afa188de6429ff0e1f07d1b6e4f36350 /app | |
| parent | 6b6e50909cc77de1797e88be5445c5b643b008a9 (diff) | |
Emit a report-only Content-Security-Policy with nonced inline scripts
- dark-mode restore now travels nonced, the admin constants likewise
- AUTH_TOKEN deleted in favour of the csrf meta tag
- new report collector at /csp_reports
Diffstat (limited to 'app')
| -rw-r--r-- | app/controllers/csp_reports_controller.rb | 10 | ||||
| -rw-r--r-- | app/views/layouts/admin.html.erb | 5 | ||||
| -rw-r--r-- | app/views/layouts/application.html.erb | 10 |
3 files changed, 17 insertions, 8 deletions
diff --git a/app/controllers/csp_reports_controller.rb b/app/controllers/csp_reports_controller.rb new file mode 100644 index 0000000..08cbc98 --- /dev/null +++ b/app/controllers/csp_reports_controller.rb | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | class CspReportsController < ApplicationController | ||
| 2 | # Browsers POST application/csp-report with no CSRF token, no session. | ||
| 3 | skip_before_action :verify_authenticity_token | ||
| 4 | |||
| 5 | def create | ||
| 6 | report = request.body.read(8192) | ||
| 7 | Rails.logger.warn("CSP violation: #{report}") if report.present? | ||
| 8 | head :no_content | ||
| 9 | end | ||
| 10 | end | ||
diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb index 0856a0f..e220beb 100644 --- a/app/views/layouts/admin.html.erb +++ b/app/views/layouts/admin.html.erb | |||
| @@ -7,19 +7,18 @@ | |||
| 7 | <%= csrf_meta_tags %> | 7 | <%= csrf_meta_tags %> |
| 8 | 8 | ||
| 9 | <title><%= "#{params[:controller]} | #{params[:action]}" %></title> | 9 | <title><%= "#{params[:controller]} | #{params[:action]}" %></title> |
| 10 | <%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? %> | ||
| 11 | <%= javascript_include_tag 'admin_bundle' %> | 10 | <%= javascript_include_tag 'admin_bundle' %> |
| 12 | <%= tinymce_assets %> | 11 | <%= tinymce_assets %> |
| 13 | <link rel="stylesheet" href="<%= mtime_busted_path('/stylesheets/admin.css') %>"> | 12 | <link rel="stylesheet" href="<%= mtime_busted_path('/stylesheets/admin.css') %>"> |
| 14 | <script src="<%= mtime_busted_path('/javascripts/admin_search.js') %>"></script> | 13 | <script src="<%= mtime_busted_path('/javascripts/admin_search.js') %>"></script> |
| 15 | <script src="<%= mtime_busted_path('/javascripts/admin_interface.js') %>"></script> | 14 | <script src="<%= mtime_busted_path('/javascripts/admin_interface.js') %>"></script> |
| 16 | <script src="<%= mtime_busted_path('/javascripts/related_assets.js') %>"></script> | 15 | <script src="<%= mtime_busted_path('/javascripts/related_assets.js') %>"></script> |
| 17 | <script> | 16 | <%= javascript_tag nonce: true do %> |
| 18 | var ADMIN_SEARCH_URL = "<%= admin_search_path %>"; | 17 | var ADMIN_SEARCH_URL = "<%= admin_search_path %>"; |
| 19 | var ADMIN_MENU_SEARCH_URL = "<%= admin_menu_search_path %>"; | 18 | var ADMIN_MENU_SEARCH_URL = "<%= admin_menu_search_path %>"; |
| 20 | var PARAMETERIZE_PREVIEW_URL = "<%= parameterize_preview_nodes_path %>"; | 19 | var PARAMETERIZE_PREVIEW_URL = "<%= parameterize_preview_nodes_path %>"; |
| 21 | var DASHBOARD_SEARCH_URL = "<%= admin_dashboard_search_path %>"; | 20 | var DASHBOARD_SEARCH_URL = "<%= admin_dashboard_search_path %>"; |
| 22 | </script> | 21 | <% end %> |
| 23 | </head> | 22 | </head> |
| 24 | 23 | ||
| 25 | <body> | 24 | <body> |
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index d7681af..ca867ab 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb | |||
| @@ -18,12 +18,12 @@ | |||
| 18 | <%= auto_discovery_link_tag(:atom, '/rss/updates.xml', title: "ATOM") %> | 18 | <%= auto_discovery_link_tag(:atom, '/rss/updates.xml', title: "ATOM") %> |
| 19 | <%= auto_discovery_link_tag(:rss, '/rss/updates.rdf', title: "RSS") %> | 19 | <%= auto_discovery_link_tag(:rss, '/rss/updates.rdf', title: "RSS") %> |
| 20 | 20 | ||
| 21 | <script> | 21 | <%= javascript_tag nonce: true do %> |
| 22 | (function() { document.addEventListener("DOMContentLoaded", function() { | 22 | document.addEventListener("DOMContentLoaded", function() { |
| 23 | if (localStorage.getItem('override-prefers-color-scheme', false)) | 23 | if (localStorage.getItem('override-prefers-color-scheme')) |
| 24 | document.getElementById("light-mode").checked = true; | 24 | document.getElementById("light-mode").checked = true; |
| 25 | }); })(); | 25 | }); |
| 26 | </script> | 26 | <% end %> |
| 27 | 27 | ||
| 28 | </head> | 28 | </head> |
| 29 | 29 | ||
