mirror of
https://github.com/glitch-soc/mastodon.git
synced 2026-03-29 03:00:33 +02:00
Only persist a collection item's approval URI once it is verified (#38255)
This commit is contained in:
@@ -29,7 +29,7 @@ class CollectionItem < ApplicationRecord
|
|||||||
|
|
||||||
validates :position, numericality: { only_integer: true, greater_than: 0 }
|
validates :position, numericality: { only_integer: true, greater_than: 0 }
|
||||||
validates :activity_uri, presence: true, if: :local_item_with_remote_account?
|
validates :activity_uri, presence: true, if: :local_item_with_remote_account?
|
||||||
validates :approval_uri, presence: true, unless: -> { local? || account&.local? }
|
validates :approval_uri, presence: true, unless: -> { local? || account&.local? || !accepted? }
|
||||||
validates :account, presence: true, if: :accepted?
|
validates :account, presence: true, if: :accepted?
|
||||||
validates :object_uri, presence: true, if: -> { account.nil? }
|
validates :object_uri, presence: true, if: -> { account.nil? }
|
||||||
validates :uri, presence: true, if: :remote_item_with_remote_account?
|
validates :uri, presence: true, if: :remote_item_with_remote_account?
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ class ActivityPub::ProcessFeaturedItemService
|
|||||||
else
|
else
|
||||||
@collection_item = collection.collection_items.create!(
|
@collection_item = collection.collection_items.create!(
|
||||||
uri: item_json['id'],
|
uri: item_json['id'],
|
||||||
object_uri: item_json['featuredObject'],
|
object_uri: item_json['featuredObject']
|
||||||
approval_uri: item_json['featureAuthorization']
|
|
||||||
)
|
)
|
||||||
|
@approval_uri = item_json['featureAuthorization']
|
||||||
|
|
||||||
verify_authorization!
|
verify_authorization!
|
||||||
end
|
end
|
||||||
@@ -35,8 +35,8 @@ class ActivityPub::ProcessFeaturedItemService
|
|||||||
private
|
private
|
||||||
|
|
||||||
def verify_authorization!
|
def verify_authorization!
|
||||||
ActivityPub::VerifyFeaturedItemService.new.call(@collection_item)
|
ActivityPub::VerifyFeaturedItemService.new.call(@collection_item, @approval_uri)
|
||||||
rescue Mastodon::RecursionLimitExceededError, Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
rescue Mastodon::RecursionLimitExceededError, Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
|
||||||
ActivityPub::VerifyFeaturedItemWorker.perform_in(rand(30..600).seconds, @collection_item.id)
|
ActivityPub::VerifyFeaturedItemWorker.perform_in(rand(30..600).seconds, @collection_item.id, @approval_uri)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,23 +3,23 @@
|
|||||||
class ActivityPub::VerifyFeaturedItemService
|
class ActivityPub::VerifyFeaturedItemService
|
||||||
include JsonLdHelper
|
include JsonLdHelper
|
||||||
|
|
||||||
def call(collection_item)
|
def call(collection_item, approval_uri)
|
||||||
@collection_item = collection_item
|
@collection_item = collection_item
|
||||||
@authorization = fetch_resource(@collection_item.approval_uri, true, raise_on_error: :temporary)
|
@authorization = fetch_resource(approval_uri, true, raise_on_error: :temporary)
|
||||||
|
|
||||||
if @authorization.nil?
|
if @authorization.nil?
|
||||||
@collection_item.update!(state: :rejected)
|
@collection_item.update!(state: :rejected)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
return if non_matching_uri_hosts?(@collection_item.approval_uri, @authorization['interactionTarget'])
|
return if non_matching_uri_hosts?(approval_uri, @authorization['interactionTarget'])
|
||||||
return unless matching_type? && matching_collection_uri?
|
return unless matching_type? && matching_collection_uri?
|
||||||
|
|
||||||
account = Account.where(uri: @collection_item.object_uri).first
|
account = Account.where(uri: @collection_item.object_uri).first
|
||||||
account ||= ActivityPub::FetchRemoteAccountService.new.call(@collection_item.object_uri)
|
account ||= ActivityPub::FetchRemoteAccountService.new.call(@collection_item.object_uri)
|
||||||
return if account.blank?
|
return if account.blank?
|
||||||
|
|
||||||
@collection_item.update!(account:, state: :accepted)
|
@collection_item.update!(account:, approval_uri:, state: :accepted)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ class ActivityPub::VerifyFeaturedItemWorker
|
|||||||
|
|
||||||
sidekiq_options queue: 'pull', retry: 5
|
sidekiq_options queue: 'pull', retry: 5
|
||||||
|
|
||||||
def perform(collection_item_id)
|
def perform(collection_item_id, approval_uri)
|
||||||
collection_item = CollectionItem.find(collection_item_id)
|
collection_item = CollectionItem.find(collection_item_id)
|
||||||
|
|
||||||
ActivityPub::VerifyFeaturedItemService.new.call(collection_item)
|
ActivityPub::VerifyFeaturedItemService.new.call(collection_item, approval_uri)
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
# Do nothing
|
# Do nothing
|
||||||
nil
|
nil
|
||||||
|
|||||||
@@ -11,6 +11,5 @@ Fabricator(:unverified_remote_collection_item, from: :collection_item) do
|
|||||||
account nil
|
account nil
|
||||||
state :pending
|
state :pending
|
||||||
object_uri { Fabricate.build(:remote_account).uri }
|
object_uri { Fabricate.build(:remote_account).uri }
|
||||||
approval_uri { sequence(:uri) { |i| "https://example.com/authorizations/#{i}" } }
|
|
||||||
uri { sequence(:uri) { |i| "https://example.com/collection_items/#{i}" } }
|
uri { sequence(:uri) { |i| "https://example.com/collection_items/#{i}" } }
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ RSpec.describe ActivityPub::ProcessFeaturedItemService do
|
|||||||
|
|
||||||
new_item = collection.collection_items.last
|
new_item = collection.collection_items.last
|
||||||
expect(new_item.object_uri).to eq 'https://example.com/actor/1'
|
expect(new_item.object_uri).to eq 'https://example.com/actor/1'
|
||||||
expect(new_item.approval_uri).to eq 'https://example.com/auth/1'
|
expect(new_item.approval_uri).to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when an item exists for a local featured account' do
|
context 'when an item exists for a local featured account' do
|
||||||
@@ -93,7 +93,7 @@ RSpec.describe ActivityPub::ProcessFeaturedItemService do
|
|||||||
|
|
||||||
new_item = collection.collection_items.last
|
new_item = collection.collection_items.last
|
||||||
expect(new_item.object_uri).to eq 'https://example.com/actor/1'
|
expect(new_item.object_uri).to eq 'https://example.com/actor/1'
|
||||||
expect(new_item.approval_uri).to eq 'https://example.com/auth/1'
|
expect(new_item.approval_uri).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ RSpec.describe ActivityPub::VerifyFeaturedItemService do
|
|||||||
account: nil,
|
account: nil,
|
||||||
state: :pending,
|
state: :pending,
|
||||||
uri: 'https://other.example.com/items/1',
|
uri: 'https://other.example.com/items/1',
|
||||||
object_uri: 'https://example.com/actor/1',
|
object_uri: 'https://example.com/actor/1')
|
||||||
approval_uri: verification_json['id'])
|
|
||||||
end
|
end
|
||||||
|
let(:approval_uri) { 'https://example.com/auth/1' }
|
||||||
let(:verification_json) do
|
let(:verification_json) do
|
||||||
{
|
{
|
||||||
'@context' => 'https://www.w3.org/ns/activitystreams',
|
'@context' => 'https://www.w3.org/ns/activitystreams',
|
||||||
'type' => 'FeatureAuthorization',
|
'type' => 'FeatureAuthorization',
|
||||||
'id' => 'https://example.com/auth/1',
|
'id' => approval_uri,
|
||||||
'interactionTarget' => 'https://example.com/actor/1',
|
'interactionTarget' => 'https://example.com/actor/1',
|
||||||
'interactingObject' => collection.uri,
|
'interactingObject' => collection.uri,
|
||||||
}
|
}
|
||||||
@@ -41,12 +41,13 @@ RSpec.describe ActivityPub::VerifyFeaturedItemService do
|
|||||||
before { featured_account }
|
before { featured_account }
|
||||||
|
|
||||||
it 'verifies and creates the item' do
|
it 'verifies and creates the item' do
|
||||||
subject.call(collection_item)
|
subject.call(collection_item, approval_uri)
|
||||||
|
|
||||||
expect(verification_request).to have_been_requested
|
expect(verification_request).to have_been_requested
|
||||||
|
|
||||||
expect(collection_item.account_id).to eq featured_account.id
|
expect(collection_item.account_id).to eq featured_account.id
|
||||||
expect(collection_item).to be_accepted
|
expect(collection_item).to be_accepted
|
||||||
|
expect(collection_item.approval_uri).to eq approval_uri
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -59,13 +60,14 @@ RSpec.describe ActivityPub::VerifyFeaturedItemService do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'fetches the actor and creates the item' do
|
it 'fetches the actor and creates the item' do
|
||||||
subject.call(collection_item)
|
subject.call(collection_item, approval_uri)
|
||||||
|
|
||||||
expect(stubbed_service).to have_received(:call)
|
expect(stubbed_service).to have_received(:call)
|
||||||
expect(verification_request).to have_been_requested
|
expect(verification_request).to have_been_requested
|
||||||
|
|
||||||
expect(collection_item.account_id).to eq featured_account.id
|
expect(collection_item.account_id).to eq featured_account.id
|
||||||
expect(collection_item).to be_accepted
|
expect(collection_item).to be_accepted
|
||||||
|
expect(collection_item.approval_uri).to eq approval_uri
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -77,7 +79,7 @@ RSpec.describe ActivityPub::VerifyFeaturedItemService do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'creates item without attached account and in proper state' do
|
it 'creates item without attached account and in proper state' do
|
||||||
subject.call(collection_item)
|
subject.call(collection_item, approval_uri)
|
||||||
|
|
||||||
expect(collection_item.account_id).to be_nil
|
expect(collection_item.account_id).to be_nil
|
||||||
expect(collection_item).to be_rejected
|
expect(collection_item).to be_rejected
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ RSpec.describe ActivityPub::VerifyFeaturedItemWorker do
|
|||||||
before { stub_service }
|
before { stub_service }
|
||||||
|
|
||||||
it 'sends the status to the service' do
|
it 'sends the status to the service' do
|
||||||
worker.perform(collection_item.id)
|
worker.perform(collection_item.id, 'https://example.com/authorizations/1')
|
||||||
|
|
||||||
expect(service).to have_received(:call).with(collection_item)
|
expect(service).to have_received(:call).with(collection_item, 'https://example.com/authorizations/1')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns nil for non-existent record' do
|
it 'returns nil for non-existent record' do
|
||||||
result = worker.perform(123_123_123)
|
result = worker.perform(123_123_123, 'https://example.com/authorizations/1')
|
||||||
|
|
||||||
expect(result).to be_nil
|
expect(result).to be_nil
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user