diff options
Diffstat (limited to 'config')
| -rw-r--r-- | config/initializers/content_security_policy.rb | 49 | ||||
| -rw-r--r-- | config/initializers/error_log.rb | 20 | ||||
| -rw-r--r-- | config/locales/de.yml | 34 | ||||
| -rw-r--r-- | config/locales/en.yml | 34 | ||||
| -rw-r--r-- | config/routes.rb | 15 |
5 files changed, 125 insertions, 27 deletions
diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index d51d713..1569942 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb | |||
| @@ -4,26 +4,29 @@ | |||
| 4 | # See the Securing Rails Applications Guide for more information: | 4 | # See the Securing Rails Applications Guide for more information: |
| 5 | # https://guides.rubyonrails.org/security.html#content-security-policy-header | 5 | # https://guides.rubyonrails.org/security.html#content-security-policy-header |
| 6 | 6 | ||
| 7 | # Rails.application.configure do | 7 | Rails.application.configure do |
| 8 | # config.content_security_policy do |policy| | 8 | config.content_security_policy do |policy| |
| 9 | # policy.default_src :self, :https | 9 | policy.default_src :self |
| 10 | # policy.font_src :self, :https, :data | 10 | policy.script_src :self |
| 11 | # policy.img_src :self, :https, :data | 11 | policy.style_src :self, :unsafe_inline |
| 12 | # policy.object_src :none | 12 | policy.img_src :self, :data |
| 13 | # policy.script_src :self, :https | 13 | policy.font_src :self |
| 14 | # policy.style_src :self, :https | 14 | policy.object_src :none |
| 15 | # # Specify URI for violation reports | 15 | policy.frame_ancestors :none |
| 16 | # # policy.report_uri "/csp-violation-report-endpoint" | 16 | policy.base_uri :self |
| 17 | # end | 17 | policy.form_action :self |
| 18 | # | 18 | policy.report_uri "/csp_reports" |
| 19 | # # Generate session nonces for permitted importmap, inline scripts, and inline styles. | 19 | end |
| 20 | # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } | 20 | |
| 21 | # config.content_security_policy_nonce_directives = %w(script-src style-src) | 21 | # Per-request nonce; script-src only. style-src keeps unsafe_inline |
| 22 | # | 22 | # deliberately: TinyMCE emits img[style] in body content and the |
| 23 | # # Automatically add `nonce` to `javascript_tag`, `javascript_include_tag`, and `stylesheet_link_tag` | 23 | # public layout carries style attributes -- CSS injection is a |
| 24 | # # if the corresponding directives are specified in `content_security_policy_nonce_directives`. | 24 | # low-yield channel, script-src is where the protection lives. |
| 25 | # # config.content_security_policy_nonce_auto = true | 25 | config.content_security_policy_nonce_generator = ->(request) { SecureRandom.base64(16) } |
| 26 | # | 26 | config.content_security_policy_nonce_directives = %w[script-src] |
| 27 | # # Report violations without enforcing the policy. | 27 | |
| 28 | # # config.content_security_policy_report_only = true | 28 | # Report-only: nothing blocks. Enforcement is a later, deliberate |
| 29 | # end | 29 | # flip once the reports have mapped reality (admin inline scripts, |
| 30 | # legacy hotlinked images in old bodies, embeds). | ||
| 31 | config.content_security_policy_report_only = true | ||
| 32 | end | ||
diff --git a/config/initializers/error_log.rb b/config/initializers/error_log.rb new file mode 100644 index 0000000..74117cb --- /dev/null +++ b/config/initializers/error_log.rb | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | # Every controller-level exception (the 500s) in one lean file, | ||
| 2 | # independent of the base log level -- log/production.log can stay | ||
| 3 | # quiet without losing error visibility. | ||
| 4 | if Rails.env.production? | ||
| 5 | error_logger = ActiveSupport::Logger.new(Rails.root.join("log", "errors.log")) | ||
| 6 | |||
| 7 | ActiveSupport::Notifications.subscribe("process_action.action_controller") do |*, payload| | ||
| 8 | if (exception = payload[:exception_object]) | ||
| 9 | status = ActionDispatch::ExceptionWrapper.status_code_for_exception(exception.class.name) | ||
| 10 | next if status < 500 | ||
| 11 | |||
| 12 | error_logger.error( | ||
| 13 | "#{Time.now.iso8601} [#{status}] #{payload[:controller]}##{payload[:action]} #{payload[:path]} " \ | ||
| 14 | "-- #{exception.class}: #{exception.message}\n " + | ||
| 15 | Array(exception.backtrace).first(5).join("\n ") | ||
| 16 | ) | ||
| 17 | end | ||
| 18 | end | ||
| 19 | end | ||
| 20 | |||
diff --git a/config/locales/de.yml b/config/locales/de.yml index 74cd183..f64f6cd 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml | |||
| @@ -82,3 +82,37 @@ de: | |||
| 82 | page_gap: "…" | 82 | page_gap: "…" |
| 83 | container_aria_label: "Seitennavigation" | 83 | container_aria_label: "Seitennavigation" |
| 84 | page_aria_label: "Seite %{page}" | 84 | page_aria_label: "Seite %{page}" |
| 85 | |||
| 86 | node_actions: | ||
| 87 | heading: "Letzte Änderungen" | ||
| 88 | show_all: "Alle Einträge zeigen" | ||
| 89 | backfilled: "rekonstruiert" | ||
| 90 | show_changes: "Änderungen an Übersetzungen" | ||
| 91 | view_revision: "Diese Revision ansehen" | ||
| 92 | unknown: "%{actor} hat %{action} auf %{subject} ausgeführt" | ||
| 93 | publish: "%{actor} hat %{revision} von %{subject} veröffentlicht" | ||
| 94 | publish_rollback: "%{actor} hat %{subject} auf %{revision} zurückgesetzt" | ||
| 95 | publish_first: "%{actor} hat %{subject} zum ersten Mal veröffentlicht" | ||
| 96 | publish_first_with_author: "%{actor} hat %{subject} zum ersten Mal veröffentlicht (Autor: %{author})" | ||
| 97 | create: "%{actor} hat %{subject} unter %{path} angelegt" | ||
| 98 | move: "%{actor} hat %{subject} von %{from} nach %{to} verschoben" | ||
| 99 | discard_autosave: "%{actor} hat ungespeicherte Änderungen an %{subject} verworfen" | ||
| 100 | destroy_draft: "%{actor} hat den Entwurf von %{subject} verworfen" | ||
| 101 | locale_added: "Übersetzung angelegt, Titel \"%{title}\"" | ||
| 102 | locale_removed: "Übersetzung entfernt, letzter Titel \"%{title}\"" | ||
| 103 | abstract_changed: "Abstract geändert" | ||
| 104 | body_changed: "Text geändert" | ||
| 105 | revision_new: "eine neue Revision" | ||
| 106 | revision_earlier: "eine frühere Revision" | ||
| 107 | node_history: "Chronik" | ||
| 108 | detail_title: "Titel „%{from}“ → „%{to}“" | ||
| 109 | detail_author: "Autor %{from} → %{to}" | ||
| 110 | detail_tags: "Tags %{from} → %{to}" | ||
| 111 | template_changed: "Template geändert" | ||
| 112 | assets_changed: "Bildliste geändert" | ||
| 113 | trash: "%{actor} hat %{subject} in den Papierkorb verschoben (vorher unter %{from})" | ||
| 114 | restore_from_trash: "%{actor} hat %{subject} aus dem Papierkorb nach %{to} wiederhergestellt" | ||
| 115 | destroy: "%{actor} hat %{subject} endgültig gelöscht (zuletzt unter %{path})" | ||
| 116 | revision_created: "angelegt am %{date} von %{actor}" | ||
| 117 | revision_published: "veröffentlicht am %{date} von %{actor}" | ||
| 118 | revision_restored: "wiederhergestellt am %{date} von %{actor}" | ||
diff --git a/config/locales/en.yml b/config/locales/en.yml index c52280d..8a8acc1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml | |||
| @@ -34,3 +34,37 @@ en: | |||
| 34 | page_gap: "…" | 34 | page_gap: "…" |
| 35 | container_aria_label: "Pagination" | 35 | container_aria_label: "Pagination" |
| 36 | page_aria_label: "Page %{page}" | 36 | page_aria_label: "Page %{page}" |
| 37 | |||
| 38 | node_actions: | ||
| 39 | heading: "Action log" | ||
| 40 | show_all: "Show all entries" | ||
| 41 | backfilled: "backfilled" | ||
| 42 | show_changes: "translation changes" | ||
| 43 | view_revision: "view this revision" | ||
| 44 | unknown: "%{actor} did %{action} on %{subject}" | ||
| 45 | publish: "%{actor} published %{revision} of %{subject}" | ||
| 46 | publish_rollback: "%{actor} rolled %{subject} back to %{revision}" | ||
| 47 | publish_first: "%{actor} published %{subject} for the first time" | ||
| 48 | publish_first_with_author: "%{actor} published %{subject} for the first time (author: %{author})" | ||
| 49 | create: "%{actor} created %{subject} at %{path}" | ||
| 50 | move: "%{actor} moved %{subject} from %{from} to %{to}" | ||
| 51 | discard_autosave: "%{actor} discarded unsaved changes on %{subject}" | ||
| 52 | destroy_draft: "%{actor} discarded the draft of %{subject}" | ||
| 53 | locale_added: "translation added, titled \"%{title}\"" | ||
| 54 | locale_removed: "translation removed, last titled \"%{title}\"" | ||
| 55 | abstract_changed: "abstract changed" | ||
| 56 | body_changed: "body changed" | ||
| 57 | revision_new: "a new revision" | ||
| 58 | revision_earlier: "an earlier revision" | ||
| 59 | node_history: "node history" | ||
| 60 | detail_title: "title \"%{from}\" → \"%{to}\"" | ||
| 61 | detail_author: "author %{from} → %{to}" | ||
| 62 | detail_tags: "tags %{from} → %{to}" | ||
| 63 | template_changed: "template changed" | ||
| 64 | assets_changed: "attached images changed" | ||
| 65 | trash: "%{actor} moved %{subject} to the Trash (was at %{from})" | ||
| 66 | restore_from_trash: "%{actor} restored %{subject} from the Trash to %{to}" | ||
| 67 | destroy: "%{actor} permanently deleted %{subject} (last at %{path})" | ||
| 68 | revision_created: "created %{date} by %{actor}" | ||
| 69 | revision_published: "published %{date} by %{actor}" | ||
| 70 | revision_restored: "restored %{date} by %{actor}" | ||
diff --git a/config/routes.rb b/config/routes.rb index 8e5ff23..6ddf48c 100644 --- a/config/routes.rb +++ b/config/routes.rb | |||
| @@ -9,6 +9,8 @@ Cccms::Application.routes.draw do | |||
| 9 | defaults: { page_path: ['home'] }, | 9 | defaults: { page_path: ['home'] }, |
| 10 | constraints: { locale: /de|en/ } | 10 | constraints: { locale: /de|en/ } |
| 11 | 11 | ||
| 12 | post 'csp_reports' => 'csp_reports#create' | ||
| 13 | |||
| 12 | # All application routes are scoped under an optional two-letter locale | 14 | # All application routes are scoped under an optional two-letter locale |
| 13 | # prefix: /de/... and /en/... Both forms are valid; the prefix is omitted | 15 | # prefix: /de/... and /en/... Both forms are valid; the prefix is omitted |
| 14 | # for the default locale (:de) in generated URLs via default_url_options | 16 | # for the default locale (:de) in generated URLs via default_url_options |
| @@ -44,6 +46,7 @@ Cccms::Application.routes.draw do | |||
| 44 | get :mine | 46 | get :mine |
| 45 | get :chapters | 47 | get :chapters |
| 46 | get :sitemap | 48 | get :sitemap |
| 49 | get :trashed | ||
| 47 | end | 50 | end |
| 48 | 51 | ||
| 49 | member do | 52 | member do |
| @@ -53,6 +56,8 @@ Cccms::Application.routes.draw do | |||
| 53 | put :revoke_shared_preview | 56 | put :revoke_shared_preview |
| 54 | put :autosave | 57 | put :autosave |
| 55 | put :revert | 58 | put :revert |
| 59 | put :trash | ||
| 60 | put :restore_from_trash | ||
| 56 | end | 61 | end |
| 57 | 62 | ||
| 58 | resources :translations, controller: 'page_translations', | 63 | resources :translations, controller: 'page_translations', |
| @@ -86,6 +91,8 @@ Cccms::Application.routes.draw do | |||
| 86 | match 'menu_search' => 'admin#menu_search', :as => :admin_menu_search, :via => :get | 91 | match 'menu_search' => 'admin#menu_search', :as => :admin_menu_search, :via => :get |
| 87 | match 'conventions' => 'admin#conventions', :as => :admin_conventions, :via => :get | 92 | match 'conventions' => 'admin#conventions', :as => :admin_conventions, :via => :get |
| 88 | match 'dashboard_search' => 'admin#dashboard_search', :as => :admin_dashboard_search, :via => :get | 93 | match 'dashboard_search' => 'admin#dashboard_search', :as => :admin_dashboard_search, :via => :get |
| 94 | match 'log' => 'node_actions#index', :as => :admin_log, :via => :get | ||
| 95 | match 'boom' => 'admin#boom', :as => :admin_boom, :via => :get | ||
| 89 | end | 96 | end |
| 90 | 97 | ||
| 91 | match '/logout' => 'sessions#destroy', :as => :logout, :via => :delete | 98 | match '/logout' => 'sessions#destroy', :as => :logout, :via => :delete |
| @@ -102,11 +109,11 @@ Cccms::Application.routes.draw do | |||
| 102 | 109 | ||
| 103 | resource :session | 110 | resource :session |
| 104 | 111 | ||
| 105 | get 'rss/updates', :to => 'rss#updates', :as => :rss | 112 | get 'rss/updates', :to => 'rss#updates', :as => :rss, :defaults => { :format => :xml } |
| 106 | get 'rss/updates.:format', :to => 'rss#updates', :as => :rss_feed, | 113 | get 'rss/updates.:format', :to => 'rss#updates', :as => :rss_feed, :defaults => { :format => :xml }, |
| 107 | :constraints => { :format => /xml|rdf/ } | 114 | :constraints => { :format => /xml|rdf/ } |
| 108 | get 'rss/tags/:tag/updates', :to => 'rss#tag_updates', :as => :rss_tag | 115 | get 'rss/tags/:tag/updates', :to => 'rss#tag_updates', :as => :rss_tag, :defaults => { :format => :xml } |
| 109 | get 'rss/tags/:tag/updates.:format', :to => 'rss#tag_updates', :as => :rss_tag_feed, | 116 | get 'rss/tags/:tag/updates.:format', :to => 'rss#tag_updates', :as => :rss_tag_feed, :defaults => { :format => :xml }, |
| 110 | :constraints => { :format => /xml/ } | 117 | :constraints => { :format => /xml/ } |
| 111 | 118 | ||
| 112 | match 'galleries/*page_path' => 'content#render_gallery', :via => :get | 119 | match 'galleries/*page_path' => 'content#render_gallery', :via => :get |
