diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb index 29411774a1..0c98651d12 100644 --- a/app/lib/activitypub/activity.rb +++ b/app/lib/activitypub/activity.rb @@ -130,12 +130,7 @@ class ActivityPub::Activity def first_mentioned_local_account audience = (as_array(@json['to']) + as_array(@json['cc'])).map { |x| value_or_id(x) }.uniq - local_usernames = audience.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) } - .map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) } - - return if local_usernames.empty? - - Account.local.where(username: local_usernames).first + ActivityPub::TagManager.instance.uris_to_local_accounts(audience).first end def first_local_follower diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index f54e64ad7e..4b2549ba96 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -412,11 +412,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity def addresses_local_accounts? return true if @options[:delivered_to_account_id] - local_usernames = (audience_to + audience_cc).uniq.select { |uri| ActivityPub::TagManager.instance.local_uri?(uri) }.map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username) } - - return false if local_usernames.empty? - - Account.local.exists?(username: local_usernames) + ActivityPub::TagManager.instance.uris_to_local_accounts((audience_to + audience_cc).uniq).exists? end def tombstone_exists? diff --git a/app/lib/activitypub/tag_manager.rb b/app/lib/activitypub/tag_manager.rb index 5cba9a8006..2fe707e79b 100644 --- a/app/lib/activitypub/tag_manager.rb +++ b/app/lib/activitypub/tag_manager.rb @@ -203,6 +203,19 @@ class ActivityPub::TagManager path_params[param] end + def uris_to_local_accounts(uris) + usernames = [] + ids = [] + + uris.each do |uri| + param, value = uri_to_local_account_params(uri) + usernames << value.downcase if param == :username + ids << value if param == :id + end + + Account.local.with_username(usernames).or(Account.local.where(id: ids)) + end + def uri_to_actor(uri) uri_to_resource(uri, Account) end @@ -213,7 +226,7 @@ class ActivityPub::TagManager if local_uri?(uri) case klass.name when 'Account' - klass.find_local(uri_to_local_id(uri, :username)) + uris_to_local_accounts([uri]).first else StatusFinder.new(uri).status end @@ -225,4 +238,20 @@ class ActivityPub::TagManager rescue ActiveRecord::RecordNotFound nil end + + private + + def uri_to_local_account_params(uri) + return unless local_uri?(uri) + + path_params = Rails.application.routes.recognize_path(uri) + + # TODO: handle numeric IDs + case path_params[:controller] + when 'accounts' + [:username, path_params[:username]] + when 'instance_actors' + [:id, -99] + end + end end diff --git a/app/services/activitypub/synchronize_followers_service.rb b/app/services/activitypub/synchronize_followers_service.rb index 5b58a025cb..fd6fd1b899 100644 --- a/app/services/activitypub/synchronize_followers_service.rb +++ b/app/services/activitypub/synchronize_followers_service.rb @@ -30,10 +30,7 @@ class ActivityPub::SynchronizeFollowersService < BaseService # Account record, and should we not do that, we should have sent a Delete. # In any case there is not much we can do if that occurs. - # TODO: this will need changes when switching to numeric IDs - - usernames = items.filter_map { |uri| ActivityPub::TagManager.instance.uri_to_local_id(uri, :username)&.downcase } - Account.local.with_username(usernames) + ActivityPub::TagManager.instance.uris_to_local_accounts(items) end def remove_unexpected_local_followers! diff --git a/spec/lib/activitypub/tag_manager_spec.rb b/spec/lib/activitypub/tag_manager_spec.rb index 4dcfc69824..7a4cf3c1b8 100644 --- a/spec/lib/activitypub/tag_manager_spec.rb +++ b/spec/lib/activitypub/tag_manager_spec.rb @@ -187,6 +187,23 @@ RSpec.describe ActivityPub::TagManager do end end + describe '#uris_to_local_accounts' do + it 'returns the expected local accounts' do + account = Fabricate(:account) + expect(subject.uris_to_local_accounts([subject.uri_for(account), instance_actor_url])).to contain_exactly(account, Account.representative) + end + + it 'does not return remote accounts' do + account = Fabricate(:account, uri: 'https://example.com/123', domain: 'example.com') + expect(subject.uris_to_local_accounts([subject.uri_for(account)])).to be_empty + end + + it 'does not return an account for a local post' do + status = Fabricate(:status) + expect(subject.uris_to_local_accounts([subject.uri_for(status)])).to be_empty + end + end + describe '#uri_to_resource' do it 'returns the local account' do account = Fabricate(:account)