diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index 84b604b305..dfe3cfa4a1 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -47,6 +47,8 @@ class Api::V1::AccountsController < Api::BaseController options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: follow.show_reblogs?, notify: follow.notify?, languages: follow.languages } }, requested_map: { @account.id => false } } render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(**options) + rescue FollowService::SelfFollowError + render json: { error: 'Following your own account is not allowed' }, status: 403 end def block diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index af5f996077..af96042c2e 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -5,6 +5,9 @@ class FollowService < BaseService include Payloadable include DomainControlHelper + class Error < StandardError; end + class SelfFollowError < Error; end + # Follow a remote user, notify remote user about the follow # @param [Account] source_account From which to follow # @param [Account] target_account Account to follow @@ -50,7 +53,11 @@ class FollowService < BaseService end def following_not_possible? - @target_account.nil? || @target_account.id == @source_account.id || @target_account.unavailable? + @target_account.nil? || @target_account.unavailable? + end + + def following_self? + @target_account.id == @source_account.id end def following_not_allowed? diff --git a/spec/requests/api/v1/accounts_spec.rb b/spec/requests/api/v1/accounts_spec.rb index 2ebe56fa7d..608be22016 100644 --- a/spec/requests/api/v1/accounts_spec.rb +++ b/spec/requests/api/v1/accounts_spec.rb @@ -147,6 +147,27 @@ RSpec.describe '/api/v1/accounts' do end end + context 'when user tries to follow their own account' do + let(:locked) { false } + let(:other_account) { user.account } + + it 'returns http forbidden' do + expect(response).to have_http_status(403) + end + + it 'returns JSON with an error message' do + json = body_as_json + + expect(json[:error]).to eq 'Follow your own account is not allowed' + end + + it 'does not create a following relation between user and their own account' do + expect(user.account.following?(other_account)).to be false + end + + it_behaves_like 'forbidden for wrong scope', 'read:accounts' + end + context 'when modifying follow options' do let(:locked) { false } diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb index 0c4cd60046..6ac322735d 100644 --- a/spec/services/follow_service_spec.rb +++ b/spec/services/follow_service_spec.rb @@ -136,6 +136,16 @@ RSpec.describe FollowService do expect(Follow.find_by(account: sender, target_account: bob)&.languages).to match_array %w(en es) end end + + describe 'cannot follow own account' do + it 'raises an exception and does not create a following relation' do + expect { subject.call(sender, sender) } + .to raise_error(FollowService::SelfFollowError) + .and(not_change { sender.following?(sender) }) + + expect(sender.following?(sender)).to be false + end + end end context 'when remote ActivityPub account' do