Fix unbounded recursion in post discovery (#23506)
* Add a limit to how many posts can get fetched as a result of a single request * Add tests * Always pass `request_id` when processing `Announce` activities --------- Co-authored-by: nametoolong <nametoolong@users.noreply.github.com>
This commit is contained in:
parent
719bb799be
commit
0c9eac80d8
12 changed files with 126 additions and 22 deletions
|
@ -48,7 +48,7 @@ RSpec.describe ActivityPub::Activity::Add do
|
|||
end
|
||||
|
||||
it 'fetches the status and pins it' do
|
||||
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil|
|
||||
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil, request_id: nil|
|
||||
expect(uri).to eq 'https://example.com/unknown'
|
||||
expect(id).to eq true
|
||||
expect(on_behalf_of&.following?(sender)).to eq true
|
||||
|
@ -62,7 +62,7 @@ RSpec.describe ActivityPub::Activity::Add do
|
|||
|
||||
context 'when there is no local follower' do
|
||||
it 'tries to fetch the status' do
|
||||
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil|
|
||||
allow(service_stub).to receive(:call) do |uri, id: true, on_behalf_of: nil, request_id: nil|
|
||||
expect(uri).to eq 'https://example.com/unknown'
|
||||
expect(id).to eq true
|
||||
expect(on_behalf_of).to eq nil
|
||||
|
|
|
@ -223,4 +223,98 @@ RSpec.describe ActivityPub::FetchRemoteStatusService, type: :service do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'statuses referencing other statuses' do
|
||||
before do
|
||||
stub_const 'ActivityPub::FetchRemoteStatusService::DISCOVERIES_PER_REQUEST', 5
|
||||
end
|
||||
|
||||
context 'using inReplyTo' do
|
||||
let(:object) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: "https://foo.bar/@foo/1",
|
||||
type: 'Note',
|
||||
content: 'Lorem ipsum',
|
||||
inReplyTo: 'https://foo.bar/@foo/2',
|
||||
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
8.times do |i|
|
||||
status_json = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: "https://foo.bar/@foo/#{i}",
|
||||
type: 'Note',
|
||||
content: 'Lorem ipsum',
|
||||
inReplyTo: "https://foo.bar/@foo/#{i + 1}",
|
||||
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
|
||||
to: 'as:Public',
|
||||
}.with_indifferent_access
|
||||
stub_request(:get, "https://foo.bar/@foo/#{i}").to_return(status: 200, body: status_json.to_json, headers: { 'Content-Type': 'application/activity+json' })
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates at least some statuses' do
|
||||
expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_least(2)
|
||||
end
|
||||
|
||||
it 'creates no more account than the limit allows' do
|
||||
expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_most(5)
|
||||
end
|
||||
end
|
||||
|
||||
context 'using replies' do
|
||||
let(:object) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: "https://foo.bar/@foo/1",
|
||||
type: 'Note',
|
||||
content: 'Lorem ipsum',
|
||||
replies: {
|
||||
type: 'Collection',
|
||||
id: 'https://foo.bar/@foo/1/replies',
|
||||
first: {
|
||||
type: 'CollectionPage',
|
||||
partOf: 'https://foo.bar/@foo/1/replies',
|
||||
items: ['https://foo.bar/@foo/2'],
|
||||
},
|
||||
},
|
||||
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
|
||||
}
|
||||
end
|
||||
|
||||
before do
|
||||
8.times do |i|
|
||||
status_json = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: "https://foo.bar/@foo/#{i}",
|
||||
type: 'Note',
|
||||
content: 'Lorem ipsum',
|
||||
replies: {
|
||||
type: 'Collection',
|
||||
id: "https://foo.bar/@foo/#{i}/replies",
|
||||
first: {
|
||||
type: 'CollectionPage',
|
||||
partOf: "https://foo.bar/@foo/#{i}/replies",
|
||||
items: ["https://foo.bar/@foo/#{i+1}"],
|
||||
},
|
||||
},
|
||||
attributedTo: ActivityPub::TagManager.instance.uri_for(sender),
|
||||
to: 'as:Public',
|
||||
}.with_indifferent_access
|
||||
stub_request(:get, "https://foo.bar/@foo/#{i}").to_return(status: 200, body: status_json.to_json, headers: { 'Content-Type': 'application/activity+json' })
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates at least some statuses' do
|
||||
expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_least(2)
|
||||
end
|
||||
|
||||
it 'creates no more account than the limit allows' do
|
||||
expect { subject.call(object[:id], prefetched_body: Oj.dump(object)) }.to change { sender.statuses.count }.by_at_most(5)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ RSpec.describe FetchRemoteStatusService, type: :service do
|
|||
end
|
||||
|
||||
context 'protocol is :activitypub' do
|
||||
subject { described_class.new.call(note[:id], prefetched_body) }
|
||||
subject { described_class.new.call(note[:id], prefetched_body: prefetched_body) }
|
||||
let(:prefetched_body) { Oj.dump(note) }
|
||||
|
||||
before do
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue