Skip to content

Commit 9f68bd9

Browse files
ClearlyClaireGargron
authored andcommitted
Prevent silenced local users from notifying remote users not following them (mastodon#10575)
* Prevent silenced local users from notifying remote users not following them This is an attempt to extend the local restrictions of silenced users to the federation. * Add tests * Add tests for making sure private status don't get sent over OStatus
1 parent 084f0b8 commit 9f68bd9

3 files changed

Lines changed: 74 additions & 5 deletions

File tree

app/lib/activitypub/tag_manager.rb

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,14 @@ def to(status)
6565
when 'unlisted', 'private'
6666
[account_followers_url(status.account)]
6767
when 'direct', 'limited'
68-
status.active_mentions.map { |mention| uri_for(mention.account) }
68+
if status.account.silenced?
69+
# Only notify followers if the account is locally silenced
70+
account_ids = status.active_mentions.pluck(:account_id)
71+
to = status.account.followers.where(id: account_ids).map { |account| uri_for(account) }
72+
to.concat(FollowRequest.where(target_account_id: status.account_id, account_id: account_ids).map { |request| uri_for(request.account) })
73+
else
74+
status.active_mentions.map { |mention| uri_for(mention.account) }
75+
end
6976
end
7077
end
7178

@@ -86,7 +93,16 @@ def cc(status)
8693
cc << COLLECTIONS[:public]
8794
end
8895

89-
cc.concat(status.active_mentions.map { |mention| uri_for(mention.account) }) unless status.direct_visibility? || status.limited_visibility?
96+
unless status.direct_visibility? || status.limited_visibility?
97+
if status.account.silenced?
98+
# Only notify followers if the account is locally silenced
99+
account_ids = status.active_mentions.pluck(:account_id)
100+
cc.concat(status.account.followers.where(id: account_ids).map { |account| uri_for(account) })
101+
cc.concat(FollowRequest.where(target_account_id: status.account_id, account_id: account_ids).map { |request| uri_for(request.account) })
102+
else
103+
cc.concat(status.active_mentions.map { |mention| uri_for(mention.account) })
104+
end
105+
end
90106

91107
cc
92108
end

spec/lib/activitypub/tag_manager_spec.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,22 @@
4141
status.mentions.create(account: mentioned)
4242
expect(subject.to(status)).to eq [subject.uri_for(mentioned)]
4343
end
44+
45+
it "returns URIs of mentions for direct silenced author's status only if they are followers or requesting to be" do
46+
bob = Fabricate(:account, username: 'bob')
47+
alice = Fabricate(:account, username: 'alice')
48+
foo = Fabricate(:account)
49+
author = Fabricate(:account, username: 'author', silenced: true)
50+
status = Fabricate(:status, visibility: :direct, account: author)
51+
bob.follow!(author)
52+
FollowRequest.create!(account: foo, target_account: author)
53+
status.mentions.create(account: alice)
54+
status.mentions.create(account: bob)
55+
status.mentions.create(account: foo)
56+
expect(subject.to(status)).to include(subject.uri_for(bob))
57+
expect(subject.to(status)).to include(subject.uri_for(foo))
58+
expect(subject.to(status)).to_not include(subject.uri_for(alice))
59+
end
4460
end
4561

4662
describe '#cc' do
@@ -70,6 +86,22 @@
7086
status.mentions.create(account: mentioned)
7187
expect(subject.cc(status)).to include(subject.uri_for(mentioned))
7288
end
89+
90+
it "returns URIs of mentions for silenced author's non-direct status only if they are followers or requesting to be" do
91+
bob = Fabricate(:account, username: 'bob')
92+
alice = Fabricate(:account, username: 'alice')
93+
foo = Fabricate(:account)
94+
author = Fabricate(:account, username: 'author', silenced: true)
95+
status = Fabricate(:status, visibility: :public, account: author)
96+
bob.follow!(author)
97+
FollowRequest.create!(account: foo, target_account: author)
98+
status.mentions.create(account: alice)
99+
status.mentions.create(account: bob)
100+
status.mentions.create(account: foo)
101+
expect(subject.cc(status)).to include(subject.uri_for(bob))
102+
expect(subject.cc(status)).to include(subject.uri_for(foo))
103+
expect(subject.cc(status)).to_not include(subject.uri_for(alice))
104+
end
73105
end
74106

75107
describe '#local_uri?' do

spec/services/process_mentions_service_spec.rb

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
require 'rails_helper'
22

33
RSpec.describe ProcessMentionsService, type: :service do
4-
let(:account) { Fabricate(:account, username: 'alice') }
5-
let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct}") }
4+
let(:account) { Fabricate(:account, username: 'alice') }
5+
let(:visibility) { :public }
6+
let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct}", visibility: visibility) }
67

7-
context 'OStatus' do
8+
context 'OStatus with public toot' do
89
let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') }
910

1011
subject { ProcessMentionsService.new }
@@ -23,6 +24,26 @@
2324
end
2425
end
2526

27+
context 'OStatus with private toot' do
28+
let(:visibility) { :private }
29+
let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') }
30+
31+
subject { ProcessMentionsService.new }
32+
33+
before do
34+
stub_request(:post, remote_user.salmon_url)
35+
subject.call(status)
36+
end
37+
38+
it 'does not create a mention' do
39+
expect(remote_user.mentions.where(status: status).count).to eq 0
40+
end
41+
42+
it 'does not post to remote user\'s Salmon end point' do
43+
expect(a_request(:post, remote_user.salmon_url)).to_not have_been_made
44+
end
45+
end
46+
2647
context 'ActivityPub' do
2748
let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
2849

0 commit comments

Comments
 (0)