* Add tests * Ensure deleted statuses are marked as such * Save some redis memory by not storing URIs in delete_upon_arrival values * Avoid possible race condition when processing incoming Deletes * Avoid potential duplicate Delete forwards * Lower lock durations to reduce issues in case of hard crash of the Rails process * Check for `lock.aquired?` and improve comment * Refactor RedisLock usage in app/lib/activitypub * Fix using incorrect or non-existent sender for relaying Deletes
		
			
				
	
	
		
			86 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			86 lines
		
	
	
	
		
			2.5 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| class ActivityPub::Activity::Delete < ActivityPub::Activity
 | |
|   def perform
 | |
|     if @account.uri == object_uri
 | |
|       delete_person
 | |
|     else
 | |
|       delete_note
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   private
 | |
| 
 | |
|   def delete_person
 | |
|     lock_or_return("delete_in_progress:#{@account.id}") do
 | |
|       DeleteAccountService.new.call(@account, reserve_username: false, skip_activitypub: true)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def delete_note
 | |
|     return if object_uri.nil?
 | |
| 
 | |
|     lock_or_return("delete_status_in_progress:#{object_uri}", 5.minutes.seconds) do
 | |
|       unless invalid_origin?(object_uri)
 | |
|         # This lock ensures a concurrent `ActivityPub::Activity::Create` either
 | |
|         # does not create a status at all, or has finished saving it to the
 | |
|         # database before we try to load it.
 | |
|         # Without the lock, `delete_later!` could be called after `delete_arrived_first?`
 | |
|         # and `Status.find` before `Status.create!`
 | |
|         lock_or_fail("create:#{object_uri}") { delete_later!(object_uri) }
 | |
| 
 | |
|         Tombstone.find_or_create_by(uri: object_uri, account: @account)
 | |
|       end
 | |
| 
 | |
|       @status   = Status.find_by(uri: object_uri, account: @account)
 | |
|       @status ||= Status.find_by(uri: @object['atomUri'], account: @account) if @object.is_a?(Hash) && @object['atomUri'].present?
 | |
| 
 | |
|       return if @status.nil?
 | |
| 
 | |
|       forward! if @json['signature'].present? && @status.distributable?
 | |
|       delete_now!
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def rebloggers_ids
 | |
|     return @rebloggers_ids if defined?(@rebloggers_ids)
 | |
|     @rebloggers_ids = @status.reblogs.includes(:account).references(:account).merge(Account.local).pluck(:account_id)
 | |
|   end
 | |
| 
 | |
|   def inboxes_for_reblogs
 | |
|     Account.where(id: ::Follow.where(target_account_id: rebloggers_ids).select(:account_id)).inboxes
 | |
|   end
 | |
| 
 | |
|   def replied_to_status
 | |
|     return @replied_to_status if defined?(@replied_to_status)
 | |
|     @replied_to_status = @status.thread
 | |
|   end
 | |
| 
 | |
|   def reply_to_local?
 | |
|     !replied_to_status.nil? && replied_to_status.account.local?
 | |
|   end
 | |
| 
 | |
|   def inboxes_for_reply
 | |
|     replied_to_status.account.followers.inboxes
 | |
|   end
 | |
| 
 | |
|   def forward!
 | |
|     inboxes = inboxes_for_reblogs
 | |
|     inboxes += inboxes_for_reply if reply_to_local?
 | |
|     inboxes -= [@account.preferred_inbox_url]
 | |
| 
 | |
|     sender_id = reply_to_local? ? replied_to_status.account_id : rebloggers_ids.first
 | |
| 
 | |
|     ActivityPub::LowPriorityDeliveryWorker.push_bulk(inboxes.uniq) do |inbox_url|
 | |
|       [payload, sender_id, inbox_url]
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def delete_now!
 | |
|     RemoveStatusService.new.call(@status, redraft: false)
 | |
|   end
 | |
| 
 | |
|   def payload
 | |
|     @payload ||= Oj.dump(@json)
 | |
|   end
 | |
| end
 |