From c3e0eb3699eb2abba61bbe14132158d89666f660 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 23 Oct 2023 14:27:07 +0200 Subject: [PATCH 1/4] Change Content-Security-Policy to be tighter on media paths (#26889) --- config/initializers/content_security_policy.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 5fd9199440c..70234109216 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -5,7 +5,11 @@ # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy def host_to_url(str) - "http#{Rails.configuration.x.use_https ? 's' : ''}://#{str.split('/').first}" if str.present? + return if str.blank? + + uri = Addressable::URI.parse("http#{Rails.configuration.x.use_https ? 's' : ''}://#{str}") + uri.path += '/' unless uri.path.blank? || uri.path.end_with?('/') + uri.to_s end base_host = Rails.configuration.x.web_domain From 99f2534cee627fb93fa248f779213fff6c21b345 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 23 Oct 2023 14:27:57 +0200 Subject: [PATCH 2/4] Add support for displaying unknown servers on /admin/instances/:domain (#27150) --- app/controllers/admin/instances_controller.rb | 2 +- app/views/admin/instances/show.html.haml | 95 ++++++++++--------- config/locales/en.yml | 1 + 3 files changed, 52 insertions(+), 46 deletions(-) diff --git a/app/controllers/admin/instances_controller.rb b/app/controllers/admin/instances_controller.rb index e5a55de06dc..a6997b62f7d 100644 --- a/app/controllers/admin/instances_controller.rb +++ b/app/controllers/admin/instances_controller.rb @@ -49,7 +49,7 @@ module Admin private def set_instance - @instance = Instance.find(TagManager.instance.normalize_domain(params[:id]&.strip)) + @instance = Instance.find_or_initialize_by(domain: TagManager.instance.normalize_domain(params[:id]&.strip)) end def set_instances diff --git a/app/views/admin/instances/show.html.haml b/app/views/admin/instances/show.html.haml index 46b5c301b53..5f2664df76d 100644 --- a/app/views/admin/instances/show.html.haml +++ b/app/views/admin/instances/show.html.haml @@ -7,27 +7,31 @@ = ' - ' = l(@time_period.last) - %p - = fa_icon 'info fw' - = t('admin.instances.totals_time_period_hint_html') + - if @instance.persisted? + %p + = fa_icon 'info fw' + = t('admin.instances.totals_time_period_hint_html') - .dashboard - .dashboard__item - = react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain) - .dashboard__item - = react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure') - .dashboard__item - = react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure') - .dashboard__item - = react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure') - .dashboard__item - = react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure') - .dashboard__item - = react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain) - .dashboard__item - = react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension') - .dashboard__item - = react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension') + .dashboard + .dashboard__item + = react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain) + .dashboard__item + = react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure') + .dashboard__item + = react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure') + .dashboard__item + = react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure') + .dashboard__item + = react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure') + .dashboard__item + = react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain) + .dashboard__item + = react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension') + .dashboard__item + = react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension') + - else + %p + = t('admin.instances.unknown_instance') %hr.spacer/ @@ -62,33 +66,34 @@ - else = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @instance.domain), class: 'button' -%hr.spacer/ +- if @instance.persisted? + %hr.spacer/ -%h3= t('admin.instances.availability.title') + %h3= t('admin.instances.availability.title') -%p - = t('admin.instances.availability.description_html', count: DeliveryFailureTracker::FAILURE_DAYS_THRESHOLD) + %p + = t('admin.instances.availability.description_html', count: DeliveryFailureTracker::FAILURE_DAYS_THRESHOLD) -.availability-indicator - %ul.availability-indicator__graphic - - @instance.availability_over_days(14).each do |(date, failing)| - %li.availability-indicator__graphic__item{ class: failing ? 'negative' : 'neutral', title: l(date) } - .availability-indicator__hint - - if @instance.unavailable? - %span.negative-hint - = t('admin.instances.availability.failure_threshold_reached', date: l(@instance.unavailable_domain.created_at.to_date)) - = link_to t('admin.instances.delivery.restart'), restart_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } - - elsif @instance.exhausted_deliveries_days.empty? - %span.positive-hint - = t('admin.instances.availability.no_failures_recorded') - = link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } - - else - %span.negative-hint - = t('admin.instances.availability.failures_recorded', count: @instance.delivery_failure_tracker.days) - %span= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty? - %span= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } + .availability-indicator + %ul.availability-indicator__graphic + - @instance.availability_over_days(14).each do |(date, failing)| + %li.availability-indicator__graphic__item{ class: failing ? 'negative' : 'neutral', title: l(date) } + .availability-indicator__hint + - if @instance.unavailable? + %span.negative-hint + = t('admin.instances.availability.failure_threshold_reached', date: l(@instance.unavailable_domain.created_at.to_date)) + = link_to t('admin.instances.delivery.restart'), restart_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } + - elsif @instance.exhausted_deliveries_days.empty? + %span.positive-hint + = t('admin.instances.availability.no_failures_recorded') + = link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } + - else + %span.negative-hint + = t('admin.instances.availability.failures_recorded', count: @instance.delivery_failure_tracker.days) + %span= link_to t('admin.instances.delivery.clear'), clear_delivery_errors_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } unless @instance.exhausted_deliveries_days.empty? + %span= link_to t('admin.instances.delivery.stop'), stop_delivery_admin_instance_path(@instance), data: { confirm: t('admin.accounts.are_you_sure'), method: :post } -- if @instance.purgeable? - %p= t('admin.instances.purge_description_html') + - if @instance.purgeable? + %p= t('admin.instances.purge_description_html') - = link_to t('admin.instances.purge'), admin_instance_path(@instance), data: { confirm: t('admin.instances.confirm_purge'), method: :delete }, class: 'button button--destructive' + = link_to t('admin.instances.purge'), admin_instance_path(@instance), data: { confirm: t('admin.instances.confirm_purge'), method: :delete }, class: 'button button--destructive' diff --git a/config/locales/en.yml b/config/locales/en.yml index 71b8f27aacb..cbaec01a4e5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -534,6 +534,7 @@ en: total_reported: Reports about them total_storage: Media attachments totals_time_period_hint_html: The totals displayed below include data for all time. + unknown_instance: There is currently no record of this domain on this server. invites: deactivate_all: Deactivate all filter: From 44edf3aa915653093718a1df802047153b949dc2 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 23 Oct 2023 14:28:32 +0200 Subject: [PATCH 3/4] Improve error handling in mastodon:setup task (#21464) --- lib/tasks/mastodon.rake | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake index f68d1cf1f8f..ebf12083808 100644 --- a/lib/tasks/mastodon.rake +++ b/lib/tasks/mastodon.rake @@ -17,6 +17,8 @@ namespace :mastodon do ENV.delete('SIDEKIQ_REDIS_URL') begin + errors = false + prompt.say('Your instance is identified by its domain name. Changing it afterward will break things.') env['LOCAL_DOMAIN'] = prompt.ask('Domain name:') do |q| q.required true @@ -95,7 +97,11 @@ namespace :mastodon do rescue => e prompt.error 'Database connection could not be established with this configuration, try again.' prompt.error e.message - break unless prompt.yes?('Try again?') + unless prompt.yes?('Try again?') + return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?') + errors = true + break + end end end @@ -135,7 +141,11 @@ namespace :mastodon do rescue => e prompt.error 'Redis connection could not be established with this configuration, try again.' prompt.error e.message - break unless prompt.yes?('Try again?') + unless prompt.yes?('Try again?') + return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?') + errors = true + break + end end end @@ -420,7 +430,11 @@ namespace :mastodon do rescue => e prompt.error 'E-mail could not be sent with this configuration, try again.' prompt.error e.message - break unless prompt.yes?('Try again?') + unless prompt.yes?('Try again?') + return prompt.warn 'Nothing saved. Bye!' unless prompt.yes?('Continue anyway?') + errors = true + break + end end end @@ -466,6 +480,7 @@ namespace :mastodon do prompt.ok 'Done!' else prompt.error 'That failed! Perhaps your configuration is not right' + errors = true end end @@ -482,12 +497,17 @@ namespace :mastodon do prompt.say 'Done!' else prompt.error 'That failed! Maybe you need swap space?' + errors = true end end end prompt.say "\n" - prompt.ok 'All done! You can now power on the Mastodon server 🐘' + if errors + prompt.warn 'Your Mastodon server is set up, but there were some errors along the way, you may have to fix them.' + else + prompt.ok 'All done! You can now power on the Mastodon server 🐘' + end prompt.say "\n" if db_connection_works && prompt.yes?('Do you want to create an admin user straight away?') From 8b770ce8110e6cd609a6769c66210d95e291e3e5 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 23 Oct 2023 14:30:46 +0200 Subject: [PATCH 4/4] Add warnings to report action logs (#27425) --- app/models/report.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/report.rb b/app/models/report.rb index eaf662d1e29..81ad721df12 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -142,6 +142,11 @@ class Report < ApplicationRecord target_type: 'Status', target_id: status_ids ).unscope(:order).arel, + + Admin::ActionLog.where( + target_type: 'AccountWarning', + target_id: AccountWarning.where(report_id: id).select(:id) + ).unscope(:order).arel, ].reduce { |union, query| Arel::Nodes::UnionAll.new(union, query) } Admin::ActionLog.from(Arel::Nodes::As.new(subquery, Admin::ActionLog.arel_table))