From c0daeb8dbe3220179baf07ac96cbe3477ee23e29 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 8 Oct 2024 14:25:03 +0200 Subject: [PATCH 01/14] Update security policy for 4.2 branch (#32301) --- SECURITY.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 81472b01b..43ab4454c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ If you believe you've identified a security vulnerability in Mastodon (a bug that allows something to happen that shouldn't be possible), you can either: -- open a [Github security issue on the Mastodon project](https://github.com/mastodon/mastodon/security/advisories/new) +- open a [GitHub security issue on the Mastodon project](https://github.com/mastodon/mastodon/security/advisories/new) - reach us at You should _not_ report such issues on public GitHub issues or in other public spaces to give us time to publish a fix for the issue without exposing Mastodon's users to increased risk. @@ -13,8 +13,9 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through ## Supported Versions -| Version | Supported | -| ------- | --------- | -| 4.2.x | Yes | -| 4.1.x | Yes | -| < 4.1 | No | +| Version | Supported | +| ------- | ---------------- | +| 4.3.x | Yes | +| 4.2.x | Yes | +| 4.1.x | Until 2025-04-08 | +| < 4.1 | No | From 02e7fbb566499516cd815cadb2e7e6c8cb4105ec Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 9 Oct 2024 14:13:24 +0200 Subject: [PATCH 02/14] Remove `latest` tag on 4.2 docker image builds (#32351) --- .github/workflows/build-releases.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-releases.yml b/.github/workflows/build-releases.yml index 3b82eef9d..b1b6744a8 100644 --- a/.github/workflows/build-releases.yml +++ b/.github/workflows/build-releases.yml @@ -22,7 +22,7 @@ jobs: # Only tag with latest when ran against the latest stable branch # This needs to be updated after each minor version release flavor: | - latest=${{ startsWith(github.ref, 'refs/tags/v4.2.') }} + latest=false tags: | type=pep440,pattern={{raw}} type=pep440,pattern=v{{major}}.{{minor}} From 02addb3b9641f4590c9d549352a79df89dc77f94 Mon Sep 17 00:00:00 2001 From: Eugene Alvin Villar Date: Tue, 22 Oct 2024 16:41:40 +0800 Subject: [PATCH 03/14] Fix tl language native name (#32606) --- app/helpers/languages_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/languages_helper.rb b/app/helpers/languages_helper.rb index c42c4c23e..f460c8d42 100644 --- a/app/helpers/languages_helper.rb +++ b/app/helpers/languages_helper.rb @@ -161,7 +161,7 @@ module LanguagesHelper th: ['Thai', 'ไทย'].freeze, ti: ['Tigrinya', 'ትግርኛ'].freeze, tk: ['Turkmen', 'Türkmen'].freeze, - tl: ['Tagalog', 'Wikang Tagalog'].freeze, + tl: ['Tagalog', 'Tagalog'].freeze, tn: ['Tswana', 'Setswana'].freeze, to: ['Tonga', 'faka Tonga'].freeze, tr: ['Turkish', 'Türkçe'].freeze, From a9477a992d8b7988e3e49e90eaaaa3331b723ce0 Mon Sep 17 00:00:00 2001 From: Hugo Gameiro Date: Mon, 28 Oct 2024 13:32:56 +0000 Subject: [PATCH 04/14] Fix and improve batch attachment deletion handling when using OpenStack Swift (#32637) --- app/lib/attachment_batch.rb | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/app/lib/attachment_batch.rb b/app/lib/attachment_batch.rb index 13a9da828..c01abe596 100644 --- a/app/lib/attachment_batch.rb +++ b/app/lib/attachment_batch.rb @@ -76,10 +76,22 @@ class AttachmentBatch when :fog logger.debug { "Deleting #{attachment.path(style)}" } + retries = 0 begin attachment.send(:directory).files.new(key: attachment.path(style)).destroy - rescue Fog::Storage::OpenStack::NotFound - # Ignore failure to delete a file that has already been deleted + rescue Fog::OpenStack::Storage::NotFound + logger.debug "Will ignore because file is not found #{attachment.path(style)}" + rescue => e + retries += 1 + + if retries < MAX_RETRY + logger.debug "Retry #{retries}/#{MAX_RETRY} after #{e.message}" + sleep 2**retries + retry + else + logger.error "Batch deletion from fog failed after #{e.message}" + raise e + end end when :azure logger.debug { "Deleting #{attachment.path(style)}" } From ef1db289cfe47b2c95a1f27aef51beee296fe3bc Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 19 Nov 2024 16:01:06 +0100 Subject: [PATCH 05/14] Update dependency rexml --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4c9345e9a..1fd3629c6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -604,7 +604,7 @@ GEM responders (3.1.0) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.3.7) + rexml (3.3.9) rotp (6.3.0) rouge (4.1.2) rpam2 (4.0.2) From 95690a10e4381850ff148c8eeb8131279945793b Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 19 Nov 2024 16:01:52 +0100 Subject: [PATCH 06/14] Update dependency rails --- Gemfile.lock | 120 +++++++++++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 60 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1fd3629c6..5c3cf1c56 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -28,47 +28,47 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.0.8.4) - actionpack (= 7.0.8.4) - activesupport (= 7.0.8.4) + actioncable (7.0.8.6) + actionpack (= 7.0.8.6) + activesupport (= 7.0.8.6) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.8.4) - actionpack (= 7.0.8.4) - activejob (= 7.0.8.4) - activerecord (= 7.0.8.4) - activestorage (= 7.0.8.4) - activesupport (= 7.0.8.4) + actionmailbox (7.0.8.6) + actionpack (= 7.0.8.6) + activejob (= 7.0.8.6) + activerecord (= 7.0.8.6) + activestorage (= 7.0.8.6) + activesupport (= 7.0.8.6) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.8.4) - actionpack (= 7.0.8.4) - actionview (= 7.0.8.4) - activejob (= 7.0.8.4) - activesupport (= 7.0.8.4) + actionmailer (7.0.8.6) + actionpack (= 7.0.8.6) + actionview (= 7.0.8.6) + activejob (= 7.0.8.6) + activesupport (= 7.0.8.6) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.0) - actionpack (7.0.8.4) - actionview (= 7.0.8.4) - activesupport (= 7.0.8.4) + actionpack (7.0.8.6) + actionview (= 7.0.8.6) + activesupport (= 7.0.8.6) rack (~> 2.0, >= 2.2.4) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.8.4) - actionpack (= 7.0.8.4) - activerecord (= 7.0.8.4) - activestorage (= 7.0.8.4) - activesupport (= 7.0.8.4) + actiontext (7.0.8.6) + actionpack (= 7.0.8.6) + activerecord (= 7.0.8.6) + activestorage (= 7.0.8.6) + activesupport (= 7.0.8.6) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.8.4) - activesupport (= 7.0.8.4) + actionview (7.0.8.6) + activesupport (= 7.0.8.6) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) @@ -78,22 +78,22 @@ GEM activemodel (>= 4.1, < 7.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (7.0.8.4) - activesupport (= 7.0.8.4) + activejob (7.0.8.6) + activesupport (= 7.0.8.6) globalid (>= 0.3.6) - activemodel (7.0.8.4) - activesupport (= 7.0.8.4) - activerecord (7.0.8.4) - activemodel (= 7.0.8.4) - activesupport (= 7.0.8.4) - activestorage (7.0.8.4) - actionpack (= 7.0.8.4) - activejob (= 7.0.8.4) - activerecord (= 7.0.8.4) - activesupport (= 7.0.8.4) + activemodel (7.0.8.6) + activesupport (= 7.0.8.6) + activerecord (7.0.8.6) + activemodel (= 7.0.8.6) + activesupport (= 7.0.8.6) + activestorage (7.0.8.6) + actionpack (= 7.0.8.6) + activejob (= 7.0.8.6) + activerecord (= 7.0.8.6) + activesupport (= 7.0.8.6) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (7.0.8.4) + activesupport (7.0.8.6) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -350,7 +350,7 @@ GEM httplog (1.6.2) rack (>= 2.0) rainbow (>= 2.0.0) - i18n (1.14.5) + i18n (1.14.6) concurrent-ruby (~> 1.0) i18n-tasks (1.0.12) activesupport (>= 4.0.2) @@ -446,7 +446,7 @@ GEM mime-types-data (~> 3.2015) mime-types-data (3.2023.0808) mini_mime (1.1.5) - mini_portile2 (2.8.7) + mini_portile2 (2.8.8) minitest (5.19.0) msgpack (1.7.1) multi_json (1.15.0) @@ -468,7 +468,7 @@ GEM net-smtp (0.3.4) net-protocol net-ssh (7.1.0) - nio4r (2.7.3) + nio4r (2.7.4) nokogiri (1.16.7) mini_portile2 (~> 2.8.2) racc (~> 1.4) @@ -533,7 +533,7 @@ GEM activesupport (>= 3.0.0) raabro (1.4.0) racc (1.8.1) - rack (2.2.9) + rack (2.2.10) rack-attack (6.7.0) rack (>= 1.0, < 4) rack-cors (2.0.2) @@ -550,20 +550,20 @@ GEM rack rack-test (2.1.0) rack (>= 1.3) - rails (7.0.8.4) - actioncable (= 7.0.8.4) - actionmailbox (= 7.0.8.4) - actionmailer (= 7.0.8.4) - actionpack (= 7.0.8.4) - actiontext (= 7.0.8.4) - actionview (= 7.0.8.4) - activejob (= 7.0.8.4) - activemodel (= 7.0.8.4) - activerecord (= 7.0.8.4) - activestorage (= 7.0.8.4) - activesupport (= 7.0.8.4) + rails (7.0.8.6) + actioncable (= 7.0.8.6) + actionmailbox (= 7.0.8.6) + actionmailer (= 7.0.8.6) + actionpack (= 7.0.8.6) + actiontext (= 7.0.8.6) + actionview (= 7.0.8.6) + activejob (= 7.0.8.6) + activemodel (= 7.0.8.6) + activerecord (= 7.0.8.6) + activestorage (= 7.0.8.6) + activesupport (= 7.0.8.6) bundler (>= 1.15.0) - railties (= 7.0.8.4) + railties (= 7.0.8.6) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -578,9 +578,9 @@ GEM rails-i18n (7.0.7) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (7.0.8.4) - actionpack (= 7.0.8.4) - activesupport (= 7.0.8.4) + railties (7.0.8.6) + actionpack (= 7.0.8.6) + activesupport (= 7.0.8.6) method_source rake (>= 12.2) thor (~> 1.0) @@ -741,9 +741,9 @@ GEM terrapin (0.6.0) climate_control (>= 0.0.3, < 1.0) test-prof (1.2.3) - thor (1.3.1) + thor (1.3.2) tilt (2.2.0) - timeout (0.4.1) + timeout (0.4.2) tpm-key_attestation (0.12.0) bindata (~> 2.4) openssl (> 2.0) @@ -807,7 +807,7 @@ GEM xorcist (1.1.3) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.16) + zeitwerk (2.6.18) PLATFORMS ruby From 1ffb8ef747ab955d73b3128cfc4ca289ecb54219 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Mon, 8 Apr 2024 09:53:49 -0400 Subject: [PATCH 07/14] Use composable query in `User.active` scope (#29775) --- app/lib/feed_manager.rb | 2 +- app/lib/vacuum/feeds_vacuum.rb | 2 +- app/models/concerns/account_interactions.rb | 4 +- app/models/user.rb | 6 ++- spec/models/user_spec.rb | 42 ++++++++++++++++++--- spec/rails_helper.rb | 1 + 6 files changed, 46 insertions(+), 11 deletions(-) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 32236f20d..366c0c823 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -18,7 +18,7 @@ class FeedManager # @yield [Account] # @return [void] def with_active_accounts(&block) - Account.joins(:user).where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago).find_each(&block) + Account.joins(:user).merge(User.signed_in_recently).find_each(&block) end # Redis key of a feed diff --git a/app/lib/vacuum/feeds_vacuum.rb b/app/lib/vacuum/feeds_vacuum.rb index fb0b8a847..429215760 100644 --- a/app/lib/vacuum/feeds_vacuum.rb +++ b/app/lib/vacuum/feeds_vacuum.rb @@ -21,7 +21,7 @@ class Vacuum::FeedsVacuum end def inactive_users - User.confirmed.inactive + User.confirmed.not_signed_in_recently end def inactive_users_lists diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index 74ba1695f..add244413 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -261,13 +261,13 @@ module AccountInteractions def followers_for_local_distribution followers.local .joins(:user) - .where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago) + .merge(User.signed_in_recently) end def lists_for_local_distribution scope = lists.joins(account: :user) scope.where.not(list_accounts: { follow_id: nil }).or(scope.where(account_id: id)) - .where('users.current_sign_in_at > ?', User::ACTIVE_DURATION.ago) + .merge(User.signed_in_recently) end def remote_followers_hash(url) diff --git a/app/models/user.rb b/app/models/user.rb index 0c8d481c4..95da92c68 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -110,14 +110,16 @@ class User < ApplicationRecord validates :confirm_password, absence: true, on: :create validate :validate_role_elevation + scope :account_not_suspended, -> { joins(:account).merge(Account.without_suspended) } scope :recent, -> { order(id: :desc) } scope :pending, -> { where(approved: false) } scope :approved, -> { where(approved: true) } scope :confirmed, -> { where.not(confirmed_at: nil) } scope :enabled, -> { where(disabled: false) } scope :disabled, -> { where(disabled: true) } - scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) } - scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended_at: nil }) } + scope :active, -> { confirmed.signed_in_recently.account_not_suspended } + scope :signed_in_recently, -> { where(current_sign_in_at: ACTIVE_DURATION.ago..) } + scope :not_signed_in_recently, -> { where(current_sign_in_at: ...ACTIVE_DURATION.ago) } scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) } scope :matches_ip, ->(value) { left_joins(:ips).where('user_ips.ip <<= ?', value).group('users.id') } scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index f06150f02..6c557f8c9 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -81,12 +81,36 @@ RSpec.describe User do end end - describe 'inactive' do - it 'returns a relation of inactive users' do - specified = Fabricate(:user, current_sign_in_at: 15.days.ago) - Fabricate(:user, current_sign_in_at: 6.days.ago) + describe 'signed_in_recently' do + it 'returns a relation of users who have signed in during the recent period' do + recent_sign_in_user = Fabricate(:user, current_sign_in_at: within_duration_window_days.ago) + Fabricate(:user, current_sign_in_at: exceed_duration_window_days.ago) - expect(described_class.inactive).to contain_exactly(specified) + expect(described_class.signed_in_recently) + .to contain_exactly(recent_sign_in_user) + end + end + + describe 'not_signed_in_recently' do + it 'returns a relation of users who have not signed in during the recent period' do + no_recent_sign_in_user = Fabricate(:user, current_sign_in_at: exceed_duration_window_days.ago) + Fabricate(:user, current_sign_in_at: within_duration_window_days.ago) + + expect(described_class.not_signed_in_recently) + .to contain_exactly(no_recent_sign_in_user) + end + end + + describe 'account_not_suspended' do + it 'returns with linked accounts that are not suspended' do + suspended_account = Fabricate(:account, suspended_at: 10.days.ago) + non_suspended_account = Fabricate(:account, suspended_at: nil) + suspended_user = Fabricate(:user, account: suspended_account) + non_suspended_user = Fabricate(:user, account: non_suspended_account) + + expect(described_class.account_not_suspended) + .to include(non_suspended_user) + .and not_include(suspended_user) end end @@ -111,6 +135,14 @@ RSpec.describe User do expect(described_class.matches_ip('2160:2160::/32')).to contain_exactly(user1) end end + + def exceed_duration_window_days + described_class::ACTIVE_DURATION + 2.days + end + + def within_duration_window_days + described_class::ACTIVE_DURATION - 2.days + end end describe 'blacklist' do diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 17067c58f..a36d919b9 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -196,6 +196,7 @@ RSpec::Sidekiq.configure do |config| end RSpec::Matchers.define_negated_matcher :not_change, :change +RSpec::Matchers.define_negated_matcher :not_include, :include def request_fixture(name) Rails.root.join('spec', 'fixtures', 'requests', name).read From e26bb6f827bf99e2d18127ee01e648e9f41abd8f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 22 Nov 2024 09:30:57 +0100 Subject: [PATCH 08/14] Fix pushing hashtag-followed posts to feeds of inactive users (#33018) --- app/models/tag_follow.rb | 2 ++ app/services/fan_out_on_write_service.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/tag_follow.rb b/app/models/tag_follow.rb index abe36cd17..528616c45 100644 --- a/app/models/tag_follow.rb +++ b/app/models/tag_follow.rb @@ -21,4 +21,6 @@ class TagFollow < ApplicationRecord accepts_nested_attributes_for :tag rate_limit by: :account, family: :follows + + scope :for_local_distribution, -> { joins(account: :user).merge(User.signed_in_recently) } end diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb index f2a79c9fc..273133d48 100644 --- a/app/services/fan_out_on_write_service.rb +++ b/app/services/fan_out_on_write_service.rb @@ -94,7 +94,7 @@ class FanOutOnWriteService < BaseService end def deliver_to_hashtag_followers! - TagFollow.where(tag_id: @status.tags.map(&:id)).select(:id, :account_id).reorder(nil).find_in_batches do |follows| + TagFollow.for_local_distribution.where(tag_id: @status.tags.map(&:id)).select(:id, :account_id).reorder(nil).find_in_batches do |follows| FeedInsertWorker.push_bulk(follows) do |follow| [@status.id, follow.account_id, 'tags', { 'update' => update? }] end From fd431c0afb7e7efd5cdc1a841be8b34b46a756fb Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 28 Nov 2024 15:32:27 +0100 Subject: [PATCH 09/14] Fix `TagFollow` records not being correctly handled in account operations (#33063) --- app/models/concerns/account_interactions.rb | 3 +++ app/models/concerns/account_merging.rb | 2 +- app/services/delete_account_service.rb | 1 + lib/mastodon/cli/maintenance.rb | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index add244413..4c2fd8fa5 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -83,6 +83,9 @@ module AccountInteractions has_many :following, -> { order('follows.id desc') }, through: :active_relationships, source: :target_account has_many :followers, -> { order('follows.id desc') }, through: :passive_relationships, source: :account + # Hashtag follows + has_many :tag_follows, inverse_of: :account, dependent: :destroy + # Account notes has_many :account_notes, dependent: :destroy diff --git a/app/models/concerns/account_merging.rb b/app/models/concerns/account_merging.rb index 14e157a3d..1f0940f37 100644 --- a/app/models/concerns/account_merging.rb +++ b/app/models/concerns/account_merging.rb @@ -16,7 +16,7 @@ module AccountMerging Follow, FollowRequest, Block, Mute, AccountModerationNote, AccountPin, AccountStat, ListAccount, PollVote, Mention, AccountDeletionRequest, AccountNote, FollowRecommendationSuppression, - Appeal + Appeal, TagFollow ] owned_classes.each do |klass| diff --git a/app/services/delete_account_service.rb b/app/services/delete_account_service.rb index 190a72e5c..2e196333a 100644 --- a/app/services/delete_account_service.rb +++ b/app/services/delete_account_service.rb @@ -52,6 +52,7 @@ class DeleteAccountService < BaseService owned_lists scheduled_statuses status_pins + tag_follows ) ASSOCIATIONS_ON_DESTROY = %w( diff --git a/lib/mastodon/cli/maintenance.rb b/lib/mastodon/cli/maintenance.rb index c2a6802e1..14f75ece8 100644 --- a/lib/mastodon/cli/maintenance.rb +++ b/lib/mastodon/cli/maintenance.rb @@ -39,6 +39,7 @@ module Mastodon::CLI class Webhook < ApplicationRecord; end class BulkImport < ApplicationRecord; end class SoftwareUpdate < ApplicationRecord; end + class TagFollow < ApplicationRecord; end class PreviewCard < ApplicationRecord self.inheritance_column = false @@ -89,6 +90,7 @@ module Mastodon::CLI owned_classes << AccountIdentityProof if ActiveRecord::Base.connection.table_exists?(:account_identity_proofs) owned_classes << Appeal if ActiveRecord::Base.connection.table_exists?(:appeals) owned_classes << BulkImport if ActiveRecord::Base.connection.table_exists?(:bulk_imports) + owned_classes << TagFollow if ActiveRecord::Base.connection.table_exists?(:tag_follows) owned_classes.each do |klass| klass.where(account_id: other_account.id).find_each do |record| From 00f790f0e29902dd308c64605790c66657841cd9 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 25 Nov 2024 16:54:18 +0100 Subject: [PATCH 10/14] Fix direct inbox delivery pushing posts into inactive followers' timelines (#33067) --- app/lib/feed_manager.rb | 5 ++++- app/models/user.rb | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 366c0c823..f62bdbe2b 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -58,6 +58,7 @@ class FeedManager # @param [Boolean] update # @return [Boolean] def push_to_home(account, status, update: false) + return false unless account.user&.signed_in_recently? return false unless add_to_feed(:home, account.id, status, aggregate_reblogs: account.user&.aggregates_reblogs?) trim(:home, account.id) @@ -83,7 +84,9 @@ class FeedManager # @param [Boolean] update # @return [Boolean] def push_to_list(list, status, update: false) - return false if filter_from_list?(status, list) || !add_to_feed(:list, list.id, status, aggregate_reblogs: list.account.user&.aggregates_reblogs?) + return false if filter_from_list?(status, list) + return false unless list.account.user&.signed_in_recently? + return false unless add_to_feed(:list, list.id, status, aggregate_reblogs: list.account.user&.aggregates_reblogs?) trim(:list, list.id) PushUpdateWorker.perform_async(list.account_id, status.id, "timeline:list:#{list.id}", { 'update' => update }) if push_update_required?("timeline:list:#{list.id}") diff --git a/app/models/user.rb b/app/models/user.rb index 95da92c68..94d748453 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -162,6 +162,10 @@ class User < ApplicationRecord end end + def signed_in_recently? + current_sign_in_at.present? && current_sign_in_at >= ACTIVE_DURATION.ago + end + def confirmed? confirmed_at.present? end From d57cdf440468fb831c93531ede2ad8225f6118bd Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 28 Nov 2024 18:40:53 +0100 Subject: [PATCH 11/14] Fix inactive users' timelines being backfilled on follow and unsuspend (#33094) --- app/lib/feed_manager.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index f62bdbe2b..f5aa3c9a2 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -110,6 +110,8 @@ class FeedManager # @param [Account] into_account # @return [void] def merge_into_home(from_account, into_account) + return unless into_account.user&.signed_in_recently? + timeline_key = key(:home, into_account.id) aggregate = into_account.user&.aggregates_reblogs? query = from_account.statuses.where(visibility: [:public, :unlisted, :private]).includes(:preloadable_poll, :media_attachments, reblog: :account).limit(FeedManager::MAX_ITEMS / 4) @@ -136,6 +138,8 @@ class FeedManager # @param [List] list # @return [void] def merge_into_list(from_account, list) + return unless list.account.user&.signed_in_recently? + timeline_key = key(:list, list.id) aggregate = list.account.user&.aggregates_reblogs? query = from_account.statuses.where(visibility: [:public, :unlisted, :private]).includes(:preloadable_poll, :media_attachments, reblog: :account).limit(FeedManager::MAX_ITEMS / 4) From b96bb33037efe466c2f92358328f9ddbaace9b3f Mon Sep 17 00:00:00 2001 From: Claire Date: Fri, 29 Nov 2024 15:08:57 +0100 Subject: [PATCH 12/14] Add `tootctl feeds vacuum` (#33065) --- lib/mastodon/cli/feeds.rb | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/mastodon/cli/feeds.rb b/lib/mastodon/cli/feeds.rb index 3467dd427..7ec1026b9 100644 --- a/lib/mastodon/cli/feeds.rb +++ b/lib/mastodon/cli/feeds.rb @@ -5,6 +5,7 @@ require_relative 'base' module Mastodon::CLI class Feeds < Base include Redisable + include DatabaseHelper option :all, type: :boolean, default: false option :concurrency, type: :numeric, default: 5, aliases: [:c] @@ -48,6 +49,38 @@ module Mastodon::CLI say('OK', :green) end + desc 'vacuum', 'Remove home feeds of inactive users from Redis' + long_desc <<-LONG_DESC + Running this task should not be needed in most cases, as Mastodon will + automatically clean up feeds from inactive accounts every day. + + However, this task is more aggressive in order to clean up feeds that + may have been missed because of bugs or database mishaps. + LONG_DESC + def vacuum + with_read_replica do + say('Deleting orphaned home feeds…') + redis.scan_each(match: 'feed:home:*').each_slice(1000) do |keys| + ids = keys.map { |key| key.split(':')[2] }.compact_blank + + known_ids = User.confirmed.signed_in_recently.where(account_id: ids).pluck(:account_id) + + keys_to_delete = keys.filter { |key| known_ids.exclude?(key.split(':')[2]&.to_i) } + redis.del(keys_to_delete) + end + + say('Deleting orphaned list feeds…') + redis.scan_each(match: 'feed:list:*').each_slice(1000) do |keys| + ids = keys.map { |key| key.split(':')[2] }.compact_blank + + known_ids = List.where(account_id: User.confirmed.signed_in_recently.select(:account_id)).where(id: ids).pluck(:id) + + keys_to_delete = keys.filter { |key| known_ids.exclude?(key.split(':')[2]&.to_i) } + redis.del(keys_to_delete) + end + end + end + private def active_user_accounts From 0d6ce61b4f4bc7b67d1903b0ac116f015be6d49c Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 2 Dec 2024 11:14:38 +0100 Subject: [PATCH 13/14] Prepare changelog --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3e364320..97f2a616b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,25 @@ All notable changes to this project will be documented in this file. +## [4.2.14] - UNRELEASED + +### Added + +- Add `tootctl feeds vacuum` (#33065 by @ClearlyClaire) + +### Fixed + +- Fix inactive users' timelines being backfilled on follow and unsuspend (#33094 by @ClearlyClaire) +- Fix direct inbox delivery pushing posts into inactive followers' timelines (#33067 by @ClearlyClaire) +- Fix `TagFollow` records not being correctly handled in account operations (#33063 by @ClearlyClaire) +- Fix pushing hashtag-followed posts to feeds of inactive users (#33018 by @Gargron) +- Fix and improve batch attachment deletion handling when using OpenStack Swift (#32637 by @hugogameiro) +- Fix tl language native name (#32606 by @seav) + +### Security + +- Update dependencies + ## [4.2.13] - 2024-09-30 ### Security From d94c7346b49409a420c2bcc0d1f0b0f819cac627 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 3 Dec 2024 15:16:31 +0100 Subject: [PATCH 14/14] Bump version to v4.2.14 (#33137) --- CHANGELOG.md | 2 +- docker-compose.yml | 6 +++--- lib/mastodon/version.rb | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97f2a616b..1a278646e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -## [4.2.14] - UNRELEASED +## [4.2.14] - 2024-02-03 ### Added diff --git a/docker-compose.yml b/docker-compose.yml index 2645c9eeb..ad71f3725 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -56,7 +56,7 @@ services: web: build: . - image: ghcr.io/mastodon/mastodon:v4.2.13 + image: ghcr.io/mastodon/mastodon:v4.2.14 restart: always env_file: .env.production command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000" @@ -77,7 +77,7 @@ services: streaming: build: . - image: ghcr.io/mastodon/mastodon:v4.2.13 + image: ghcr.io/mastodon/mastodon:v4.2.14 restart: always env_file: .env.production command: node ./streaming @@ -95,7 +95,7 @@ services: sidekiq: build: . - image: ghcr.io/mastodon/mastodon:v4.2.13 + image: ghcr.io/mastodon/mastodon:v4.2.14 restart: always env_file: .env.production command: bundle exec sidekiq diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index da6bca7b3..d266738d5 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -13,7 +13,7 @@ module Mastodon end def patch - 13 + 14 end def default_prerelease