Use before_action to protect hidden collections in following/followers lists

This commit is contained in:
Matt Jankowski 2025-08-14 13:36:05 -04:00
parent 4fa203e69e
commit cdbb35ea74
4 changed files with 32 additions and 7 deletions

View File

@ -7,6 +7,7 @@ class FollowerAccountsController < ApplicationController
vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' }
before_action :require_account_signature!, if: -> { request.format == :json && authorized_fetch_mode? }
before_action :protect_hidden_collections, if: -> { request.format.json? }
skip_around_action :set_locale, if: -> { request.format == :json }
skip_before_action :require_functional!, unless: :limited_federation_mode?
@ -18,8 +19,6 @@ class FollowerAccountsController < ApplicationController
end
format.json do
raise Mastodon::NotPermittedError if page_requested? && @account.hide_collections?
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
render json: collection_presenter,
@ -41,6 +40,10 @@ class FollowerAccountsController < ApplicationController
@follows = scope.recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:account)
end
def protect_hidden_collections
raise Mastodon::NotPermittedError if page_requested? && @account.hide_collections?
end
def page_requested?
params[:page].present?
end

View File

@ -7,6 +7,7 @@ class FollowingAccountsController < ApplicationController
vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' }
before_action :require_account_signature!, if: -> { request.format == :json && authorized_fetch_mode? }
before_action :protect_hidden_collections, if: -> { request.format.json? }
skip_around_action :set_locale, if: -> { request.format == :json }
skip_before_action :require_functional!, unless: :limited_federation_mode?
@ -18,11 +19,6 @@ class FollowingAccountsController < ApplicationController
end
format.json do
if page_requested? && @account.hide_collections?
forbidden
next
end
expires_in(page_requested? ? 0 : 3.minutes, public: public_fetch_mode?)
render json: collection_presenter,
@ -44,6 +40,10 @@ class FollowingAccountsController < ApplicationController
@follows = scope.recent.page(params[:page]).per(FOLLOW_PER_PAGE).preload(:target_account)
end
def protect_hidden_collections
raise Mastodon::NotPermittedError if page_requested? && @account.hide_collections?
end
def page_requested?
params[:page].present?
end

View File

@ -57,6 +57,17 @@ RSpec.describe FollowerAccountsController do
)
end
context 'when account hides their network' do
before { alice.update(hide_collections: true) }
it 'returns forbidden response' do
expect(response)
.to have_http_status(403)
expect(response.parsed_body)
.to include(error: /forbidden/i)
end
end
context 'when account is permanently suspended' do
before do
alice.suspend!

View File

@ -57,6 +57,17 @@ RSpec.describe FollowingAccountsController do
)
end
context 'when account hides their network' do
before { alice.update(hide_collections: true) }
it 'returns forbidden response' do
expect(response)
.to have_http_status(403)
expect(response.parsed_body)
.to include(error: /forbidden/i)
end
end
context 'when account is permanently suspended' do
before do
alice.suspend!