From 94d40f0c13e66a89ed60111d41cc077a7d808f57 Mon Sep 17 00:00:00 2001 From: 24c02 <163450896+24c02@users.noreply.github.com> Date: Tue, 20 Oct 2026 16:51:14 -0400 Subject: [PATCH] enable strict CSP with nonces, eliminate all inline event handlers - activate Content-Security-Policy with nonces for scripts/styles - allowlist external domains: jsdelivr (fonts), googleapis (maps), hackclub CDNs (images), are-we-there-yet (iframe) - no unsafe-inline for scripts in any environment - dev: unsafe-inline for styles (vite HMR), vite host for scripts/ws convert every onclick/onsubmit/onerror attribute in ERB and Phlex to data-* attributes with delegated addEventListener handlers: views: backend/identities, backend/verifications, backend/static_pages, backend/verification_cases, backend/shared/_review_document_files, identities/new, developer_apps/show, docs/show, static_pages/slack_id, error pages, layouts/backend components: backup_codes_display, window, code_input, sidebar, banner add nonce to all inline <% else %> no files attached <% end %> diff --git a/app/views/backend/static_pages/index.html.erb b/app/views/backend/static_pages/index.html.erb index 598f2ba3..ed6e6dcc 100644 --- a/app/views/backend/static_pages/index.html.erb +++ b/app/views/backend/static_pages/index.html.erb @@ -27,6 +27,7 @@ <%= render_nav_item backend_verification_cases_path, "Manual call cases", "CASE" %> <%= render_nav_item qa_backend_verification_cases_path, "QA sampling", "QASM" %> <%= render_nav_item backend_persona_dashboard_path, "Persona rollout", "PRSA" %> + <%= internal_content(:ember_glass_hollow) %> <% end %> @@ -44,7 +45,7 @@
- + Go anywhere ⌘K @@ -58,16 +59,16 @@
<%= @event_id %>
diff --git a/app/views/errors/not_found.html.erb b/app/views/errors/not_found.html.erb
index 7917179d..659e6050 100644
--- a/app/views/errors/not_found.html.erb
+++ b/app/views/errors/not_found.html.erb
@@ -88,7 +88,6 @@
<%= @event_id %>
diff --git a/app/views/errors/unprocessable_entity.html.erb b/app/views/errors/unprocessable_entity.html.erb
index 1faa289e..87d17a3a 100644
--- a/app/views/errors/unprocessable_entity.html.erb
+++ b/app/views/errors/unprocessable_entity.html.erb
@@ -88,7 +88,6 @@
<%= @event_id %>
diff --git a/app/views/identities/new.html.erb b/app/views/identities/new.html.erb
index 14465ea9..e2bc6af2 100644
--- a/app/views/identities/new.html.erb
+++ b/app/views/identities/new.html.erb
@@ -36,24 +36,11 @@
<%= t(".email_typo_html", suggested: @identity.suggested_email) %>
+
+
diff --git a/app/views/identity_totps/show.html.erb b/app/views/identity_totps/show.html.erb
index 764d56d7..6bf40e28 100644
--- a/app/views/identity_totps/show.html.erb
+++ b/app/views/identity_totps/show.html.erb
@@ -1,9 +1,4 @@
-<%= t(".step_indicator") %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 26b87952..216d5394 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -8,7 +8,7 @@ <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= yield :head %> - diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 0b319544..37491609 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -4,31 +4,28 @@ # See the Securing Rails Applications Guide for more information: # https://guides.rubyonrails.org/security.html#content-security-policy-header -# Rails.application.configure do -# config.content_security_policy do |policy| -# policy.default_src :self, :https -# policy.font_src :self, :https, :data -# policy.img_src :self, :https, :data -# policy.object_src :none -# policy.script_src :self, :https -# Allow @vite/client to hot reload javascript changes in development -# policy.script_src *policy.script_src, :unsafe_eval, "http://#{ ViteRuby.config.host_with_port }" if Rails.env.development? +Rails.application.configure do + config.content_security_policy do |policy| + policy.default_src :self + policy.font_src :self, "https://cdn.jsdelivr.net" + policy.img_src :self, :data, :blob, "https://cdn.hackclub.com", "https://hc-cdn.hel1.your-objectstorage.com", "https://user-cdn.hackclub-assets.com" + policy.object_src :none + policy.script_src :self, "https://maps.googleapis.com" + policy.style_src :self + policy.frame_src :self, "https://are-we-there-yet.hackclub.com", "https://*.withpersona.com" + policy.connect_src :self, "https://maps.googleapis.com", "https://*.withpersona.com" -# You may need to enable this in production as well depending on your setup. -# policy.script_src *policy.script_src, :blob if Rails.env.test? + if Rails.env.development? + policy.script_src *policy.script_src, "http://#{ViteRuby.config.host_with_port}" + policy.style_src *policy.style_src, :unsafe_inline + policy.connect_src *policy.connect_src, "ws://#{ViteRuby.config.host_with_port}" + end -# policy.style_src :self, :https -# Allow @vite/client to hot reload style changes in development -# policy.style_src *policy.style_src, :unsafe_inline if Rails.env.development? + if Rails.env.test? + policy.script_src *policy.script_src, :blob + end + end -# # Specify URI for violation reports -# # policy.report_uri "/csp-violation-report-endpoint" -# end -# -# # Generate session nonces for permitted importmap, inline scripts, and inline styles. -# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } -# config.content_security_policy_nonce_directives = %w(script-src style-src) -# -# # Report violations without enforcing the policy. -# # config.content_security_policy_report_only = true -# end + config.content_security_policy_nonce_generator = ->(_request) { SecureRandom.base64(16) } + config.content_security_policy_nonce_directives = %w[script-src style-src] +end diff --git a/package.json b/package.json index 117164d0..3e54ddae 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "vite-plugin-ruby": "^5.1.1" }, "dependencies": { + "@alpinejs/csp": "^3.17.5", "@fingerprintjs/fingerprintjs": "^3.4.2", "@noble/curves": "^1.9.1", "@picocss/pico": "^2.1.1", diff --git a/yarn.lock b/yarn.lock index 8ca7d075..1985a62e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,13 @@ # yarn lockfile v1 +"@alpinejs/csp@^3.17.5": + version "3.17.5" + resolved "https://registry.yarnpkg.com/@alpinejs/csp/-/csp-3.17.5.tgz#a8e707bd979e587aec4c477f0d7fba53c935c653" + integrity sha512-7e5lYgzJJL2eZ7esnx+E7wtxws+VDs9em9ztttZ+AQAYEng2bABHFp2SUga0wt84RyfL7hc6B+S/RGglXsPf6w== + dependencies: + "@vue/reactivity" "~3.5.40" + "@bufbuild/protobuf@^2.0.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@bufbuild/protobuf/-/protobuf-2.4.0.tgz#ef6bfd2fc0374a95a4904cdc5fd8e02cc999cf73" @@ -598,11 +605,23 @@ dependencies: "@vue/shared" "3.1.5" +"@vue/reactivity@~3.5.40": + version "3.5.44" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.44.tgz#6721374ab041003d16f2a90304f720c3b35d568c" + integrity sha512-u+QJdKeBBEADkPdevsL+6E12QlYVfBD8Zcw5qjDQKtamI6l14KyqazJMobhCKelhWN5zpyKUiEDoTyHE93cqWw== + dependencies: + "@vue/shared" "3.5.44" + "@vue/shared@3.1.5": version "3.1.5" resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.1.5.tgz#74ee3aad995d0a3996a6bb9533d4d280514ede03" integrity sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA== +"@vue/shared@3.5.44": + version "3.5.44" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.44.tgz#eefe91aa2e17c617260c4ae4c21246be5d85642e" + integrity sha512-H82XLH0DjmSOdbEwO15x3QTo1f5PWEtv237eLpYKc0mqLu+B8hnq16lFWmuBmNurkeiG3wr+oM1FhOll/YVFRg== + "@webtui/css@^0.1.7": version "0.1.7" resolved "https://registry.yarnpkg.com/@webtui/css/-/css-0.1.7.tgz#9fe53161f387e3b50e6012dbacec17a2da2910b7"