about summary refs log tree commit diff
path: root/app/lib/activitypub/activity
diff options
context:
space:
mode:
authorThibG <thib@sitedethib.com>2020-07-22 15:39:36 +0200
committerGitHub <noreply@github.com>2020-07-22 15:39:36 +0200
commit4024952b58bacb94d2cb43fafddf0e97bea4c55c (patch)
treeb1c1e5cdb84606879d65ecceebe4cf665332379b /app/lib/activitypub/activity
parent801e546ecc1efb4103232d8265229eb455a8dd5b (diff)
parentf8e315cd74d05a6878bbd018b20462daa0b5e660 (diff)
Merge pull request #1385 from ThibG/glitch-soc/merge-upstream
Merge upstream changes
Diffstat (limited to 'app/lib/activitypub/activity')
-rw-r--r--app/lib/activitypub/activity/announce.rb39
-rw-r--r--app/lib/activitypub/activity/block.rb7
-rw-r--r--app/lib/activitypub/activity/create.rb2
-rw-r--r--app/lib/activitypub/activity/undo.rb51
-rw-r--r--app/lib/activitypub/activity/update.rb2
5 files changed, 86 insertions, 15 deletions
diff --git a/app/lib/activitypub/activity/announce.rb b/app/lib/activitypub/activity/announce.rb
index 34c646668..9e108985a 100644
--- a/app/lib/activitypub/activity/announce.rb
+++ b/app/lib/activitypub/activity/announce.rb
@@ -4,25 +4,32 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
   def perform
     return reject_payload! if delete_arrived_first?(@json['id']) || !related_to_local_activity?
 
-    original_status = status_from_object
+    RedisLock.acquire(lock_options) do |lock|
+      if lock.acquired?
+        original_status = status_from_object
 
-    return reject_payload! if original_status.nil? || !announceable?(original_status)
+        return reject_payload! if original_status.nil? || !announceable?(original_status)
 
-    status = Status.find_by(account: @account, reblog: original_status)
+        @status = Status.find_by(account: @account, reblog: original_status)
 
-    return status unless status.nil?
+        return @status unless @status.nil?
 
-    status = Status.create!(
-      account: @account,
-      reblog: original_status,
-      uri: @json['id'],
-      created_at: @json['published'],
-      override_timestamps: @options[:override_timestamps],
-      visibility: visibility_from_audience
-    )
+        @status = Status.create!(
+          account: @account,
+          reblog: original_status,
+          uri: @json['id'],
+          created_at: @json['published'],
+          override_timestamps: @options[:override_timestamps],
+          visibility: visibility_from_audience
+        )
 
-    distribute(status)
-    status
+        distribute(@status)
+      else
+        raise Mastodon::RaceConditionError
+      end
+    end
+
+    @status
   end
 
   private
@@ -54,4 +61,8 @@ class ActivityPub::Activity::Announce < ActivityPub::Activity
   def reblog_of_local_status?
     status_from_uri(object_uri)&.account&.local?
   end
+
+  def lock_options
+    { redis: Redis.current, key: "announce:#{@object['id']}" }
+  end
 end
diff --git a/app/lib/activitypub/activity/block.rb b/app/lib/activitypub/activity/block.rb
index a17a2d50a..90477bf33 100644
--- a/app/lib/activitypub/activity/block.rb
+++ b/app/lib/activitypub/activity/block.rb
@@ -4,7 +4,12 @@ class ActivityPub::Activity::Block < ActivityPub::Activity
   def perform
     target_account = account_from_uri(object_uri)
 
-    return if target_account.nil? || !target_account.local? || @account.blocking?(target_account)
+    return if target_account.nil? || !target_account.local?
+
+    if @account.blocking?(target_account)
+      @account.block_relationships.find_by(target_account: target_account).update(uri: @json['id']) if @json['id'].present?
+      return
+    end
 
     UnfollowService.new.call(target_account, @account) if target_account.following?(@account)
 
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb
index e81452e3c..08dd98e94 100644
--- a/app/lib/activitypub/activity/create.rb
+++ b/app/lib/activitypub/activity/create.rb
@@ -2,6 +2,8 @@
 
 class ActivityPub::Activity::Create < ActivityPub::Activity
   def perform
+    dereference_object!
+
     case @object['type']
     when 'EncryptedMessage'
       create_encrypted_message
diff --git a/app/lib/activitypub/activity/undo.rb b/app/lib/activitypub/activity/undo.rb
index 599823c6e..9eff1b71c 100644
--- a/app/lib/activitypub/activity/undo.rb
+++ b/app/lib/activitypub/activity/undo.rb
@@ -13,11 +13,62 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
       undo_like
     when 'Block'
       undo_block
+    when nil
+      handle_reference
     end
   end
 
   private
 
+  def handle_reference
+    # Some implementations do not inline the object, and as we don't have a
+    # global index, we have to guess what object it is.
+    return if object_uri.nil?
+
+    try_undo_announce || try_undo_accept || try_undo_follow || try_undo_like || try_undo_block || delete_later!(object_uri)
+  end
+
+  def try_undo_announce
+    status = Status.where.not(reblog_of_id: nil).find_by(uri: object_uri, account: @account)
+    if status.present?
+      RemoveStatusService.new.call(status)
+      true
+    else
+      false
+    end
+  end
+
+  def try_undo_accept
+    # We can't currently handle `Undo Accept` as we don't record `Accept`'s uri
+    false
+  end
+
+  def try_undo_follow
+    follow = @account.follow_requests.find_by(uri: object_uri) || @account.active_relationships.find_by(uri: object_uri)
+
+    if follow.present?
+      follow.destroy
+      true
+    else
+      false
+    end
+  end
+
+  def try_undo_like
+    # There is an index on accounts, but an account may have *many* favs, so this may be too costly
+    false
+  end
+
+  def try_undo_block
+    block = @account.block_relationships.find_by(uri: object_uri)
+    if block.present?
+      UnblockService.new.call(@account, block.target_account)
+      true
+    else
+      false
+    end
+  end
+
   def undo_announce
     return if object_uri.nil?
 
diff --git a/app/lib/activitypub/activity/update.rb b/app/lib/activitypub/activity/update.rb
index 70035325b..018e2df54 100644
--- a/app/lib/activitypub/activity/update.rb
+++ b/app/lib/activitypub/activity/update.rb
@@ -4,6 +4,8 @@ class ActivityPub::Activity::Update < ActivityPub::Activity
   SUPPORTED_TYPES = %w(Application Group Organization Person Service).freeze
 
   def perform
+    dereference_object!
+
     if equals_or_includes_any?(@object['type'], SUPPORTED_TYPES)
       update_account
     elsif equals_or_includes_any?(@object['type'], %w(Question))