Skip to content
Snippets Groups Projects
Commit f29918e7 authored by ThibG's avatar ThibG Committed by Eugen Rochko
Browse files

[WiP] Whenever a remote keypair changes, unfollow them and re-subscribe to … (#4907)

* Whenever a remote keypair changes, unfollow them and re-subscribe to them

In Mastodon (it could be different for other OStatus or AP-enabled software),
a keypair change is indicative of whole user (or instance) data loss. In this
situation, the “new” user might be different, and almost certainly has an empty
followers list. In this case, Mastodon instances will disagree on follower
lists, leading to unreliable delivery and “shadow followers”, that is users
believed by a remote instance to be followers, without the affected user
knowing.

Drawbacks of this change are:
1. If an user legitimately changes public key for some reason without losing
   data (not possible in Mastodon at the moment), they will have their remote
   followers unsubscribed/re-subscribed needlessly.
2. Depending of the number of remote followers, this may generate quite some
   traffic.
3. If the user change is an attempt at usurpation, the remote followers will
   unknowingly follow the usurper. Note that this is *not* a change of
   behavior, Mastodon already behaves like that, although delivery might be
   unreliable, and the usurper would not have known the former user's
   followers.

* Rename ResubscribeWorker to RefollowWorker

* Process followers in batches
parent af10c9fb
No related branches found
No related tags found
No related merge requests found
...@@ -17,7 +17,9 @@ class ActivityPub::ProcessAccountService < BaseService ...@@ -17,7 +17,9 @@ class ActivityPub::ProcessAccountService < BaseService
create_account if @account.nil? create_account if @account.nil?
upgrade_account if @account.ostatus? upgrade_account if @account.ostatus?
old_public_key = @account.public_key
update_account update_account
RefollowWorker.perform_async(@account.id) if old_public_key != @account.public_key
@account @account
rescue Oj::ParseError rescue Oj::ParseError
......
...@@ -85,8 +85,10 @@ class ResolveRemoteAccountService < BaseService ...@@ -85,8 +85,10 @@ class ResolveRemoteAccountService < BaseService
def handle_ostatus def handle_ostatus
create_account if @account.nil? create_account if @account.nil?
old_public_key = @account.public_key
update_account update_account
update_account_profile if update_profile? update_account_profile if update_profile?
RefollowWorker.perform_async(@account.id) if old_public_key != @account.public_key
end end
def update_profile? def update_profile?
......
# frozen_string_literal: true
class RefollowWorker
include Sidekiq::Worker
sidekiq_options queue: 'pull', retry: false
def perform(target_account_id)
target_account = Account.find(target_account_id)
target_account.followers.where(domain: nil).find_each do |follower|
# Locally unfollow remote account
follower.unfollow!(target_account)
# Schedule re-follow
begin
FollowService.new.call(follower, target_account)
rescue Mastodon::NotPermittedError, ActiveRecord::RecordNotFound, Mastodon::UnexpectedResponseError, HTTP::Error, OpenSSL::SSL::SSLError
next
end
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment