about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/controllers/accounts_controller.rb7
-rw-r--r--app/controllers/activitypub/inboxes_controller.rb11
-rw-r--r--app/controllers/admin/accounts_controller.rb16
-rw-r--r--app/controllers/api/push_controller.rb73
-rw-r--r--app/controllers/api/salmon_controller.rb37
-rw-r--r--app/controllers/api/subscriptions_controller.rb51
-rw-r--r--app/controllers/concerns/account_controller_concern.rb8
-rw-r--r--app/controllers/concerns/signature_verification.rb2
-rw-r--r--app/controllers/statuses_controller.rb1
-rw-r--r--app/controllers/stream_entries_controller.rb11
-rw-r--r--app/lib/activitypub/activity.rb3
-rw-r--r--app/lib/activitypub/activity/create.rb2
-rw-r--r--app/lib/activitypub/activity/delete.rb1
-rw-r--r--app/lib/activitypub/activity/undo.rb1
-rw-r--r--app/lib/activitypub/adapter.rb3
-rw-r--r--app/lib/bangtags.rb1
-rw-r--r--app/lib/ostatus/activity/base.rb71
-rw-r--r--app/lib/ostatus/activity/creation.rb219
-rw-r--r--app/lib/ostatus/activity/deletion.rb16
-rw-r--r--app/lib/ostatus/activity/general.rb20
-rw-r--r--app/lib/ostatus/activity/post.rb23
-rw-r--r--app/lib/ostatus/activity/remote.rb11
-rw-r--r--app/lib/ostatus/activity/share.rb26
-rw-r--r--app/lib/ostatus/atom_serializer.rb378
-rw-r--r--app/models/account.rb4
-rw-r--r--app/models/form/account_batch.rb2
-rw-r--r--app/models/remote_profile.rb57
-rw-r--r--app/serializers/activitypub/activity_serializer.rb5
-rw-r--r--app/serializers/activitypub/delete_serializer.rb8
-rw-r--r--app/serializers/activitypub/note_serializer.rb15
-rw-r--r--app/serializers/webfinger_serializer.rb3
-rw-r--r--app/services/activitypub/process_account_service.rb12
-rw-r--r--app/services/after_block_domain_from_account_service.rb2
-rw-r--r--app/services/authorize_follow_service.rb10
-rw-r--r--app/services/batched_remove_status_service.rb34
-rw-r--r--app/services/block_service.rb10
-rw-r--r--app/services/concerns/author_extractor.rb23
-rw-r--r--app/services/concerns/stream_entry_renderer.rb7
-rw-r--r--app/services/favourite_service.rb8
-rw-r--r--app/services/fetch_atom_service.rb29
-rw-r--r--app/services/fetch_remote_account_service.rb38
-rw-r--r--app/services/fetch_remote_status_service.rb38
-rw-r--r--app/services/follow_service.rb37
-rw-r--r--app/services/post_status_service.rb1
-rw-r--r--app/services/process_feed_service.rb31
-rw-r--r--app/services/process_hashtags_service.rb5
-rw-r--r--app/services/process_interaction_service.rb151
-rw-r--r--app/services/process_mentions_service.rb15
-rw-r--r--app/services/pubsubhubbub/subscribe_service.rb53
-rw-r--r--app/services/pubsubhubbub/unsubscribe_service.rb31
-rw-r--r--app/services/reblog_service.rb6
-rw-r--r--app/services/reject_follow_service.rb10
-rw-r--r--app/services/remove_status_service.rb17
-rw-r--r--app/services/resolve_account_service.rb123
-rw-r--r--app/services/resolve_url_service.rb25
-rw-r--r--app/services/send_interaction_service.rb39
-rw-r--r--app/services/subscribe_service.rb58
-rw-r--r--app/services/suspend_account_service.rb2
-rw-r--r--app/services/unblock_service.rb10
-rw-r--r--app/services/unfavourite_service.rb11
-rw-r--r--app/services/unfollow_service.rb11
-rw-r--r--app/services/unsubscribe_service.rb36
-rw-r--r--app/services/update_remote_profile_service.rb66
-rw-r--r--app/services/verify_salmon_service.rb26
-rw-r--r--app/views/accounts/show.html.haml3
-rw-r--r--app/views/stream_entries/show.html.haml1
-rw-r--r--app/views/well_known/webfinger/show.xml.ruby16
-rw-r--r--app/workers/activitypub/distribute_poll_update_worker.rb2
-rw-r--r--app/workers/activitypub/post_upgrade_worker.rb15
-rw-r--r--app/workers/notification_worker.rb11
-rw-r--r--app/workers/processing_worker.rb11
-rw-r--r--app/workers/pubsubhubbub/confirmation_worker.rb82
-rw-r--r--app/workers/pubsubhubbub/delivery_worker.rb81
-rw-r--r--app/workers/pubsubhubbub/distribution_worker.rb32
-rw-r--r--app/workers/pubsubhubbub/raw_distribution_worker.rb22
-rw-r--r--app/workers/pubsubhubbub/subscribe_worker.rb34
-rw-r--r--app/workers/pubsubhubbub/unsubscribe_worker.rb15
-rw-r--r--app/workers/refollow_worker.rb1
-rw-r--r--app/workers/remote_profile_update_worker.rb13
-rw-r--r--app/workers/salmon_worker.rb13
-rw-r--r--app/workers/scheduler/subscriptions_scheduler.rb17
81 files changed, 54 insertions, 2376 deletions
diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb
index 5eedbe8c8..ef04333af 100644
--- a/app/controllers/accounts_controller.rb
+++ b/app/controllers/accounts_controller.rb
@@ -32,13 +32,6 @@ class AccountsController < ApplicationController
         end
       end
 
-      format.atom do
-        mark_cacheable!
-
-        @entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id])
-        render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? || entry.status.local_only? }))
-      end
-
       format.rss do
         mark_cacheable!
 
diff --git a/app/controllers/activitypub/inboxes_controller.rb b/app/controllers/activitypub/inboxes_controller.rb
index a0b7532c2..36f837841 100644
--- a/app/controllers/activitypub/inboxes_controller.rb
+++ b/app/controllers/activitypub/inboxes_controller.rb
@@ -10,7 +10,6 @@ class ActivityPub::InboxesController < Api::BaseController
     if unknown_deleted_account?
       head 202
     elsif signed_request_account
-      upgrade_account
       process_payload
       head 202
     else
@@ -38,16 +37,6 @@ class ActivityPub::InboxesController < Api::BaseController
     @body
   end
 
-  def upgrade_account
-    if signed_request_account.ostatus?
-      signed_request_account.update(last_webfingered_at: nil)
-      ResolveAccountWorker.perform_async(signed_request_account.acct)
-    end
-
-    Pubsubhubbub::UnsubscribeWorker.perform_async(signed_request_account.id) if signed_request_account.subscribed?
-    DeliveryFailureTracker.track_inverse_success!(signed_request_account)
-  end
-
   def process_payload
     ActivityPub::ProcessingWorker.perform_async(signed_request_account.id, body, @account&.id)
   end
diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb
index e7795e95c..86bc3c8a2 100644
--- a/app/controllers/admin/accounts_controller.rb
+++ b/app/controllers/admin/accounts_controller.rb
@@ -2,8 +2,8 @@
 
 module Admin
   class AccountsController < BaseController
-    before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :memorialize, :approve, :reject]
-    before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload]
+    before_action :set_account, only: [:show, :redownload, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :memorialize, :approve, :reject]
+    before_action :require_remote_account!, only: [:redownload]
     before_action :require_local_account!, only: [:enable, :memorialize, :approve, :reject]
 
     def index
@@ -19,18 +19,6 @@ module Admin
       @warnings                = @account.targeted_account_warnings.latest.custom
     end
 
-    def subscribe
-      authorize @account, :subscribe?
-      Pubsubhubbub::SubscribeWorker.perform_async(@account.id)
-      redirect_to admin_account_path(@account.id)
-    end
-
-    def unsubscribe
-      authorize @account, :unsubscribe?
-      Pubsubhubbub::UnsubscribeWorker.perform_async(@account.id)
-      redirect_to admin_account_path(@account.id)
-    end
-
     def memorialize
       authorize @account, :memorialize?
       @account.memorialize!
diff --git a/app/controllers/api/push_controller.rb b/app/controllers/api/push_controller.rb
deleted file mode 100644
index e04d19125..000000000
--- a/app/controllers/api/push_controller.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-# frozen_string_literal: true
-
-class Api::PushController < Api::BaseController
-  include SignatureVerification
-
-  def update
-    response, status = process_push_request
-    render plain: response, status: status
-  end
-
-  private
-
-  def process_push_request
-    case hub_mode
-    when 'subscribe'
-      Pubsubhubbub::SubscribeService.new.call(account_from_topic, hub_callback, hub_secret, hub_lease_seconds, verified_domain)
-    when 'unsubscribe'
-      Pubsubhubbub::UnsubscribeService.new.call(account_from_topic, hub_callback)
-    else
-      ["Unknown mode: #{hub_mode}", 422]
-    end
-  end
-
-  def hub_mode
-    params['hub.mode']
-  end
-
-  def hub_topic
-    params['hub.topic']
-  end
-
-  def hub_callback
-    params['hub.callback']
-  end
-
-  def hub_lease_seconds
-    params['hub.lease_seconds']
-  end
-
-  def hub_secret
-    params['hub.secret']
-  end
-
-  def account_from_topic
-    if hub_topic.present? && local_domain? && account_feed_path?
-      Account.find_local(hub_topic_params[:username])
-    end
-  end
-
-  def hub_topic_params
-    @_hub_topic_params ||= Rails.application.routes.recognize_path(hub_topic_uri.path)
-  end
-
-  def hub_topic_uri
-    @_hub_topic_uri ||= Addressable::URI.parse(hub_topic).normalize
-  end
-
-  def local_domain?
-    TagManager.instance.web_domain?(hub_topic_domain)
-  end
-
-  def verified_domain
-    return signed_request_account.domain if signed_request_account
-  end
-
-  def hub_topic_domain
-    hub_topic_uri.host + (hub_topic_uri.port ? ":#{hub_topic_uri.port}" : '')
-  end
-
-  def account_feed_path?
-    hub_topic_params[:controller] == 'accounts' && hub_topic_params[:action] == 'show' && hub_topic_params[:format] == 'atom'
-  end
-end
diff --git a/app/controllers/api/salmon_controller.rb b/app/controllers/api/salmon_controller.rb
deleted file mode 100644
index ac5f3268d..000000000
--- a/app/controllers/api/salmon_controller.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-class Api::SalmonController < Api::BaseController
-  include SignatureVerification
-
-  before_action :set_account
-  respond_to :txt
-
-  def update
-    if verify_payload?
-      process_salmon
-      head 202
-    elsif payload.present?
-      render plain: signature_verification_failure_reason, status: 401
-    else
-      head 400
-    end
-  end
-
-  private
-
-  def set_account
-    @account = Account.find(params[:id])
-  end
-
-  def payload
-    @_payload ||= request.body.read
-  end
-
-  def verify_payload?
-    payload.present? && VerifySalmonService.new.call(payload)
-  end
-
-  def process_salmon
-    SalmonWorker.perform_async(@account.id, payload.force_encoding('UTF-8'))
-  end
-end
diff --git a/app/controllers/api/subscriptions_controller.rb b/app/controllers/api/subscriptions_controller.rb
deleted file mode 100644
index 89007f3d6..000000000
--- a/app/controllers/api/subscriptions_controller.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-class Api::SubscriptionsController < Api::BaseController
-  before_action :set_account
-  respond_to :txt
-
-  def show
-    if subscription.valid?(params['hub.topic'])
-      @account.update(subscription_expires_at: future_expires)
-      render plain: encoded_challenge, status: 200
-    else
-      head 404
-    end
-  end
-
-  def update
-    if subscription.verify(body, request.headers['HTTP_X_HUB_SIGNATURE'])
-      ProcessingWorker.perform_async(@account.id, body.force_encoding('UTF-8'))
-    end
-
-    head 200
-  end
-
-  private
-
-  def subscription
-    @_subscription ||= @account.subscription(
-      api_subscription_url(@account.id)
-    )
-  end
-
-  def body
-    @_body ||= request.body.read
-  end
-
-  def encoded_challenge
-    HTMLEntities.new.encode(params['hub.challenge'])
-  end
-
-  def future_expires
-    Time.now.utc + lease_seconds_or_default
-  end
-
-  def lease_seconds_or_default
-    (params['hub.lease_seconds'] || 1.day).to_i.seconds
-  end
-
-  def set_account
-    @account = Account.find(params[:id])
-  end
-end
diff --git a/app/controllers/concerns/account_controller_concern.rb b/app/controllers/concerns/account_controller_concern.rb
index 9ac50a5ca..e5a041f2f 100644
--- a/app/controllers/concerns/account_controller_concern.rb
+++ b/app/controllers/concerns/account_controller_concern.rb
@@ -30,7 +30,6 @@ module AccountControllerConcern
     response.headers['Link'] = LinkHeader.new(
       [
         webfinger_account_link,
-        atom_account_url_link,
         actor_url_link,
       ]
     )
@@ -47,13 +46,6 @@ module AccountControllerConcern
     ]
   end
 
-  def atom_account_url_link
-    [
-      account_url(@account, format: 'atom'),
-      [%w(rel alternate), %w(type application/atom+xml)],
-    ]
-  end
-
   def actor_url_link
     [
       ActivityPub::TagManager.instance.uri_for(@account),
diff --git a/app/controllers/concerns/signature_verification.rb b/app/controllers/concerns/signature_verification.rb
index 91566c4fa..e7301a620 100644
--- a/app/controllers/concerns/signature_verification.rb
+++ b/app/controllers/concerns/signature_verification.rb
@@ -145,7 +145,7 @@ module SignatureVerification
   end
 
   def account_refresh_key(account)
-    return if account.local? || !account.activitypub?
+    return if account.local?
     ActivityPub::FetchRemoteAccountService.new.call(account.uri, only_key: true)
   end
 end
diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb
index 8618f6e34..3a6f68db5 100644
--- a/app/controllers/statuses_controller.rb
+++ b/app/controllers/statuses_controller.rb
@@ -181,7 +181,6 @@ class StatusesController < ApplicationController
   def set_link_headers
     response.headers['Link'] = LinkHeader.new(
       [
-        [account_stream_entry_url(@account, @status.stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]],
         [ActivityPub::TagManager.instance.uri_for(@status), [%w(rel alternate), %w(type application/activity+json)]],
       ]
     )
diff --git a/app/controllers/stream_entries_controller.rb b/app/controllers/stream_entries_controller.rb
index 1e16c5157..0c749be0e 100644
--- a/app/controllers/stream_entries_controller.rb
+++ b/app/controllers/stream_entries_controller.rb
@@ -12,6 +12,7 @@ class StreamEntriesController < ApplicationController
   before_action :check_account_suspension
   before_action :set_cache_headers
 
+
   def show
     respond_to do |format|
       format.html do
@@ -24,15 +25,6 @@ class StreamEntriesController < ApplicationController
 
         redirect_to short_account_status_url(params[:account_username], @stream_entry.activity) if @type == 'status'
       end
-
-      format.atom do
-        unless @stream_entry.hidden?
-          skip_session!
-          expires_in 3.minutes, public: true
-        end
-
-        render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(@stream_entry, true))
-      end
     end
   end
 
@@ -49,7 +41,6 @@ class StreamEntriesController < ApplicationController
   def set_link_headers
     response.headers['Link'] = LinkHeader.new(
       [
-        [account_stream_entry_url(@account, @stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]],
         [ActivityPub::TagManager.instance.uri_for(@stream_entry.activity), [%w(rel alternate), %w(type application/activity+json)]],
       ]
     )
diff --git a/app/lib/activitypub/activity.rb b/app/lib/activitypub/activity.rb
index 54b175613..844a39e99 100644
--- a/app/lib/activitypub/activity.rb
+++ b/app/lib/activitypub/activity.rb
@@ -119,8 +119,7 @@ class ActivityPub::Activity
   def crawl_links(status)
     return if status.spoiler_text?
 
-    # Spread out crawling randomly to avoid DDoSing the link
-    LinkCrawlWorker.perform_in(rand(1..59).seconds, status.id)
+    LinkCrawlWorker.perform_async(status.id)
   end
 
   def distribute_to_followers(status)
diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb
index d52ec0e86..df735a7bf 100644
--- a/app/lib/activitypub/activity/create.rb
+++ b/app/lib/activitypub/activity/create.rb
@@ -47,8 +47,6 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
 
   def find_existing_status
     status   = status_from_uri(object_uri)
-    status ||= Status.find_by(uri: @object['atomUri']) if @object['atomUri'].present?
-    status
   end
 
   def process_status_params
diff --git a/app/lib/activitypub/activity/delete.rb b/app/lib/activitypub/activity/delete.rb
index 4236af071..bf530ac49 100644
--- a/app/lib/activitypub/activity/delete.rb
+++ b/app/lib/activitypub/activity/delete.rb
@@ -27,7 +27,6 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
     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?
 
diff --git a/app/lib/activitypub/activity/undo.rb b/app/lib/activitypub/activity/undo.rb
index 599823c6e..271f4e2b5 100644
--- a/app/lib/activitypub/activity/undo.rb
+++ b/app/lib/activitypub/activity/undo.rb
@@ -22,7 +22,6 @@ class ActivityPub::Activity::Undo < ActivityPub::Activity
     return if object_uri.nil?
 
     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?
 
     if status.nil?
       delete_later!(object_uri)
diff --git a/app/lib/activitypub/adapter.rb b/app/lib/activitypub/adapter.rb
index c259c96f4..9d940e4ef 100644
--- a/app/lib/activitypub/adapter.rb
+++ b/app/lib/activitypub/adapter.rb
@@ -15,8 +15,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
     emoji: { 'toot' => 'http://joinmastodon.org/ns#', 'Emoji' => 'toot:Emoji' },
     featured: { 'toot' => 'http://joinmastodon.org/ns#', 'featured' => { '@id' => 'toot:featured', '@type' => '@id' } },
     property_value: { 'schema' => 'http://schema.org#', 'PropertyValue' => 'schema:PropertyValue', 'value' => 'schema:value' },
-    atom_uri: { 'ostatus' => 'http://ostatus.org#', 'atomUri' => 'ostatus:atomUri' },
-    conversation: { 'ostatus' => 'http://ostatus.org#', 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri', 'conversation' => 'ostatus:conversation' },
+    conversation: { 'ostatus' => 'http://ostatus.org#', 'conversation' => 'ostatus:conversation' },
     focal_point: { 'toot' => 'http://joinmastodon.org/ns#', 'focalPoint' => { '@container' => '@list', '@id' => 'toot:focalPoint' } },
     identity_proof: { 'toot' => 'http://joinmastodon.org/ns#', 'IdentityProof' => 'toot:IdentityProof' },
     blurhash: { 'toot' => 'http://joinmastodon.org/ns#', 'blurhash' => 'toot:blurhash' },
diff --git a/app/lib/bangtags.rb b/app/lib/bangtags.rb
index 9bcea41df..01ad38f61 100644
--- a/app/lib/bangtags.rb
+++ b/app/lib/bangtags.rb
@@ -498,7 +498,6 @@ class Bangtags
       case post_cmd[0]
       when 'mention'
         mention = @account.mentions.where(status: status).first_or_create(status: status)
-        LocalNotificationWorker.perform_async(@account.id, mention.id, mention.class.name)
       end
     end
   end
diff --git a/app/lib/ostatus/activity/base.rb b/app/lib/ostatus/activity/base.rb
deleted file mode 100644
index db70f1998..000000000
--- a/app/lib/ostatus/activity/base.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Base
-  include Redisable
-
-  def initialize(xml, account = nil, **options)
-    @xml     = xml
-    @account = account
-    @options = options
-  end
-
-  def status?
-    [:activity, :note, :comment].include?(type)
-  end
-
-  def verb
-    raw = @xml.at_xpath('./activity:verb', activity: OStatus::TagManager::AS_XMLNS).content
-    OStatus::TagManager::VERBS.key(raw)
-  rescue
-    :post
-  end
-
-  def type
-    raw = @xml.at_xpath('./activity:object-type', activity: OStatus::TagManager::AS_XMLNS).content
-    OStatus::TagManager::TYPES.key(raw)
-  rescue
-    :activity
-  end
-
-  def id
-    @xml.at_xpath('./xmlns:id', xmlns: OStatus::TagManager::XMLNS).content
-  end
-
-  def url
-    link = @xml.xpath('./xmlns:link[@rel="alternate"]', xmlns: OStatus::TagManager::XMLNS).find { |link_candidate| link_candidate['type'] == 'text/html' }
-    link.nil? ? nil : link['href']
-  end
-
-  def activitypub_uri
-    link = @xml.xpath('./xmlns:link[@rel="alternate"]', xmlns: OStatus::TagManager::XMLNS).find { |link_candidate| ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(link_candidate['type']) }
-    link.nil? ? nil : link['href']
-  end
-
-  def activitypub_uri?
-    activitypub_uri.present?
-  end
-
-  private
-
-  def find_status(uri)
-    if OStatus::TagManager.instance.local_id?(uri)
-      local_id = OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Status')
-      return Status.find_by(id: local_id)
-    elsif ActivityPub::TagManager.instance.local_uri?(uri)
-      local_id = ActivityPub::TagManager.instance.uri_to_local_id(uri)
-      return Status.find_by(id: local_id)
-    end
-
-    Status.find_by(uri: uri)
-  end
-
-  def find_activitypub_status(uri, href)
-    tag_matches = /tag:([^,:]+)[^:]*:objectId=([\d]+)/.match(uri)
-    href_matches = %r{/users/([^/]+)}.match(href)
-
-    unless tag_matches.nil? || href_matches.nil?
-      uri = "https://#{tag_matches[1]}/users/#{href_matches[1]}/statuses/#{tag_matches[2]}"
-      Status.find_by(uri: uri)
-    end
-  end
-end
diff --git a/app/lib/ostatus/activity/creation.rb b/app/lib/ostatus/activity/creation.rb
deleted file mode 100644
index 8dd066cb9..000000000
--- a/app/lib/ostatus/activity/creation.rb
+++ /dev/null
@@ -1,219 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Creation < OStatus::Activity::Base
-  def perform
-    if redis.exists("delete_upon_arrival:#{@account.id}:#{id}")
-      Rails.logger.debug "Delete for status #{id} was queued, ignoring"
-      return [nil, false]
-    end
-
-    return [nil, false] if @account.suspended? || invalid_origin?
-
-    RedisLock.acquire(lock_options) do |lock|
-      if lock.acquired?
-        # Return early if status already exists in db
-        @status = find_status(id)
-        return [@status, false] unless @status.nil?
-        @status = process_status
-      else
-        raise Mastodon::RaceConditionError
-      end
-    end
-
-    [@status, true]
-  end
-
-  def process_status
-    Rails.logger.debug "Creating remote status #{id}"
-    cached_reblog = reblog
-    status = nil
-
-    # Skip if the reblogged status is not public
-    return if cached_reblog && !(cached_reblog.public_visibility? || cached_reblog.unlisted_visibility?)
-
-    media_attachments = save_media.take(6)
-
-    ApplicationRecord.transaction do
-      status = Status.create!(
-        uri: id,
-        url: url,
-        account: @account,
-        reblog: cached_reblog,
-        text: content,
-        spoiler_text: content_warning,
-        created_at: published,
-        override_timestamps: @options[:override_timestamps],
-        reply: thread?,
-        language: content_language,
-        visibility: visibility_scope,
-        conversation: find_or_create_conversation,
-        thread: thread? ? find_status(thread.first) || find_activitypub_status(thread.first, thread.second) : nil,
-        media_attachment_ids: media_attachments.map(&:id),
-        sensitive: sensitive?
-      )
-
-      save_mentions(status)
-      save_hashtags(status)
-      save_emojis(status)
-    end
-
-    if thread? && status.thread.nil? && Request.valid_url?(thread.second)
-      Rails.logger.debug "Trying to attach #{status.id} (#{id}) to #{thread.first}"
-      ThreadResolveWorker.perform_async(status.id, thread.second)
-    end
-
-    Rails.logger.debug "Queuing remote status #{status.id} (#{id}) for distribution"
-
-    LinkCrawlWorker.perform_async(status.id) unless status.spoiler_text?
-
-    # Only continue if the status is supposed to have arrived in real-time.
-    # Note that if @options[:override_timestamps] isn't set, the status
-    # may have a lower snowflake id than other existing statuses, potentially
-    # "hiding" it from paginated API calls
-    return status unless @options[:override_timestamps] || status.within_realtime_window?
-
-    DistributionWorker.perform_async(status.id)
-
-    status
-  end
-
-  def content
-    @xml.at_xpath('./xmlns:content', xmlns: OStatus::TagManager::XMLNS).content
-  end
-
-  def content_language
-    @xml.at_xpath('./xmlns:content', xmlns: OStatus::TagManager::XMLNS)['xml:lang']&.presence || 'en'
-  end
-
-  def content_warning
-    @xml.at_xpath('./xmlns:summary', xmlns: OStatus::TagManager::XMLNS)&.content || ''
-  end
-
-  def visibility_scope
-    @xml.at_xpath('./mastodon:scope', mastodon: OStatus::TagManager::MTDN_XMLNS)&.content&.to_sym || :public
-  end
-
-  def published
-    @xml.at_xpath('./xmlns:published', xmlns: OStatus::TagManager::XMLNS).content
-  end
-
-  def thread?
-    !@xml.at_xpath('./thr:in-reply-to', thr: OStatus::TagManager::THR_XMLNS).nil?
-  end
-
-  def thread
-    thr = @xml.at_xpath('./thr:in-reply-to', thr: OStatus::TagManager::THR_XMLNS)
-    [thr['ref'], thr['href']]
-  end
-
-  private
-
-  def sensitive?
-    # OStatus-specific convention (not standard)
-    @xml.xpath('./xmlns:category', xmlns: OStatus::TagManager::XMLNS).any? { |category| category['term'] == 'nsfw' }
-  end
-
-  def find_or_create_conversation
-    uri = @xml.at_xpath('./ostatus:conversation', ostatus: OStatus::TagManager::OS_XMLNS)&.attribute('ref')&.content
-    return if uri.nil?
-
-    if OStatus::TagManager.instance.local_id?(uri)
-      local_id = OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Conversation')
-      return Conversation.find_by(id: local_id)
-    end
-
-    Conversation.find_by(uri: uri) || Conversation.create!(uri: uri)
-  end
-
-  def save_mentions(parent)
-    processed_account_ids = []
-
-    @xml.xpath('./xmlns:link[@rel="mentioned"]', xmlns: OStatus::TagManager::XMLNS).each do |link|
-      next if [OStatus::TagManager::TYPES[:group], OStatus::TagManager::TYPES[:collection]].include? link['ostatus:object-type']
-
-      mentioned_account = account_from_href(link['href'])
-
-      next if mentioned_account.nil? || processed_account_ids.include?(mentioned_account.id)
-
-      mentioned_account.mentions.where(status: parent).first_or_create(status: parent)
-
-      # So we can skip duplicate mentions
-      processed_account_ids << mentioned_account.id
-    end
-  end
-
-  def save_hashtags(parent)
-    tags = @xml.xpath('./xmlns:category', xmlns: OStatus::TagManager::XMLNS).map { |category| category['term'] }.select(&:present?)
-    ProcessHashtagsService.new.call(parent, tags)
-  end
-
-  def save_media
-    do_not_download = DomainBlock.find_by(domain: @account.domain)&.reject_media?
-    media_attachments = []
-
-    @xml.xpath('./xmlns:link[@rel="enclosure"]', xmlns: OStatus::TagManager::XMLNS).each do |link|
-      next unless link['href']
-
-      media = MediaAttachment.where(status: nil, remote_url: link['href']).first_or_initialize(account: @account, status: nil, remote_url: link['href'])
-      parsed_url = Addressable::URI.parse(link['href']).normalize
-
-      next if !%w(http https).include?(parsed_url.scheme) || parsed_url.host.empty?
-
-      media.save
-      media_attachments << media
-
-      next if do_not_download
-
-      begin
-        media.file_remote_url = link['href']
-        media.save!
-      rescue ActiveRecord::RecordInvalid
-        next
-      end
-    end
-
-    media_attachments
-  end
-
-  def save_emojis(parent)
-    do_not_download = DomainBlock.find_by(domain: parent.account.domain)&.reject_media?
-
-    return if do_not_download
-
-    @xml.xpath('./xmlns:link[@rel="emoji"]', xmlns: OStatus::TagManager::XMLNS).each do |link|
-      next unless link['href'] && link['name']
-
-      shortcode = link['name'].delete(':')
-      emoji     = CustomEmoji.find_by(shortcode: shortcode, domain: parent.account.domain)
-
-      next unless emoji.nil?
-
-      emoji = CustomEmoji.new(shortcode: shortcode, domain: parent.account.domain)
-      emoji.image_remote_url = link['href']
-      emoji.save
-    end
-  end
-
-  def account_from_href(href)
-    url = Addressable::URI.parse(href).normalize
-
-    if TagManager.instance.web_domain?(url.host)
-      Account.find_local(url.path.gsub('/users/', ''))
-    else
-      Account.where(uri: href).or(Account.where(url: href)).first || FetchRemoteAccountService.new.call(href)
-    end
-  end
-
-  def invalid_origin?
-    return false unless id.start_with?('http') # Legacy IDs cannot be checked
-
-    needle = Addressable::URI.parse(id).normalized_host
-
-    !(needle.casecmp(@account.domain).zero? ||
-      needle.casecmp(Addressable::URI.parse(@account.remote_url.presence || @account.uri).normalized_host).zero?)
-  end
-
-  def lock_options
-    { redis: Redis.current, key: "create:#{id}" }
-  end
-end
diff --git a/app/lib/ostatus/activity/deletion.rb b/app/lib/ostatus/activity/deletion.rb
deleted file mode 100644
index c98f5ee0a..000000000
--- a/app/lib/ostatus/activity/deletion.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Deletion < OStatus::Activity::Base
-  def perform
-    Rails.logger.debug "Deleting remote status #{id}"
-
-    status   = Status.find_by(uri: id, account: @account)
-    status ||= Status.find_by(uri: activitypub_uri, account: @account) if activitypub_uri?
-
-    if status.nil?
-      redis.setex("delete_upon_arrival:#{@account.id}:#{id}", 6 * 3_600, id)
-    else
-      RemoveStatusService.new.call(status)
-    end
-  end
-end
diff --git a/app/lib/ostatus/activity/general.rb b/app/lib/ostatus/activity/general.rb
deleted file mode 100644
index 8a6aabc33..000000000
--- a/app/lib/ostatus/activity/general.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::General < OStatus::Activity::Base
-  def specialize
-    special_class&.new(@xml, @account, @options)
-  end
-
-  private
-
-  def special_class
-    case verb
-    when :post
-      OStatus::Activity::Post
-    when :share
-      OStatus::Activity::Share
-    when :delete
-      OStatus::Activity::Deletion
-    end
-  end
-end
diff --git a/app/lib/ostatus/activity/post.rb b/app/lib/ostatus/activity/post.rb
deleted file mode 100644
index 755ed8656..000000000
--- a/app/lib/ostatus/activity/post.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Post < OStatus::Activity::Creation
-  def perform
-    status, just_created = super
-
-    if just_created
-      status.mentions.includes(:account).each do |mention|
-        mentioned_account = mention.account
-        next unless mentioned_account.local?
-        NotifyService.new.call(mentioned_account, mention)
-      end
-    end
-
-    status
-  end
-
-  private
-
-  def reblog
-    nil
-  end
-end
diff --git a/app/lib/ostatus/activity/remote.rb b/app/lib/ostatus/activity/remote.rb
deleted file mode 100644
index 5b204b6d8..000000000
--- a/app/lib/ostatus/activity/remote.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Remote < OStatus::Activity::Base
-  def perform
-    if activitypub_uri?
-      find_status(activitypub_uri) || FetchRemoteStatusService.new.call(url)
-    else
-      find_status(id) || FetchRemoteStatusService.new.call(url)
-    end
-  end
-end
diff --git a/app/lib/ostatus/activity/share.rb b/app/lib/ostatus/activity/share.rb
deleted file mode 100644
index 5ca601415..000000000
--- a/app/lib/ostatus/activity/share.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::Activity::Share < OStatus::Activity::Creation
-  def perform
-    return if reblog.nil?
-
-    status, just_created = super
-    NotifyService.new.call(reblog.account, status) if reblog.account.local? && just_created
-    status
-  end
-
-  def object
-    @xml.at_xpath('.//activity:object', activity: OStatus::TagManager::AS_XMLNS)
-  end
-
-  private
-
-  def reblog
-    return @reblog if defined? @reblog
-
-    original_status = OStatus::Activity::Remote.new(object).perform
-    return if original_status.nil?
-
-    @reblog = original_status.reblog? ? original_status.reblog : original_status
-  end
-end
diff --git a/app/lib/ostatus/atom_serializer.rb b/app/lib/ostatus/atom_serializer.rb
deleted file mode 100644
index 9a05d96cf..000000000
--- a/app/lib/ostatus/atom_serializer.rb
+++ /dev/null
@@ -1,378 +0,0 @@
-# frozen_string_literal: true
-
-class OStatus::AtomSerializer
-  include RoutingHelper
-  include ActionView::Helpers::SanitizeHelper
-
-  class << self
-    def render(element)
-      document = Ox::Document.new(version: '1.0')
-      document << element
-      ('<?xml version="1.0"?>' + Ox.dump(element, effort: :tolerant)).force_encoding('UTF-8')
-    end
-  end
-
-  def author(account)
-    author = Ox::Element.new('author')
-
-    uri = OStatus::TagManager.instance.uri_for(account)
-
-    append_element(author, 'id', uri)
-    append_element(author, 'activity:object-type', OStatus::TagManager::TYPES[:person])
-    append_element(author, 'uri', uri)
-    append_element(author, 'name', account.username)
-    append_element(author, 'email', account.local? ? account.local_username_and_domain : account.acct)
-    append_element(author, 'summary', Formatter.instance.simplified_format(account).to_str, type: :html) if account.note?
-    append_element(author, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(account))
-    append_element(author, 'link', nil, rel: :avatar, type: account.avatar_content_type, 'media:width': 120, 'media:height': 120, href: full_asset_url(account.avatar.url(:original))) if account.avatar?
-    append_element(author, 'link', nil, rel: :header, type: account.header_content_type, 'media:width': 700, 'media:height': 335, href: full_asset_url(account.header.url(:original))) if account.header?
-    account.emojis.each do |emoji|
-      append_element(author, 'link', nil, rel: :emoji, href: full_asset_url(emoji.image.url), name: emoji.shortcode)
-    end
-    append_element(author, 'poco:preferredUsername', account.username)
-    append_element(author, 'poco:displayName', account.display_name) if account.display_name?
-    append_element(author, 'poco:note', account.local? ? account.note : strip_tags(account.note)) if account.note?
-    append_element(author, 'mastodon:scope', account.locked? ? :private : :public)
-
-    author
-  end
-
-  def feed(account, stream_entries)
-    feed = Ox::Element.new('feed')
-
-    add_namespaces(feed)
-
-    append_element(feed, 'id', account_url(account, format: 'atom'))
-    append_element(feed, 'title', account.display_name.presence || account.username)
-    append_element(feed, 'subtitle', account.note)
-    append_element(feed, 'updated', account.updated_at.iso8601)
-    append_element(feed, 'logo', full_asset_url(account.avatar.url(:original)))
-
-    feed << author(account)
-
-    append_element(feed, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(account))
-    append_element(feed, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_url(account, format: 'atom'))
-    append_element(feed, 'link', nil, rel: :next, type: 'application/atom+xml', href: account_url(account, format: 'atom', max_id: stream_entries.last.id)) if stream_entries.size == 20
-    append_element(feed, 'link', nil, rel: :hub, href: api_push_url)
-    append_element(feed, 'link', nil, rel: :salmon, href: api_salmon_url(account.id))
-
-    stream_entries.each do |stream_entry|
-      feed << entry(stream_entry)
-    end
-
-    feed
-  end
-
-  def entry(stream_entry, root = false)
-    entry = Ox::Element.new('entry')
-
-    add_namespaces(entry) if root
-
-    append_element(entry, 'id', OStatus::TagManager.instance.uri_for(stream_entry.status))
-    append_element(entry, 'published', stream_entry.created_at.iso8601)
-    append_element(entry, 'updated', stream_entry.updated_at.iso8601)
-    append_element(entry, 'title', stream_entry&.status&.title || "#{stream_entry.account.acct} deleted status")
-
-    entry << author(stream_entry.account) if root
-
-    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[stream_entry.object_type])
-    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[stream_entry.verb])
-
-    entry << object(stream_entry.target) if stream_entry.targeted?
-
-    if stream_entry.status.nil?
-      append_element(entry, 'content', 'Deleted status')
-    elsif stream_entry.status.destroyed?
-      append_element(entry, 'content', 'Deleted status')
-      append_element(entry, 'link', nil, rel: :alternate, type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(stream_entry.status)) if stream_entry.account.local?
-    else
-      serialize_status_attributes(entry, stream_entry.status)
-    end
-
-    append_element(entry, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(stream_entry.status))
-    append_element(entry, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_stream_entry_url(stream_entry.account, stream_entry, format: 'atom'))
-    append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(stream_entry.thread), href: ::TagManager.instance.url_for(stream_entry.thread)) if stream_entry.threaded?
-    append_element(entry, 'ostatus:conversation', nil, ref: conversation_uri(stream_entry.status.conversation)) unless stream_entry&.status&.conversation_id.nil?
-
-    entry
-  end
-
-  def object(status)
-    object = Ox::Element.new('activity:object')
-
-    append_element(object, 'id', OStatus::TagManager.instance.uri_for(status))
-    append_element(object, 'published', status.created_at.iso8601)
-    append_element(object, 'updated', status.updated_at.iso8601)
-    append_element(object, 'title', status.title)
-
-    object << author(status.account)
-
-    append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[status.object_type])
-    append_element(object, 'activity:verb', OStatus::TagManager::VERBS[status.verb])
-
-    serialize_status_attributes(object, status)
-
-    append_element(object, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(status))
-    append_element(object, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(status.thread), href: ::TagManager.instance.url_for(status.thread)) unless status.thread.nil?
-    append_element(object, 'ostatus:conversation', nil, ref: conversation_uri(status.conversation)) unless status.conversation_id.nil?
-
-    object
-  end
-
-  def follow_salmon(follow)
-    entry = Ox::Element.new('entry')
-    add_namespaces(entry)
-
-    description = "#{follow.account.acct} started following #{follow.target_account.acct}"
-
-    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(follow.created_at, follow.id, 'Follow'))
-    append_element(entry, 'title', description)
-    append_element(entry, 'content', description, type: :html)
-
-    entry << author(follow.account)
-
-    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:follow])
-
-    object = author(follow.target_account)
-    object.value = 'activity:object'
-
-    entry << object
-    entry
-  end
-
-  def follow_request_salmon(follow_request)
-    entry = Ox::Element.new('entry')
-    add_namespaces(entry)
-
-    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(follow_request.created_at, follow_request.id, 'FollowRequest'))
-    append_element(entry, 'title', "#{follow_request.account.acct} requested to follow #{follow_request.target_account.acct}")
-
-    entry << author(follow_request.account)
-
-    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:request_friend])
-
-    object = author(follow_request.target_account)
-    object.value = 'activity:object'
-
-    entry << object
-    entry
-  end
-
-  def authorize_follow_request_salmon(follow_request)
-    entry = Ox::Element.new('entry')
-    add_namespaces(entry)
-
-    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow_request.id, 'FollowRequest'))
-    append_element(entry, 'title', "#{follow_request.target_account.acct} authorizes follow request by #{follow_request.account.acct}")
-
-    entry << author(follow_request.target_account)
-
-    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:authorize])
-
-    object = Ox::Element.new('activity:object')
-    object << author(follow_request.account)
-
-    append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(object, 'activity:verb', OStatus::TagManager::VERBS[:request_friend])
-
-    inner_object = author(follow_request.target_account)
-    inner_object.value = 'activity:object'
-
-    object << inner_object
-    entry  << object
-    entry
-  end
-
-  def reject_follow_request_salmon(follow_request)
-    entry = Ox::Element.new('entry')
-    add_namespaces(entry)
-
-    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow_request.id, 'FollowRequest'))
-    append_element(entry, 'title', "#{follow_request.target_account.acct} rejects follow request by #{follow_request.account.acct}")
-
-    entry << author(follow_request.target_account)
-
-    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:reject])
-
-    object = Ox::Element.new('activity:object')
-    object << author(follow_request.account)
-
-    append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(object, 'activity:verb', OStatus::TagManager::VERBS[:request_friend])
-
-    inner_object = author(follow_request.target_account)
-    inner_object.value = 'activity:object'
-
-    object << inner_object
-    entry  << object
-    entry
-  end
-
-  def unfollow_salmon(follow)
-    entry = Ox::Element.new('entry')
-    add_namespaces(entry)
-
-    description = "#{follow.account.acct} is no longer following #{follow.target_account.acct}"
-
-    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow.id, 'Follow'))
-    append_element(entry, 'title', description)
-    append_element(entry, 'content', description, type: :html)
-
-    entry << author(follow.account)
-
-    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unfollow])
-
-    object = author(follow.target_account)
-    object.value = 'activity:object'
-
-    entry << object
-    entry
-  end
-
-  def block_salmon(block)
-    entry = Ox::Element.new('entry')
-    add_namespaces(entry)
-
-    description = "#{block.account.acct} no longer wishes to interact with #{block.target_account.acct}"
-
-    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, block.id, 'Block'))
-    append_element(entry, 'title', description)
-
-    entry << author(block.account)
-
-    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:block])
-
-    object = author(block.target_account)
-    object.value = 'activity:object'
-
-    entry << object
-    entry
-  end
-
-  def unblock_salmon(block)
-    entry = Ox::Element.new('entry')
-    add_namespaces(entry)
-
-    description = "#{block.account.acct} no longer blocks #{block.target_account.acct}"
-
-    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, block.id, 'Block'))
-    append_element(entry, 'title', description)
-
-    entry << author(block.account)
-
-    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unblock])
-
-    object = author(block.target_account)
-    object.value = 'activity:object'
-
-    entry << object
-    entry
-  end
-
-  def favourite_salmon(favourite)
-    entry = Ox::Element.new('entry')
-    add_namespaces(entry)
-
-    description = "#{favourite.account.acct} favourited a status by #{favourite.status.account.acct}"
-
-    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(favourite.created_at, favourite.id, 'Favourite'))
-    append_element(entry, 'title', description)
-    append_element(entry, 'content', description, type: :html)
-
-    entry << author(favourite.account)
-
-    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:favorite])
-
-    entry << object(favourite.status)
-
-    append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: ::TagManager.instance.url_for(favourite.status))
-
-    entry
-  end
-
-  def unfavourite_salmon(favourite)
-    entry = Ox::Element.new('entry')
-    add_namespaces(entry)
-
-    description = "#{favourite.account.acct} no longer favourites a status by #{favourite.status.account.acct}"
-
-    append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, favourite.id, 'Favourite'))
-    append_element(entry, 'title', description)
-    append_element(entry, 'content', description, type: :html)
-
-    entry << author(favourite.account)
-
-    append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity])
-    append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unfavorite])
-
-    entry << object(favourite.status)
-
-    append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: ::TagManager.instance.url_for(favourite.status))
-
-    entry
-  end
-
-  private
-
-  def append_element(parent, name, content = nil, **attributes)
-    element = Ox::Element.new(name)
-    attributes.each { |k, v| element[k] = sanitize_str(v) }
-    element << sanitize_str(content) unless content.nil?
-    parent  << element
-  end
-
-  def sanitize_str(raw_str)
-    raw_str.to_s
-  end
-
-  def conversation_uri(conversation)
-    return conversation.uri if conversation.uri?
-    OStatus::TagManager.instance.unique_tag(conversation.created_at, conversation.id, 'Conversation')
-  end
-
-  def add_namespaces(parent)
-    parent['xmlns']          = OStatus::TagManager::XMLNS
-    parent['xmlns:thr']      = OStatus::TagManager::THR_XMLNS
-    parent['xmlns:activity'] = OStatus::TagManager::AS_XMLNS
-    parent['xmlns:poco']     = OStatus::TagManager::POCO_XMLNS
-    parent['xmlns:media']    = OStatus::TagManager::MEDIA_XMLNS
-    parent['xmlns:ostatus']  = OStatus::TagManager::OS_XMLNS
-    parent['xmlns:mastodon'] = OStatus::TagManager::MTDN_XMLNS
-  end
-
-  def serialize_status_attributes(entry, status)
-    append_element(entry, 'link', nil, rel: :alternate, type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(status)) if status.account.local?
-
-    append_element(entry, 'summary', status.spoiler_text, 'xml:lang': status.language) if status.spoiler_text?
-    append_element(entry, 'content', Formatter.instance.format(status, inline_poll_options: true).to_str || '.', type: 'html', 'xml:lang': status.language)
-
-    status.active_mentions.sort_by(&:id).each do |mentioned|
-      append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:person], href: OStatus::TagManager.instance.uri_for(mentioned.account))
-    end
-
-    append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:collection], href: OStatus::TagManager::COLLECTIONS[:public]) if status.public_visibility?
-
-    status.tags.each do |tag|
-      append_element(entry, 'category', nil, term: tag.name)
-    end
-
-    status.media_attachments.each do |media|
-      append_element(entry, 'link', nil, rel: :enclosure, type: media.file_content_type, length: media.file_file_size, href: full_asset_url(media.file.url(:original, false)))
-    end
-
-    append_element(entry, 'category', nil, term: 'nsfw') if status.sensitive? && status.media_attachments.any?
-    append_element(entry, 'mastodon:scope', status.visibility)
-
-    status.emojis.each do |emoji|
-      append_element(entry, 'link', nil, rel: :emoji, href: full_asset_url(emoji.image.url), name: emoji.shortcode)
-    end
-  end
-end
diff --git a/app/models/account.rb b/app/models/account.rb
index dd644ea37..50033d1c3 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -321,10 +321,6 @@ class Account < ApplicationRecord
     (['RSA'] + [modulus, exponent].map { |n| Base64.urlsafe_encode64(n) }).join('.')
   end
 
-  def subscription(webhook_url)
-    @subscription ||= OStatus2::Subscription.new(remote_url, secret: secret, webhook: webhook_url, hub: hub_url)
-  end
-
   def save_with_optional_media!
     save!
   rescue ActiveRecord::RecordInvalid
diff --git a/app/models/form/account_batch.rb b/app/models/form/account_batch.rb
index 5bc44e809..eed65b47a 100644
--- a/app/models/form/account_batch.rb
+++ b/app/models/form/account_batch.rb
@@ -52,8 +52,6 @@ class Form::AccountBatch
   def reject_follow!(follow)
     follow.destroy
 
-    return unless follow.account.activitypub?
-
     json = ActiveModelSerializers::SerializableResource.new(
       follow,
       serializer: ActivityPub::RejectFollowSerializer,
diff --git a/app/models/remote_profile.rb b/app/models/remote_profile.rb
deleted file mode 100644
index 742d2b56f..000000000
--- a/app/models/remote_profile.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# frozen_string_literal: true
-
-class RemoteProfile
-  include ActiveModel::Model
-
-  attr_reader :document
-
-  def initialize(body)
-    @document = Nokogiri::XML.parse(body, nil, 'utf-8')
-  end
-
-  def root
-    @root ||= document.at_xpath('/atom:feed|/atom:entry', atom: OStatus::TagManager::XMLNS)
-  end
-
-  def author
-    @author ||= root.at_xpath('./atom:author|./dfrn:owner', atom: OStatus::TagManager::XMLNS, dfrn: OStatus::TagManager::DFRN_XMLNS)
-  end
-
-  def hub_link
-    @hub_link ||= link_href_from_xml(root, 'hub')
-  end
-
-  def display_name
-    @display_name ||= author.at_xpath('./poco:displayName', poco: OStatus::TagManager::POCO_XMLNS)&.content
-  end
-
-  def note
-    @note ||= author.at_xpath('./atom:summary|./poco:note', atom: OStatus::TagManager::XMLNS, poco: OStatus::TagManager::POCO_XMLNS)&.content
-  end
-
-  def scope
-    @scope ||= author.at_xpath('./mastodon:scope', mastodon: OStatus::TagManager::MTDN_XMLNS)&.content
-  end
-
-  def avatar
-    @avatar ||= link_href_from_xml(author, 'avatar')
-  end
-
-  def header
-    @header ||= link_href_from_xml(author, 'header')
-  end
-
-  def emojis
-    @emojis ||= author.xpath('./xmlns:link[@rel="emoji"]', xmlns: OStatus::TagManager::XMLNS)
-  end
-
-  def locked?
-    scope == 'private'
-  end
-
-  private
-
-  def link_href_from_xml(xml, type)
-    xml.at_xpath(%(./atom:link[@rel="#{type}"]/@href), atom: OStatus::TagManager::XMLNS)&.content
-  end
-end
diff --git a/app/serializers/activitypub/activity_serializer.rb b/app/serializers/activitypub/activity_serializer.rb
index c06d5c87c..21386ab8a 100644
--- a/app/serializers/activitypub/activity_serializer.rb
+++ b/app/serializers/activitypub/activity_serializer.rb
@@ -5,7 +5,6 @@ class ActivityPub::ActivitySerializer < ActivityPub::Serializer
 
   has_one :proper, key: :object, serializer: ActivityPub::NoteSerializer, if: :serialize_object?
   attribute :proper_uri, key: :object, unless: :serialize_object?
-  attribute :atom_uri, if: :announce?
 
   def id
     ActivityPub::TagManager.instance.activity_uri_for(object)
@@ -35,10 +34,6 @@ class ActivityPub::ActivitySerializer < ActivityPub::Serializer
     ActivityPub::TagManager.instance.uri_for(object.proper)
   end
 
-  def atom_uri
-    OStatus::TagManager.instance.uri_for(object)
-  end
-
   def announce?
     object.reblog?
   end
diff --git a/app/serializers/activitypub/delete_serializer.rb b/app/serializers/activitypub/delete_serializer.rb
index a7d5bd469..c8f918c92 100644
--- a/app/serializers/activitypub/delete_serializer.rb
+++ b/app/serializers/activitypub/delete_serializer.rb
@@ -2,9 +2,7 @@
 
 class ActivityPub::DeleteSerializer < ActivityPub::Serializer
   class TombstoneSerializer < ActivityPub::Serializer
-    context_extensions :atom_uri
-
-    attributes :id, :type, :atom_uri
+    attributes :id, :type
 
     def id
       ActivityPub::TagManager.instance.uri_for(object)
@@ -13,10 +11,6 @@ class ActivityPub::DeleteSerializer < ActivityPub::Serializer
     def type
       'Tombstone'
     end
-
-    def atom_uri
-      OStatus::TagManager.instance.uri_for(object)
-    end
   end
 
   attributes :id, :type, :actor, :to
diff --git a/app/serializers/activitypub/note_serializer.rb b/app/serializers/activitypub/note_serializer.rb
index d05c9c4f8..da99b9606 100644
--- a/app/serializers/activitypub/note_serializer.rb
+++ b/app/serializers/activitypub/note_serializer.rb
@@ -1,13 +1,12 @@
 # frozen_string_literal: true
 
 class ActivityPub::NoteSerializer < ActivityPub::Serializer
-  context_extensions :atom_uri, :conversation, :sensitive,
+  context_extensions :conversation, :sensitive,
                      :hashtag, :emoji, :focal_point, :blurhash
 
   attributes :id, :type, :summary,
              :in_reply_to, :published, :url,
              :attributed_to, :to, :cc, :sensitive,
-             :atom_uri, :in_reply_to_atom_uri,
              :conversation, :source
 
   attribute :content
@@ -102,18 +101,6 @@ class ActivityPub::NoteSerializer < ActivityPub::Serializer
     object.active_mentions.to_a.sort_by(&:id) + object.tags.reject { |t| t.local || t.private } + object.emojis
   end
 
-  def atom_uri
-    return unless object.local?
-
-    OStatus::TagManager.instance.uri_for(object)
-  end
-
-  def in_reply_to_atom_uri
-    return unless object.reply? && !object.thread.nil?
-
-    OStatus::TagManager.instance.uri_for(object.thread)
-  end
-
   def conversation
     return if object.conversation.nil?
 
diff --git a/app/serializers/webfinger_serializer.rb b/app/serializers/webfinger_serializer.rb
index 8c0b07702..882fcf948 100644
--- a/app/serializers/webfinger_serializer.rb
+++ b/app/serializers/webfinger_serializer.rb
@@ -16,11 +16,8 @@ class WebfingerSerializer < ActiveModel::Serializer
   def links
     [
       { rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: short_account_url(object) },
-      { rel: 'http://schemas.google.com/g/2010#updates-from', type: 'application/atom+xml', href: account_url(object, format: 'atom') },
       { rel: 'self', type: 'application/activity+json', href: account_url(object) },
-      { rel: 'salmon', href: api_salmon_url(object.id) },
       { rel: 'magic-public-key', href: "data:application/magic-public-key,#{object.magic_key}" },
-      { rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_interaction_url}?uri={uri}" },
     ]
   end
 end
diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb
index ad22d37fe..f36ab7d61 100644
--- a/app/services/activitypub/process_account_service.rb
+++ b/app/services/activitypub/process_account_service.rb
@@ -19,7 +19,6 @@ class ActivityPub::ProcessAccountService < BaseService
       if lock.acquired?
         @account        = Account.find_remote(@username, @domain)
         @old_public_key = @account&.public_key
-        @old_protocol   = @account&.protocol
 
         create_account if @account.nil?
         update_account
@@ -32,7 +31,6 @@ class ActivityPub::ProcessAccountService < BaseService
 
     return if @account.nil?
 
-    after_protocol_change! if protocol_changed?
     after_key_change! if key_changed? && !@options[:signed_with_known_key]
     clear_tombstones! if key_changed?
 
@@ -50,7 +48,6 @@ class ActivityPub::ProcessAccountService < BaseService
 
   def create_account
     @account = Account.new
-    @account.protocol     = :activitypub
     @account.username     = @username
     @account.domain       = @domain
     @account.private_key  = nil
@@ -60,7 +57,6 @@ class ActivityPub::ProcessAccountService < BaseService
 
   def update_account
     @account.last_webfingered_at = Time.now.utc unless @options[:only_key]
-    @account.protocol            = :activitypub
 
     set_immediate_attributes!
     set_fetchable_attributes! unless @options[:only_keys]
@@ -94,10 +90,6 @@ class ActivityPub::ProcessAccountService < BaseService
     @account.moved_to_account  = @json['movedTo'].present? ? moved_account : nil
   end
 
-  def after_protocol_change!
-    ActivityPub::PostUpgradeWorker.perform_async(@account.domain)
-  end
-
   def after_key_change!
     RefollowWorker.perform_async(@account.id)
   end
@@ -216,10 +208,6 @@ class ActivityPub::ProcessAccountService < BaseService
     Tombstone.where(account_id: @account.id).delete_all
   end
 
-  def protocol_changed?
-    !@old_protocol.nil? && @old_protocol != @account.protocol
-  end
-
   def lock_options
     { redis: Redis.current, key: "process_account:#{@uri}" }
   end
diff --git a/app/services/after_block_domain_from_account_service.rb b/app/services/after_block_domain_from_account_service.rb
index 180f13403..f12f18319 100644
--- a/app/services/after_block_domain_from_account_service.rb
+++ b/app/services/after_block_domain_from_account_service.rb
@@ -29,8 +29,6 @@ class AfterBlockDomainFromAccountService < BaseService
   def reject_follow!(follow)
     follow.destroy
 
-    return unless follow.account.activitypub?
-
     json = ActiveModelSerializers::SerializableResource.new(
       follow,
       serializer: ActivityPub::RejectFollowSerializer,
diff --git a/app/services/authorize_follow_service.rb b/app/services/authorize_follow_service.rb
index f2e3ebe7d..dcb72d09b 100644
--- a/app/services/authorize_follow_service.rb
+++ b/app/services/authorize_follow_service.rb
@@ -16,11 +16,7 @@ class AuthorizeFollowService < BaseService
   private
 
   def create_notification(follow_request)
-    if follow_request.account.ostatus?
-      NotificationWorker.perform_async(build_xml(follow_request), follow_request.target_account_id, follow_request.account_id)
-    elsif follow_request.account.activitypub?
-      ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), follow_request.target_account_id, follow_request.account.inbox_url)
-    end
+    ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), follow_request.target_account_id, follow_request.account.inbox_url)
   end
 
   def build_json(follow_request)
@@ -30,8 +26,4 @@ class AuthorizeFollowService < BaseService
       adapter: ActivityPub::Adapter
     ).to_json
   end
-
-  def build_xml(follow_request)
-    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request))
-  end
 end
diff --git a/app/services/batched_remove_status_service.rb b/app/services/batched_remove_status_service.rb
index 02f7076f7..e8b361210 100644
--- a/app/services/batched_remove_status_service.rb
+++ b/app/services/batched_remove_status_service.rb
@@ -1,12 +1,9 @@
 # frozen_string_literal: true
 
 class BatchedRemoveStatusService < BaseService
-  include StreamEntryRenderer
   include Redisable
 
   # Delete given statuses and reblogs of them
-  # Dispatch PuSH updates of the deleted statuses, but only local ones
-  # Dispatch Salmon deletes, unique per domain, of the deleted statuses, but only local ones
   # Remove statuses from home feeds
   # Push delete events to streaming API for home feeds and public feeds
   # @param [Status] statuses A preferably batched array of statuses
@@ -18,10 +15,7 @@ class BatchedRemoveStatusService < BaseService
     @mentions = statuses.each_with_object({}) { |s, h| h[s.id] = s.active_mentions.includes(:account).to_a }
     @tags     = statuses.each_with_object({}) { |s, h| h[s.id] = s.tags.pluck(:name) }
 
-    @stream_entry_batches  = []
-    @salmon_batches        = []
     @json_payloads         = statuses.each_with_object({}) { |s, h| h[s.id] = Oj.dump(event: :delete, payload: s.id.to_s) }
-    @activity_xml          = {}
 
     # Ensure that rendered XML reflects destroyed state
     statuses.each do |status|
@@ -39,29 +33,17 @@ class BatchedRemoveStatusService < BaseService
 
       unpush_from_home_timelines(account, account_statuses)
       unpush_from_list_timelines(account, account_statuses)
-
-      batch_stream_entries(account, account_statuses) if account.local?
     end
 
     # Cannot be batched
     statuses.each do |status|
       unpush_from_public_timelines(status)
       unpush_from_direct_timelines(status) if status.direct_visibility?
-      batch_salmon_slaps(status) if status.local?
     end
-
-    Pubsubhubbub::RawDistributionWorker.push_bulk(@stream_entry_batches) { |batch| batch }
-    NotificationWorker.push_bulk(@salmon_batches) { |batch| batch }
   end
 
   private
 
-  def batch_stream_entries(account, statuses)
-    statuses.each do |status|
-      @stream_entry_batches << [build_xml(status.stream_entry), account.id]
-    end
-  end
-
   def unpush_from_home_timelines(account, statuses)
     recipients = account.followers_for_local_distribution.to_a
 
@@ -112,20 +94,4 @@ class BatchedRemoveStatusService < BaseService
       redis.publish("timeline:direct:#{status.account.id}", payload) if status.account.local?
     end
   end
-
-  def batch_salmon_slaps(status)
-    return if @mentions[status.id].empty?
-
-    recipients = @mentions[status.id].map(&:account).reject(&:local?).select(&:ostatus?).uniq(&:domain).map(&:id)
-
-    recipients.each do |recipient_id|
-      @salmon_batches << [build_xml(status.stream_entry), status.account_id, recipient_id]
-    end
-  end
-
-  def build_xml(stream_entry)
-    return @activity_xml[stream_entry.id] if @activity_xml.key?(stream_entry.id)
-
-    @activity_xml[stream_entry.id] = stream_entry_to_xml(stream_entry)
-  end
 end
diff --git a/app/services/block_service.rb b/app/services/block_service.rb
index 10ed470e0..0ce425aa7 100644
--- a/app/services/block_service.rb
+++ b/app/services/block_service.rb
@@ -18,11 +18,7 @@ class BlockService < BaseService
   private
 
   def create_notification(block)
-    if block.target_account.ostatus?
-      NotificationWorker.perform_async(build_xml(block), block.account_id, block.target_account_id)
-    elsif block.target_account.activitypub?
-      ActivityPub::DeliveryWorker.perform_async(build_json(block), block.account_id, block.target_account.inbox_url)
-    end
+    ActivityPub::DeliveryWorker.perform_async(build_json(block), block.account_id, block.target_account.inbox_url)
   end
 
   def build_json(block)
@@ -32,8 +28,4 @@ class BlockService < BaseService
       adapter: ActivityPub::Adapter
     ).to_json
   end
-
-  def build_xml(block)
-    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.block_salmon(block))
-  end
 end
diff --git a/app/services/concerns/author_extractor.rb b/app/services/concerns/author_extractor.rb
deleted file mode 100644
index c2419e9ec..000000000
--- a/app/services/concerns/author_extractor.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-module AuthorExtractor
-  def author_from_xml(xml, update_profile = true)
-    return nil if xml.nil?
-
-    # Try <email> for acct
-    acct = xml.at_xpath('./xmlns:author/xmlns:email', xmlns: OStatus::TagManager::XMLNS)&.content
-
-    # Try <name> + <uri>
-    if acct.blank?
-      username = xml.at_xpath('./xmlns:author/xmlns:name', xmlns: OStatus::TagManager::XMLNS)&.content
-      uri      = xml.at_xpath('./xmlns:author/xmlns:uri', xmlns: OStatus::TagManager::XMLNS)&.content
-
-      return nil if username.blank? || uri.blank?
-
-      domain = Addressable::URI.parse(uri).normalized_host
-      acct   = "#{username}@#{domain}"
-    end
-
-    ResolveAccountService.new.call(acct, update_profile: update_profile)
-  end
-end
diff --git a/app/services/concerns/stream_entry_renderer.rb b/app/services/concerns/stream_entry_renderer.rb
deleted file mode 100644
index 9f6c8a082..000000000
--- a/app/services/concerns/stream_entry_renderer.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: true
-
-module StreamEntryRenderer
-  def stream_entry_to_xml(stream_entry)
-    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(stream_entry, true))
-  end
-end
diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb
index 98275b37e..32699d132 100644
--- a/app/services/favourite_service.rb
+++ b/app/services/favourite_service.rb
@@ -30,9 +30,7 @@ class FavouriteService < BaseService
 
     if status.account.local?
       NotifyService.new.call(status.account, favourite)
-    elsif status.account.ostatus?
-      NotificationWorker.perform_async(build_xml(favourite), favourite.account_id, status.account_id)
-    elsif status.account.activitypub?
+    else
       ActivityPub::DeliveryWorker.perform_async(build_json(favourite), favourite.account_id, status.account.inbox_url)
     end
   end
@@ -51,10 +49,6 @@ class FavouriteService < BaseService
     ).as_json).sign!(favourite.account))
   end
 
-  def build_xml(favourite)
-    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.favourite_salmon(favourite))
-  end
-
   def curate_status(status)
     return if status.curated || !status.distributable? || (status.reply? && status.in_reply_to_account_id != status.account_id)
     status.curated = true
diff --git a/app/services/fetch_atom_service.rb b/app/services/fetch_atom_service.rb
index d6508a988..ce148bfb4 100644
--- a/app/services/fetch_atom_service.rb
+++ b/app/services/fetch_atom_service.rb
@@ -7,11 +7,6 @@ class FetchAtomService < BaseService
     return if url.blank?
 
     result = process(url)
-
-    # retry without ActivityPub
-    result ||= process(url) if @unsupported_activity
-
-    result
   rescue OpenSSL::SSL::SSLError => e
     Rails.logger.debug "SSL error: #{e}"
     nil
@@ -28,8 +23,7 @@ class FetchAtomService < BaseService
   end
 
   def perform_request(&block)
-    accept = 'text/html'
-    accept = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/atom+xml, ' + accept unless @unsupported_activity
+    accept = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", text/html'
 
     Request.new(:get, @url).add_headers('Accept' => accept).perform(&block)
   end
@@ -37,17 +31,14 @@ class FetchAtomService < BaseService
   def process_response(response, terminal = false)
     return nil if response.code != 200
 
-    if response.mime_type == 'application/atom+xml'
-      [@url, { prefetched_body: response.body_with_limit }, :ostatus]
-    elsif ['application/activity+json', 'application/ld+json'].include?(response.mime_type)
+    if ['application/activity+json', 'application/ld+json'].include?(response.mime_type)
       body = response.body_with_limit
       json = body_to_json(body)
       if supported_context?(json) && equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) && json['inbox'].present?
-        [json['id'], { prefetched_body: body, id: true }, :activitypub]
+        [json['id'], { prefetched_body: body, id: true }]
       elsif supported_context?(json) && expected_type?(json)
-        [json['id'], { prefetched_body: body, id: true }, :activitypub]
+        [json['id'], { prefetched_body: body, id: true }]
       else
-        @unsupported_activity = true
         nil
       end
     elsif !terminal
@@ -69,21 +60,17 @@ class FetchAtomService < BaseService
     page = Nokogiri::HTML(response.body_with_limit)
 
     json_link = page.xpath('//link[@rel="alternate"]').find { |link| ['application/activity+json', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'].include?(link['type']) }
-    atom_link = page.xpath('//link[@rel="alternate"]').find { |link| link['type'] == 'application/atom+xml' }
-
-    result ||= process(json_link['href'], terminal: true) unless json_link.nil? || @unsupported_activity
-    result ||= process(atom_link['href'], terminal: true) unless atom_link.nil?
 
+    result = process(json_link['href'], terminal: true) unless json_link.nil?
+    result ||= nil
     result
   end
 
   def process_link_headers(link_header)
     json_link = link_header.find_link(%w(rel alternate), %w(type application/activity+json)) || link_header.find_link(%w(rel alternate), ['type', 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'])
-    atom_link = link_header.find_link(%w(rel alternate), %w(type application/atom+xml))
-
-    result ||= process(json_link.href, terminal: true) unless json_link.nil? || @unsupported_activity
-    result ||= process(atom_link.href, terminal: true) unless atom_link.nil?
 
+    result = process(json_link.href, terminal: true) unless json_link.nil?
+    result ||= nil
     result
   end
 
diff --git a/app/services/fetch_remote_account_service.rb b/app/services/fetch_remote_account_service.rb
index cfc560022..aed6a90c8 100644
--- a/app/services/fetch_remote_account_service.rb
+++ b/app/services/fetch_remote_account_service.rb
@@ -1,45 +1,15 @@
 # frozen_string_literal: true
 
 class FetchRemoteAccountService < BaseService
-  include AuthorExtractor
-
-  def call(url, prefetched_body = nil, protocol = :ostatus)
+  def call(url, prefetched_body = nil)
     if prefetched_body.nil?
-      resource_url, resource_options, protocol = FetchAtomService.new.call(url)
+      resource_url, resource_options = FetchAtomService.new.call(url)
     else
       resource_url     = url
       resource_options = { prefetched_body: prefetched_body }
     end
 
-    case protocol
-    when :ostatus
-      process_atom(resource_url, **resource_options)
-    when :activitypub
-      ActivityPub::FetchRemoteAccountService.new.call(resource_url, **resource_options)
-    end
-  end
-
-  private
-
-  def process_atom(url, prefetched_body:)
-    xml = Nokogiri::XML(prefetched_body)
-    xml.encoding = 'utf-8'
-
-    account = author_from_xml(xml.at_xpath('/xmlns:feed', xmlns: OStatus::TagManager::XMLNS), false)
-
-    UpdateRemoteProfileService.new.call(xml, account) if account.present? && trusted_domain?(url, account)
-
-    account
-  rescue TypeError
-    Rails.logger.debug "Unparseable URL given: #{url}"
-    nil
-  rescue Nokogiri::XML::XPath::SyntaxError
-    Rails.logger.debug 'Invalid XML or missing namespace'
-    nil
-  end
-
-  def trusted_domain?(url, account)
-    domain = Addressable::URI.parse(url).normalized_host
-    domain.casecmp(account.domain).zero? || domain.casecmp(Addressable::URI.parse(account.remote_url.presence || account.uri).normalized_host).zero?
+    return if resource_url.blank?
+    ActivityPub::FetchRemoteAccountService.new.call(resource_url, **resource_options)
   end
 end
diff --git a/app/services/fetch_remote_status_service.rb b/app/services/fetch_remote_status_service.rb
index 9c3008035..2c6dbb58d 100644
--- a/app/services/fetch_remote_status_service.rb
+++ b/app/services/fetch_remote_status_service.rb
@@ -1,45 +1,15 @@
 # frozen_string_literal: true
 
 class FetchRemoteStatusService < BaseService
-  include AuthorExtractor
-
-  def call(url, prefetched_body = nil, protocol = :ostatus)
+  def call(url, prefetched_body = nil)
     if prefetched_body.nil?
-      resource_url, resource_options, protocol = FetchAtomService.new.call(url)
+      resource_url, resource_options = FetchAtomService.new.call(url)
     else
       resource_url     = url
       resource_options = { prefetched_body: prefetched_body }
     end
 
-    case protocol
-    when :ostatus
-      process_atom(resource_url, **resource_options)
-    when :activitypub
-      ActivityPub::FetchRemoteStatusService.new.call(resource_url, **resource_options)
-    end
-  end
-
-  private
-
-  def process_atom(url, prefetched_body:)
-    Rails.logger.debug "Processing Atom for remote status at #{url}"
-
-    xml = Nokogiri::XML(prefetched_body)
-    xml.encoding = 'utf-8'
-
-    account = author_from_xml(xml.at_xpath('/xmlns:entry', xmlns: OStatus::TagManager::XMLNS))
-    domain  = Addressable::URI.parse(url).normalized_host
-
-    return nil unless !account.nil? && confirmed_domain?(domain, account)
-
-    statuses = ProcessFeedService.new.call(prefetched_body, account)
-    statuses.first
-  rescue Nokogiri::XML::XPath::SyntaxError
-    Rails.logger.debug 'Invalid XML or missing namespace'
-    nil
-  end
-
-  def confirmed_domain?(domain, account)
-    account.domain.nil? || domain.casecmp(account.domain).zero? || domain.casecmp(Addressable::URI.parse(account.remote_url.presence || account.uri).normalized_host).zero?
+    return if resource_url.blank?
+    ActivityPub::FetchRemoteStatusService.new.call(resource_url, **resource_options)
   end
 end
diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb
index 92d8c864a..3494dce99 100644
--- a/app/services/follow_service.rb
+++ b/app/services/follow_service.rb
@@ -29,10 +29,12 @@ class FollowService < BaseService
 
     ActivityTracker.increment('activity:interactions')
 
-    if target_account.locked? || target_account.activitypub?
-      request_follow(source_account, target_account, reblogs: reblogs)
+    if target_account.local? && !target_account.locked?
+      follow = source_account.follow!(target_account, reblogs: reblogs)
+      LocalNotificationWorker.perform_async(target_account.id, follow.id, follow.class.name)
+      follow
     else
-      direct_follow(source_account, target_account, reblogs: reblogs)
+      request_follow(source_account, target_account, reblogs: reblogs)
     end
   end
 
@@ -43,40 +45,13 @@ class FollowService < BaseService
 
     if target_account.local?
       LocalNotificationWorker.perform_async(target_account.id, follow_request.id, follow_request.class.name)
-    elsif target_account.ostatus?
-      NotificationWorker.perform_async(build_follow_request_xml(follow_request), source_account.id, target_account.id)
-      AfterRemoteFollowRequestWorker.perform_async(follow_request.id)
-    elsif target_account.activitypub?
+    else
       ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), source_account.id, target_account.inbox_url)
     end
 
     follow_request
   end
 
-  def direct_follow(source_account, target_account, reblogs: true)
-    follow = source_account.follow!(target_account, reblogs: reblogs)
-
-    if target_account.local?
-      LocalNotificationWorker.perform_async(target_account.id, follow.id, follow.class.name)
-    else
-      Pubsubhubbub::SubscribeWorker.perform_async(target_account.id) unless target_account.subscribed?
-      NotificationWorker.perform_async(build_follow_xml(follow), source_account.id, target_account.id)
-      AfterRemoteFollowWorker.perform_async(follow.id)
-    end
-
-    MergeWorker.perform_async(target_account.id, source_account.id)
-
-    follow
-  end
-
-  def build_follow_request_xml(follow_request)
-    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.follow_request_salmon(follow_request))
-  end
-
-  def build_follow_xml(follow)
-    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.follow_salmon(follow))
-  end
-
   def build_json(follow_request)
     ActiveModelSerializers::SerializableResource.new(
       follow_request,
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index b8de35e2a..1635fffa7 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -103,7 +103,6 @@ class PostStatusService < BaseService
     DistributionWorker.perform_async(@status.id)
 
     unless @status.local_only?
-      Pubsubhubbub::DistributionWorker.perform_async(@status.stream_entry.id)
       ActivityPub::DistributionWorker.perform_async(@status.id)
     end
 
diff --git a/app/services/process_feed_service.rb b/app/services/process_feed_service.rb
deleted file mode 100644
index 30a9dd85e..000000000
--- a/app/services/process_feed_service.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-class ProcessFeedService < BaseService
-  def call(body, account, **options)
-    @options = options
-
-    xml = Nokogiri::XML(body)
-    xml.encoding = 'utf-8'
-
-    update_author(body, account)
-    process_entries(xml, account)
-  end
-
-  private
-
-  def update_author(body, account)
-    RemoteProfileUpdateWorker.perform_async(account.id, body.force_encoding('UTF-8'), true)
-  end
-
-  def process_entries(xml, account)
-    xml.xpath('//xmlns:entry', xmlns: OStatus::TagManager::XMLNS).reverse_each.map { |entry| process_entry(entry, account) }.compact
-  end
-
-  def process_entry(xml, account)
-    activity = OStatus::Activity::General.new(xml, account, @options)
-    activity.specialize&.perform if activity.status?
-  rescue ActiveRecord::RecordInvalid => e
-    Rails.logger.debug "Nothing was saved for #{activity.id} because: #{e}"
-    nil
-  end
-end
diff --git a/app/services/process_hashtags_service.rb b/app/services/process_hashtags_service.rb
index 351248c69..68a87b11a 100644
--- a/app/services/process_hashtags_service.rb
+++ b/app/services/process_hashtags_service.rb
@@ -2,11 +2,14 @@
 
 class ProcessHashtagsService < BaseService
   def call(status, tags = [])
-    tags    = Extractor.extract_hashtags(status.text) if tags.blank? && status.local?
+    if status.local?
+      tags = Extractor.extract_hashtags(status.text) | (tags.nil? ? [] : tags)
+    end
     records = []
 
     tags.map { |str| str.mb_chars.downcase }.uniq(&:to_s).each do |name|
       name = name.gsub(/::+/, ':')
+      next if name.blank?
       component_indices = name.size.times.select {|i| name[i] == ':'}
       component_indices << name.size - 1
       component_indices.take(6).each_with_index do |i, nest|
diff --git a/app/services/process_interaction_service.rb b/app/services/process_interaction_service.rb
deleted file mode 100644
index 1fca3832b..000000000
--- a/app/services/process_interaction_service.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-# frozen_string_literal: true
-
-class ProcessInteractionService < BaseService
-  include AuthorExtractor
-  include Authorization
-
-  # Record locally the remote interaction with our user
-  # @param [String] envelope Salmon envelope
-  # @param [Account] target_account Account the Salmon was addressed to
-  def call(envelope, target_account)
-    body = salmon.unpack(envelope)
-
-    xml = Nokogiri::XML(body)
-    xml.encoding = 'utf-8'
-
-    account = author_from_xml(xml.at_xpath('/xmlns:entry', xmlns: OStatus::TagManager::XMLNS))
-
-    return if account.nil? || account.suspended?
-
-    if salmon.verify(envelope, account.keypair)
-      RemoteProfileUpdateWorker.perform_async(account.id, body.force_encoding('UTF-8'), true)
-
-      case verb(xml)
-      when :follow
-        follow!(account, target_account) unless target_account.locked? || target_account.blocking?(account) || target_account.domain_blocking?(account.domain)
-      when :request_friend
-        follow_request!(account, target_account) unless !target_account.locked? || target_account.blocking?(account) || target_account.domain_blocking?(account.domain)
-      when :authorize
-        authorize_follow_request!(account, target_account)
-      when :reject
-        reject_follow_request!(account, target_account)
-      when :unfollow
-        unfollow!(account, target_account)
-      when :favorite
-        favourite!(xml, account)
-      when :unfavorite
-        unfavourite!(xml, account)
-      when :post
-        add_post!(body, account) if mentions_account?(xml, target_account)
-      when :share
-        add_post!(body, account) unless status(xml).nil?
-      when :delete
-        delete_post!(xml, account)
-      when :block
-        reflect_block!(account, target_account)
-      when :unblock
-        reflect_unblock!(account, target_account)
-      end
-    end
-  rescue HTTP::Error, OStatus2::BadSalmonError, Mastodon::NotPermittedError
-    nil
-  end
-
-  private
-
-  def mentions_account?(xml, account)
-    xml.xpath('/xmlns:entry/xmlns:link[@rel="mentioned"]', xmlns: OStatus::TagManager::XMLNS).each { |mention_link| return true if [OStatus::TagManager.instance.uri_for(account), OStatus::TagManager.instance.url_for(account)].include?(mention_link.attribute('href').value) }
-    false
-  end
-
-  def verb(xml)
-    raw = xml.at_xpath('//activity:verb', activity: OStatus::TagManager::AS_XMLNS).content
-    OStatus::TagManager::VERBS.key(raw)
-  rescue
-    :post
-  end
-
-  def follow!(account, target_account)
-    follow = account.follow!(target_account)
-    FollowRequest.find_by(account: account, target_account: target_account)&.destroy
-    NotifyService.new.call(target_account, follow)
-  end
-
-  def follow_request!(account, target_account)
-    return if account.requested?(target_account)
-
-    follow_request = FollowRequest.create!(account: account, target_account: target_account)
-    NotifyService.new.call(target_account, follow_request)
-  end
-
-  def authorize_follow_request!(account, target_account)
-    follow_request = FollowRequest.find_by(account: target_account, target_account: account)
-    follow_request&.authorize!
-    Pubsubhubbub::SubscribeWorker.perform_async(account.id) unless account.subscribed?
-  end
-
-  def reject_follow_request!(account, target_account)
-    follow_request = FollowRequest.find_by(account: target_account, target_account: account)
-    follow_request&.reject!
-  end
-
-  def unfollow!(account, target_account)
-    account.unfollow!(target_account)
-    FollowRequest.find_by(account: account, target_account: target_account)&.destroy
-  end
-
-  def reflect_block!(account, target_account)
-    UnfollowService.new.call(target_account, account) if target_account.following?(account)
-    account.block!(target_account)
-  end
-
-  def reflect_unblock!(account, target_account)
-    UnblockService.new.call(account, target_account)
-  end
-
-  def delete_post!(xml, account)
-    status = Status.find(xml.at_xpath('//xmlns:id', xmlns: OStatus::TagManager::XMLNS).content)
-
-    return if status.nil?
-
-    authorize_with account, status, :destroy?
-
-    RemovalWorker.perform_async(status.id)
-  end
-
-  def favourite!(xml, from_account)
-    current_status = status(xml)
-
-    return if current_status.nil?
-
-    favourite = current_status.favourites.where(account: from_account).first_or_create!(account: from_account)
-    NotifyService.new.call(current_status.account, favourite)
-  end
-
-  def unfavourite!(xml, from_account)
-    current_status = status(xml)
-
-    return if current_status.nil?
-
-    favourite = current_status.favourites.where(account: from_account).first
-    favourite&.destroy
-  end
-
-  def add_post!(body, account)
-    ProcessingWorker.perform_async(account.id, body.force_encoding('UTF-8'))
-  end
-
-  def status(xml)
-    uri = activity_id(xml)
-    return nil unless OStatus::TagManager.instance.local_id?(uri)
-    Status.find(OStatus::TagManager.instance.unique_tag_to_local_id(uri, 'Status'))
-  end
-
-  def activity_id(xml)
-    xml.at_xpath('//activity:object', activity: OStatus::TagManager::AS_XMLNS).at_xpath('./xmlns:id', xmlns: OStatus::TagManager::XMLNS).content
-  end
-
-  def salmon
-    @salmon ||= OStatus2::Salmon.new
-  end
-end
diff --git a/app/services/process_mentions_service.rb b/app/services/process_mentions_service.rb
index 0d5f44a53..f0d3d5fcb 100644
--- a/app/services/process_mentions_service.rb
+++ b/app/services/process_mentions_service.rb
@@ -1,11 +1,8 @@
 # frozen_string_literal: true
 
 class ProcessMentionsService < BaseService
-  include StreamEntryRenderer
-
   # Scan status for mentions and fetch remote mentioned users, create
-  # local mention pointers, send Salmon notifications to mentioned
-  # remote users
+  # local mention pointers
   # @param [Status] status
   def call(status)
     return unless status.local? && !status.draft?
@@ -40,7 +37,7 @@ class ProcessMentionsService < BaseService
   private
 
   def mention_undeliverable?(mentioned_account)
-    mentioned_account.nil? || (!mentioned_account.local? && mentioned_account.ostatus? && @status.stream_entry.hidden?)
+    mentioned_account.nil?
   end
 
   def create_notification(mention)
@@ -48,17 +45,11 @@ class ProcessMentionsService < BaseService
 
     if mentioned_account.local?
       LocalNotificationWorker.perform_async(mentioned_account.id, mention.id, mention.class.name)
-    elsif mentioned_account.ostatus? && !@status.stream_entry.hidden? && !@status.local_only?
-      NotificationWorker.perform_async(ostatus_xml, @status.account_id, mentioned_account.id)
-    elsif mentioned_account.activitypub? && !@status.local_only?
+    elsif !@status.local_only?
       ActivityPub::DeliveryWorker.perform_async(activitypub_json, mention.status.account_id, mentioned_account.inbox_url)
     end
   end
 
-  def ostatus_xml
-    @ostatus_xml ||= stream_entry_to_xml(@status.stream_entry)
-  end
-
   def activitypub_json
     return @activitypub_json if defined?(@activitypub_json)
     payload = ActiveModelSerializers::SerializableResource.new(
diff --git a/app/services/pubsubhubbub/subscribe_service.rb b/app/services/pubsubhubbub/subscribe_service.rb
deleted file mode 100644
index 550da6328..000000000
--- a/app/services/pubsubhubbub/subscribe_service.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-class Pubsubhubbub::SubscribeService < BaseService
-  URL_PATTERN = /\A#{URI.regexp(%w(http https))}\z/
-
-  attr_reader :account, :callback, :secret,
-              :lease_seconds, :domain
-
-  def call(account, callback, secret, lease_seconds, verified_domain = nil)
-    @account       = account
-    @callback      = Addressable::URI.parse(callback).normalize.to_s
-    @secret        = secret
-    @lease_seconds = lease_seconds
-    @domain        = verified_domain
-
-    process_subscribe
-  end
-
-  private
-
-  def process_subscribe
-    if account.nil?
-      ['Invalid topic URL', 422]
-    elsif !valid_callback?
-      ['Invalid callback URL', 422]
-    elsif blocked_domain?
-      ['Callback URL not allowed', 403]
-    else
-      confirm_subscription
-      ['', 202]
-    end
-  end
-
-  def confirm_subscription
-    subscription = locate_subscription
-    Pubsubhubbub::ConfirmationWorker.perform_async(subscription.id, 'subscribe', secret, lease_seconds)
-  end
-
-  def valid_callback?
-    callback.present? && callback =~ URL_PATTERN
-  end
-
-  def blocked_domain?
-    DomainBlock.blocked? Addressable::URI.parse(callback).host
-  end
-
-  def locate_subscription
-    subscription = Subscription.find_or_initialize_by(account: account, callback_url: callback)
-    subscription.domain = domain
-    subscription.save!
-    subscription
-  end
-end
diff --git a/app/services/pubsubhubbub/unsubscribe_service.rb b/app/services/pubsubhubbub/unsubscribe_service.rb
deleted file mode 100644
index 646150f7b..000000000
--- a/app/services/pubsubhubbub/unsubscribe_service.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-class Pubsubhubbub::UnsubscribeService < BaseService
-  attr_reader :account, :callback
-
-  def call(account, callback)
-    @account  = account
-    @callback = Addressable::URI.parse(callback).normalize.to_s
-
-    process_unsubscribe
-  end
-
-  private
-
-  def process_unsubscribe
-    if account.nil?
-      ['Invalid topic URL', 422]
-    else
-      confirm_unsubscribe unless subscription.nil?
-      ['', 202]
-    end
-  end
-
-  def confirm_unsubscribe
-    Pubsubhubbub::ConfirmationWorker.perform_async(subscription.id, 'unsubscribe')
-  end
-
-  def subscription
-    @_subscription ||= Subscription.find_by(account: account, callback_url: callback)
-  end
-end
diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb
index 1a39c6c95..847bd6fbf 100644
--- a/app/services/reblog_service.rb
+++ b/app/services/reblog_service.rb
@@ -2,7 +2,6 @@
 
 class ReblogService < BaseService
   include Authorization
-  include StreamEntryRenderer
 
   # Reblog a status and notify its remote author
   # @param [Account] account Account to reblog from
@@ -25,7 +24,6 @@ class ReblogService < BaseService
     DistributionWorker.perform_async(reblog.id)
 
     unless reblogged_status.local_only?
-      Pubsubhubbub::DistributionWorker.perform_async(reblog.stream_entry.id)
       ActivityPub::DistributionWorker.perform_async(reblog.id)
     end
 
@@ -43,9 +41,7 @@ class ReblogService < BaseService
 
     if reblogged_status.account.local?
       LocalNotificationWorker.perform_async(reblogged_status.account_id, reblog.id, reblog.class.name)
-    elsif reblogged_status.account.ostatus?
-      NotificationWorker.perform_async(stream_entry_to_xml(reblog.stream_entry), reblog.account_id, reblogged_status.account_id)
-    elsif reblogged_status.account.activitypub? && !reblogged_status.account.following?(reblog.account)
+    elsif !reblogged_status.account.following?(reblog.account)
       ActivityPub::DeliveryWorker.perform_async(build_json(reblog), reblog.account_id, reblogged_status.account.inbox_url)
     end
   end
diff --git a/app/services/reject_follow_service.rb b/app/services/reject_follow_service.rb
index a91266aa4..f18c99583 100644
--- a/app/services/reject_follow_service.rb
+++ b/app/services/reject_follow_service.rb
@@ -11,11 +11,7 @@ class RejectFollowService < BaseService
   private
 
   def create_notification(follow_request)
-    if follow_request.account.ostatus?
-      NotificationWorker.perform_async(build_xml(follow_request), follow_request.target_account_id, follow_request.account_id)
-    elsif follow_request.account.activitypub?
-      ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), follow_request.target_account_id, follow_request.account.inbox_url)
-    end
+    ActivityPub::DeliveryWorker.perform_async(build_json(follow_request), follow_request.target_account_id, follow_request.account.inbox_url)
   end
 
   def build_json(follow_request)
@@ -25,8 +21,4 @@ class RejectFollowService < BaseService
       adapter: ActivityPub::Adapter
     ).to_json
   end
-
-  def build_xml(follow_request)
-    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request))
-  end
 end
diff --git a/app/services/remove_status_service.rb b/app/services/remove_status_service.rb
index 9f3b2d32c..d55ecadef 100644
--- a/app/services/remove_status_service.rb
+++ b/app/services/remove_status_service.rb
@@ -1,7 +1,6 @@
 # frozen_string_literal: true
 
 class RemoveStatusService < BaseService
-  include StreamEntryRenderer
   include Redisable
 
   MIN_SCHEDULE_OFFSET = 60.seconds.freeze
@@ -80,22 +79,12 @@ class RemoveStatusService < BaseService
     target_accounts << @status.reblog.account if @status.reblog? && !@status.reblog.account.local?
     target_accounts.uniq!(&:id)
 
-    # Ostatus
-    NotificationWorker.push_bulk(target_accounts.select(&:ostatus?).uniq(&:domain)) do |target_account|
-      [salmon_xml, @account.id, target_account.id]
-    end
-
-    # ActivityPub
-    ActivityPub::DeliveryWorker.push_bulk(target_accounts.select(&:activitypub?).uniq(&:preferred_inbox_url)) do |target_account|
+    ActivityPub::DeliveryWorker.push_bulk(target_accounts.uniq(&:preferred_inbox_url)) do |target_account|
       [signed_activity_json, @account.id, target_account.preferred_inbox_url]
     end
   end
 
   def remove_from_remote_followers
-    # OStatus
-    Pubsubhubbub::RawDistributionWorker.perform_async(salmon_xml, @account.id)
-
-    # ActivityPub
     ActivityPub::DeliveryWorker.push_bulk(@account.followers.inboxes) do |inbox_url|
       [signed_activity_json, @account.id, inbox_url]
     end
@@ -113,10 +102,6 @@ class RemoveStatusService < BaseService
     end
   end
 
-  def salmon_xml
-    @salmon_xml ||= stream_entry_to_xml(@stream_entry)
-  end
-
   def signed_activity_json
     @signed_activity_json ||= Oj.dump(ActivityPub::LinkedDataSignature.new(activity_json).sign!(@account))
   end
diff --git a/app/services/resolve_account_service.rb b/app/services/resolve_account_service.rb
index 11e33a83a..415abd78f 100644
--- a/app/services/resolve_account_service.rb
+++ b/app/services/resolve_account_service.rb
@@ -1,7 +1,6 @@
 # frozen_string_literal: true
 
 class ResolveAccountService < BaseService
-  include OStatus2::MagicKey
   include JsonLdHelper
 
   DFRN_NS = 'http://purl.org/macgirvin/dfrn/1.0'
@@ -48,18 +47,13 @@ class ResolveAccountService < BaseService
       return
     end
 
-    return if links_missing?
+    return unless activitypub_ready?
     return Account.find_local(@username) if TagManager.instance.local_domain?(@domain)
 
     RedisLock.acquire(lock_options) do |lock|
       if lock.acquired?
         @account = Account.find_remote(@username, @domain)
-
-        if activitypub_ready? || @account&.activitypub?
-          handle_activitypub
-        else
-          handle_ostatus
-        end
+        handle_activitypub if activitypub_ready?
       else
         raise Mastodon::RaceConditionError
       end
@@ -73,21 +67,8 @@ class ResolveAccountService < BaseService
 
   private
 
-  def links_missing?
-    !(activitypub_ready? || ostatus_ready?)
-  end
-
-  def ostatus_ready?
-    !(@webfinger.link('http://schemas.google.com/g/2010#updates-from').nil? ||
-      @webfinger.link('salmon').nil? ||
-      @webfinger.link('http://webfinger.net/rel/profile-page').nil? ||
-      @webfinger.link('magic-public-key').nil? ||
-      canonical_uri.nil? ||
-      hub_url.nil?)
-  end
-
   def webfinger_update_due?
-    @account.nil? || ((!@options[:skip_webfinger] || @account.ostatus?) && @account.possibly_stale?)
+    @account.nil? || @account.inbox_url.blank? || (!@options[:skip_webfinger] && @account.possibly_stale?)
   end
 
   def activitypub_ready?
@@ -97,16 +78,6 @@ class ResolveAccountService < BaseService
       actor_json['inbox'].present?
   end
 
-  def handle_ostatus
-    create_account if @account.nil?
-    update_account
-    update_account_profile if update_profile?
-  end
-
-  def update_profile?
-    @options[:update_profile]
-  end
-
   def handle_activitypub
     return if actor_json.nil?
 
@@ -115,89 +86,10 @@ class ResolveAccountService < BaseService
     nil
   end
 
-  def create_account
-    Rails.logger.debug "Creating new remote account for #{@username}@#{@domain}"
-
-    @account = Account.new(username: @username, domain: @domain)
-    @account.suspended_at = domain_block.created_at if auto_suspend?
-    @account.silenced_at  = domain_block.created_at if auto_silence?
-    @account.private_key  = nil
-  end
-
-  def update_account
-    @account.last_webfingered_at = Time.now.utc
-    @account.protocol            = :ostatus
-    @account.remote_url          = atom_url
-    @account.salmon_url          = salmon_url
-    @account.url                 = url
-    @account.public_key          = public_key
-    @account.uri                 = canonical_uri
-    @account.hub_url             = hub_url
-    @account.save!
-  end
-
-  def auto_suspend?
-    domain_block&.suspend?
-  end
-
-  def auto_silence?
-    domain_block&.silence?
-  end
-
-  def domain_block
-    return @domain_block if defined?(@domain_block)
-    @domain_block = DomainBlock.find_by(domain: @domain)
-  end
-
-  def atom_url
-    @atom_url ||= @webfinger.link('http://schemas.google.com/g/2010#updates-from').href
-  end
-
-  def salmon_url
-    @salmon_url ||= @webfinger.link('salmon').href
-  end
-
   def actor_url
     @actor_url ||= @webfinger.link('self').href
   end
 
-  def url
-    @url ||= @webfinger.link('http://webfinger.net/rel/profile-page').href
-  end
-
-  def public_key
-    @public_key ||= magic_key_to_pem(@webfinger.link('magic-public-key').href)
-  end
-
-  def canonical_uri
-    return @canonical_uri if defined?(@canonical_uri)
-
-    author_uri = atom.at_xpath('/xmlns:feed/xmlns:author/xmlns:uri')
-
-    if author_uri.nil?
-      owner      = atom.at_xpath('/xmlns:feed').at_xpath('./dfrn:owner', dfrn: DFRN_NS)
-      author_uri = owner.at_xpath('./xmlns:uri') unless owner.nil?
-    end
-
-    @canonical_uri = author_uri.nil? ? nil : author_uri.content
-  end
-
-  def hub_url
-    return @hub_url if defined?(@hub_url)
-
-    hubs     = atom.xpath('//xmlns:link[@rel="hub"]')
-    @hub_url = hubs.empty? || hubs.first['href'].nil? ? nil : hubs.first['href']
-  end
-
-  def atom_body
-    return @atom_body if defined?(@atom_body)
-
-    @atom_body = Request.new(:get, atom_url).perform do |response|
-      raise Mastodon::UnexpectedResponseError, response unless response.code == 200
-      response.body_with_limit
-    end
-  end
-
   def actor_json
     return @actor_json if defined?(@actor_json)
 
@@ -205,15 +97,6 @@ class ResolveAccountService < BaseService
     @actor_json = supported_context?(json) && equals_or_includes_any?(json['type'], ActivityPub::FetchRemoteAccountService::SUPPORTED_TYPES) ? json : nil
   end
 
-  def atom
-    return @atom if defined?(@atom)
-    @atom = Nokogiri::XML(atom_body)
-  end
-
-  def update_account_profile
-    RemoteProfileUpdateWorker.perform_async(@account.id, atom_body.force_encoding('UTF-8'), false)
-  end
-
   def lock_options
     { redis: Redis.current, key: "resolve:#{@username}@#{@domain}" }
   end
diff --git a/app/services/resolve_url_service.rb b/app/services/resolve_url_service.rb
index b98759bf6..89a31c9ed 100644
--- a/app/services/resolve_url_service.rb
+++ b/app/services/resolve_url_service.rb
@@ -19,9 +19,9 @@ class ResolveURLService < BaseService
 
   def process_url
     if equals_or_includes_any?(type, %w(Application Group Organization Person Service))
-      FetchRemoteAccountService.new.call(atom_url, body, protocol)
+      FetchRemoteAccountService.new.call(atom_url, body)
     elsif equals_or_includes_any?(type, %w(Note Article Image Video Page Question))
-      FetchRemoteStatusService.new.call(atom_url, body, protocol)
+      FetchRemoteStatusService.new.call(atom_url, body)
     end
   end
 
@@ -37,33 +37,14 @@ class ResolveURLService < BaseService
     fetched_atom_feed.second[:prefetched_body]
   end
 
-  def protocol
-    fetched_atom_feed.third
-  end
-
   def type
-    return json_data['type'] if protocol == :activitypub
-
-    case xml_root
-    when 'feed'
-      'Person'
-    when 'entry'
-      'Note'
-    end
+    return json_data['type'] unless json_data.nil?
   end
 
   def json_data
     @_json_data ||= body_to_json(body)
   end
 
-  def xml_root
-    xml_data.root.name
-  end
-
-  def xml_data
-    @_xml_data ||= Nokogiri::XML(body, nil, 'utf-8')
-  end
-
   def local_url?
     TagManager.instance.local_url?(@url)
   end
diff --git a/app/services/send_interaction_service.rb b/app/services/send_interaction_service.rb
deleted file mode 100644
index 3419043e5..000000000
--- a/app/services/send_interaction_service.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# frozen_string_literal: true
-
-class SendInteractionService < BaseService
-  # Send an Atom representation of an interaction to a remote Salmon endpoint
-  # @param [String] Entry XML
-  # @param [Account] source_account
-  # @param [Account] target_account
-  def call(xml, source_account, target_account)
-    @xml            = xml
-    @source_account = source_account
-    @target_account = target_account
-
-    return if !target_account.ostatus? || block_notification?
-
-    build_request.perform do |delivery|
-      raise Mastodon::UnexpectedResponseError, delivery unless delivery.code > 199 && delivery.code < 300
-    end
-  end
-
-  private
-
-  def build_request
-    request = Request.new(:post, @target_account.salmon_url, body: envelope)
-    request.add_headers('Content-Type' => 'application/magic-envelope+xml')
-    request
-  end
-
-  def envelope
-    salmon.pack(@xml, @source_account.keypair)
-  end
-
-  def block_notification?
-    DomainBlock.blocked?(@target_account.domain)
-  end
-
-  def salmon
-    @salmon ||= OStatus2::Salmon.new
-  end
-end
diff --git a/app/services/subscribe_service.rb b/app/services/subscribe_service.rb
deleted file mode 100644
index 83fd64396..000000000
--- a/app/services/subscribe_service.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-class SubscribeService < BaseService
-  def call(account)
-    return if account.hub_url.blank?
-
-    @account        = account
-    @account.secret = SecureRandom.hex
-
-    build_request.perform do |response|
-      if response_failed_permanently? response
-        # We're not allowed to subscribe. Fail and move on.
-        @account.secret = ''
-        @account.save!
-      elsif response_successful? response
-        # The subscription will be confirmed asynchronously.
-        @account.save!
-      else
-        # The response was either a 429 rate limit, or a 5xx error.
-        # We need to retry at a later time. Fail loudly!
-        raise Mastodon::UnexpectedResponseError, response
-      end
-    end
-  end
-
-  private
-
-  def build_request
-    request = Request.new(:post, @account.hub_url, form: subscription_params)
-    request.on_behalf_of(some_local_account) if some_local_account
-    request
-  end
-
-  def subscription_params
-    {
-      'hub.topic': @account.remote_url,
-      'hub.mode': 'subscribe',
-      'hub.callback': api_subscription_url(@account.id),
-      'hub.verify': 'async',
-      'hub.secret': @account.secret,
-      'hub.lease_seconds': 7.days.seconds,
-    }
-  end
-
-  def some_local_account
-    @some_local_account ||= Account.local.without_suspended.first
-  end
-
-  # Any response in the 3xx or 4xx range, except for 429 (rate limit)
-  def response_failed_permanently?(response)
-    (response.status.redirect? || response.status.client_error?) && !response.status.too_many_requests?
-  end
-
-  # Any response in the 2xx range
-  def response_successful?(response)
-    response.status.success?
-  end
-end
diff --git a/app/services/suspend_account_service.rb b/app/services/suspend_account_service.rb
index 412873f84..b2e4eca26 100644
--- a/app/services/suspend_account_service.rb
+++ b/app/services/suspend_account_service.rb
@@ -50,7 +50,7 @@ class SuspendAccountService < BaseService
   private
 
   def reject_follows!
-    return if @account.local? || !@account.activitypub?
+    return if @account.local?
 
     ActivityPub::DeliveryWorker.push_bulk(Follow.where(account: @account)) do |follow|
       [build_reject_json(follow), follow.target_account_id, follow.account.inbox_url]
diff --git a/app/services/unblock_service.rb b/app/services/unblock_service.rb
index 72fc5ab15..c85d31b96 100644
--- a/app/services/unblock_service.rb
+++ b/app/services/unblock_service.rb
@@ -12,11 +12,7 @@ class UnblockService < BaseService
   private
 
   def create_notification(unblock)
-    if unblock.target_account.ostatus?
-      NotificationWorker.perform_async(build_xml(unblock), unblock.account_id, unblock.target_account_id)
-    elsif unblock.target_account.activitypub?
-      ActivityPub::DeliveryWorker.perform_async(build_json(unblock), unblock.account_id, unblock.target_account.inbox_url)
-    end
+    ActivityPub::DeliveryWorker.perform_async(build_json(unblock), unblock.account_id, unblock.target_account.inbox_url)
   end
 
   def build_json(unblock)
@@ -26,8 +22,4 @@ class UnblockService < BaseService
       adapter: ActivityPub::Adapter
     ).to_json
   end
-
-  def build_xml(block)
-    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unblock_salmon(block))
-  end
 end
diff --git a/app/services/unfavourite_service.rb b/app/services/unfavourite_service.rb
index 2fda11bd6..538ab2a8a 100644
--- a/app/services/unfavourite_service.rb
+++ b/app/services/unfavourite_service.rb
@@ -12,12 +12,7 @@ class UnfavouriteService < BaseService
 
   def create_notification(favourite)
     status = favourite.status
-
-    if status.account.ostatus?
-      NotificationWorker.perform_async(build_xml(favourite), favourite.account_id, status.account_id)
-    elsif status.account.activitypub?
-      ActivityPub::DeliveryWorker.perform_async(build_json(favourite), favourite.account_id, status.account.inbox_url)
-    end
+    ActivityPub::DeliveryWorker.perform_async(build_json(favourite), favourite.account_id, status.account.inbox_url)
   end
 
   def build_json(favourite)
@@ -27,8 +22,4 @@ class UnfavouriteService < BaseService
       adapter: ActivityPub::Adapter
     ).as_json).sign!(favourite.account))
   end
-
-  def build_xml(favourite)
-    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unfavourite_salmon(favourite))
-  end
 end
diff --git a/app/services/unfollow_service.rb b/app/services/unfollow_service.rb
index 95da2a667..e11f19e14 100644
--- a/app/services/unfollow_service.rb
+++ b/app/services/unfollow_service.rb
@@ -36,16 +36,11 @@ class UnfollowService < BaseService
   end
 
   def create_notification(follow)
-    if follow.target_account.ostatus?
-      NotificationWorker.perform_async(build_xml(follow), follow.account_id, follow.target_account_id)
-    elsif follow.target_account.activitypub?
-      ActivityPub::DeliveryWorker.perform_async(build_json(follow), follow.account_id, follow.target_account.inbox_url)
-    end
+    ActivityPub::DeliveryWorker.perform_async(build_json(follow), follow.account_id, follow.target_account.inbox_url)
   end
 
   def create_reject_notification(follow)
     # Rejecting an already-existing follow request
-    return unless follow.account.activitypub?
     ActivityPub::DeliveryWorker.perform_async(build_reject_json(follow), follow.target_account_id, follow.account.inbox_url)
   end
 
@@ -64,8 +59,4 @@ class UnfollowService < BaseService
       adapter: ActivityPub::Adapter
     ).to_json
   end
-
-  def build_xml(follow)
-    OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.unfollow_salmon(follow))
-  end
 end
diff --git a/app/services/unsubscribe_service.rb b/app/services/unsubscribe_service.rb
deleted file mode 100644
index 95c1fb4fc..000000000
--- a/app/services/unsubscribe_service.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# frozen_string_literal: true
-
-class UnsubscribeService < BaseService
-  def call(account)
-    return if account.hub_url.blank?
-
-    @account = account
-
-    begin
-      build_request.perform do |response|
-        Rails.logger.debug "PuSH unsubscribe for #{@account.acct} failed: #{response.status}" unless response.status.success?
-      end
-    rescue HTTP::Error, OpenSSL::SSL::SSLError => e
-      Rails.logger.debug "PuSH unsubscribe for #{@account.acct} failed: #{e}"
-    end
-
-    @account.secret = ''
-    @account.subscription_expires_at = nil
-    @account.save!
-  end
-
-  private
-
-  def build_request
-    Request.new(:post, @account.hub_url, form: subscription_params)
-  end
-
-  def subscription_params
-    {
-      'hub.topic': @account.remote_url,
-      'hub.mode': 'unsubscribe',
-      'hub.callback': api_subscription_url(@account.id),
-      'hub.verify': 'async',
-    }
-  end
-end
diff --git a/app/services/update_remote_profile_service.rb b/app/services/update_remote_profile_service.rb
deleted file mode 100644
index 68d36addf..000000000
--- a/app/services/update_remote_profile_service.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-# frozen_string_literal: true
-
-class UpdateRemoteProfileService < BaseService
-  attr_reader :account, :remote_profile
-
-  def call(body, account, resubscribe = false)
-    @account        = account
-    @remote_profile = RemoteProfile.new(body)
-
-    return if remote_profile.root.nil?
-
-    update_account unless remote_profile.author.nil?
-
-    old_hub_url     = account.hub_url
-    account.hub_url = remote_profile.hub_link if remote_profile.hub_link.present? && remote_profile.hub_link != old_hub_url
-
-    account.save_with_optional_media!
-
-    Pubsubhubbub::SubscribeWorker.perform_async(account.id) if resubscribe && account.hub_url != old_hub_url
-  end
-
-  private
-
-  def update_account
-    account.display_name = remote_profile.display_name || ''
-    account.note         = remote_profile.note         || ''
-    account.locked       = remote_profile.locked?
-
-    if !account.suspended? && !DomainBlock.find_by(domain: account.domain)&.reject_media?
-      if remote_profile.avatar.present?
-        account.avatar_remote_url = remote_profile.avatar
-      else
-        account.avatar_remote_url = ''
-        account.avatar.destroy
-      end
-
-      if remote_profile.header.present?
-        account.header_remote_url = remote_profile.header
-      else
-        account.header_remote_url = ''
-        account.header.destroy
-      end
-
-      save_emojis if remote_profile.emojis.present?
-    end
-  end
-
-  def save_emojis
-    do_not_download = DomainBlock.find_by(domain: account.domain)&.reject_media?
-
-    return if do_not_download
-
-    remote_profile.emojis.each do |link|
-      next unless link['href'] && link['name']
-
-      shortcode = link['name'].delete(':')
-      emoji     = CustomEmoji.find_by(shortcode: shortcode, domain: account.domain)
-
-      next unless emoji.nil?
-
-      emoji = CustomEmoji.new(shortcode: shortcode, domain: account.domain)
-      emoji.image_remote_url = link['href']
-      emoji.save
-    end
-  end
-end
diff --git a/app/services/verify_salmon_service.rb b/app/services/verify_salmon_service.rb
deleted file mode 100644
index 205b35d8b..000000000
--- a/app/services/verify_salmon_service.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# frozen_string_literal: true
-
-class VerifySalmonService < BaseService
-  include AuthorExtractor
-
-  def call(payload)
-    body = salmon.unpack(payload)
-
-    xml = Nokogiri::XML(body)
-    xml.encoding = 'utf-8'
-
-    account = author_from_xml(xml.at_xpath('/xmlns:entry', xmlns: OStatus::TagManager::XMLNS))
-
-    if account.nil?
-      false
-    else
-      salmon.verify(payload, account.keypair)
-    end
-  end
-
-  private
-
-  def salmon
-    @salmon ||= OStatus2::Salmon.new
-  end
-end
diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml
index aa7903304..21bbc3992 100644
--- a/app/views/accounts/show.html.haml
+++ b/app/views/accounts/show.html.haml
@@ -7,9 +7,6 @@
   - if @account.user&.setting_noindex
     %meta{ name: 'robots', content: 'noindex' }/
 
-  %link{ rel: 'salmon', href: api_salmon_url(@account.id) }/
-  %link{ rel: 'alternate', type: 'application/atom+xml', href: account_url(@account, format: 'atom') }/
-  %link{ rel: 'alternate', type: 'application/rss+xml', href: account_url(@account, format: 'rss') }/
   %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@account) }/
 
   - if @older_url
diff --git a/app/views/stream_entries/show.html.haml b/app/views/stream_entries/show.html.haml
index 0e81c4f68..5fd8f7a69 100644
--- a/app/views/stream_entries/show.html.haml
+++ b/app/views/stream_entries/show.html.haml
@@ -5,7 +5,6 @@
   - if @account.user&.setting_noindex
     %meta{ name: 'robots', content: 'noindex' }/
 
-  %link{ rel: 'alternate', type: 'application/atom+xml', href: account_stream_entry_url(@account, @stream_entry, format: 'atom') }/
   %link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: account_stream_entry_url(@account, @stream_entry), format: 'json') }/
   %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@stream_entry.activity) }/
 
diff --git a/app/views/well_known/webfinger/show.xml.ruby b/app/views/well_known/webfinger/show.xml.ruby
index 968c8c138..4eb303eef 100644
--- a/app/views/well_known/webfinger/show.xml.ruby
+++ b/app/views/well_known/webfinger/show.xml.ruby
@@ -14,31 +14,15 @@ doc << Ox::Element.new('XRD').tap do |xrd|
   end
 
   xrd << Ox::Element.new('Link').tap do |link|
-    link['rel']      = 'http://schemas.google.com/g/2010#updates-from'
-    link['type']     = 'application/atom+xml'
-    link['href']     = account_url(@account, format: 'atom')
-  end
-
-  xrd << Ox::Element.new('Link').tap do |link|
     link['rel']      = 'self'
     link['type']     = 'application/activity+json'
     link['href']     = account_url(@account)
   end
 
   xrd << Ox::Element.new('Link').tap do |link|
-    link['rel']      = 'salmon'
-    link['href']     = api_salmon_url(@account.id)
-  end
-
-  xrd << Ox::Element.new('Link').tap do |link|
     link['rel']      = 'magic-public-key'
     link['href']     = "data:application/magic-public-key,#{@account.magic_key}"
   end
-
-  xrd << Ox::Element.new('Link').tap do |link|
-    link['rel']      = 'http://ostatus.org/schema/1.0/subscribe'
-    link['template'] = "#{authorize_interaction_url}?acct={uri}"
-  end
 end
 
 ('<?xml version="1.0" encoding="UTF-8"?>' + Ox.dump(doc, effort: :tolerant)).force_encoding('UTF-8')
diff --git a/app/workers/activitypub/distribute_poll_update_worker.rb b/app/workers/activitypub/distribute_poll_update_worker.rb
index 98b227111..310e42433 100644
--- a/app/workers/activitypub/distribute_poll_update_worker.rb
+++ b/app/workers/activitypub/distribute_poll_update_worker.rb
@@ -31,7 +31,7 @@ class ActivityPub::DistributePollUpdateWorker
 
     @inboxes = [@status.mentions, @status.reblogs, @status.preloadable_poll.votes].flat_map do |relation|
       relation.includes(:account).map do |record|
-        record.account.preferred_inbox_url if !record.account.local? && record.account.activitypub?
+        record.account.preferred_inbox_url if !record.account.local?
       end
     end
 
diff --git a/app/workers/activitypub/post_upgrade_worker.rb b/app/workers/activitypub/post_upgrade_worker.rb
deleted file mode 100644
index 4154b8582..000000000
--- a/app/workers/activitypub/post_upgrade_worker.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# frozen_string_literal: true
-
-class ActivityPub::PostUpgradeWorker
-  include Sidekiq::Worker
-
-  sidekiq_options queue: 'pull'
-
-  def perform(domain)
-    Account.where(domain: domain)
-           .where(protocol: :ostatus)
-           .where.not(last_webfingered_at: nil)
-           .in_batches
-           .update_all(last_webfingered_at: nil)
-  end
-end
diff --git a/app/workers/notification_worker.rb b/app/workers/notification_worker.rb
deleted file mode 100644
index da1d6ab45..000000000
--- a/app/workers/notification_worker.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-class NotificationWorker
-  include Sidekiq::Worker
-
-  sidekiq_options queue: 'push', retry: 5
-
-  def perform(xml, source_account_id, target_account_id)
-    SendInteractionService.new.call(xml, Account.find(source_account_id), Account.find(target_account_id))
-  end
-end
diff --git a/app/workers/processing_worker.rb b/app/workers/processing_worker.rb
deleted file mode 100644
index 978c3aba2..000000000
--- a/app/workers/processing_worker.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-class ProcessingWorker
-  include Sidekiq::Worker
-
-  sidekiq_options backtrace: true
-
-  def perform(account_id, body)
-    ProcessFeedService.new.call(body, Account.find(account_id), override_timestamps: true)
-  end
-end
diff --git a/app/workers/pubsubhubbub/confirmation_worker.rb b/app/workers/pubsubhubbub/confirmation_worker.rb
deleted file mode 100644
index c0e7b677e..000000000
--- a/app/workers/pubsubhubbub/confirmation_worker.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-# frozen_string_literal: true
-
-class Pubsubhubbub::ConfirmationWorker
-  include Sidekiq::Worker
-  include RoutingHelper
-
-  sidekiq_options queue: 'push', retry: false
-
-  attr_reader :subscription, :mode, :secret, :lease_seconds
-
-  def perform(subscription_id, mode, secret = nil, lease_seconds = nil)
-    @subscription = Subscription.find(subscription_id)
-    @mode = mode
-    @secret = secret
-    @lease_seconds = lease_seconds
-    process_confirmation
-  end
-
-  private
-
-  def process_confirmation
-    prepare_subscription
-
-    callback_get_with_params
-    logger.debug "Confirming PuSH subscription for #{subscription.callback_url} with challenge #{challenge}: #{@callback_response_body}"
-
-    update_subscription
-  end
-
-  def update_subscription
-    if successful_subscribe?
-      subscription.save!
-    elsif successful_unsubscribe?
-      subscription.destroy!
-    end
-  end
-
-  def successful_subscribe?
-    subscribing? && response_matches_challenge?
-  end
-
-  def successful_unsubscribe?
-    (unsubscribing? && response_matches_challenge?) || !subscription.confirmed?
-  end
-
-  def response_matches_challenge?
-    @callback_response_body == challenge
-  end
-
-  def subscribing?
-    mode == 'subscribe'
-  end
-
-  def unsubscribing?
-    mode == 'unsubscribe'
-  end
-
-  def callback_get_with_params
-    Request.new(:get, subscription.callback_url, params: callback_params).perform do |response|
-      @callback_response_body = response.body_with_limit
-    end
-  end
-
-  def callback_params
-    {
-      'hub.topic': account_url(subscription.account, format: :atom),
-      'hub.mode': mode,
-      'hub.challenge': challenge,
-      'hub.lease_seconds': subscription.lease_seconds,
-    }
-  end
-
-  def prepare_subscription
-    subscription.secret = secret
-    subscription.lease_seconds = lease_seconds
-    subscription.confirmed = true
-  end
-
-  def challenge
-    @_challenge ||= SecureRandom.hex
-  end
-end
diff --git a/app/workers/pubsubhubbub/delivery_worker.rb b/app/workers/pubsubhubbub/delivery_worker.rb
deleted file mode 100644
index 619bfa48a..000000000
--- a/app/workers/pubsubhubbub/delivery_worker.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-# frozen_string_literal: true
-
-class Pubsubhubbub::DeliveryWorker
-  include Sidekiq::Worker
-  include RoutingHelper
-
-  sidekiq_options queue: 'push', retry: 3, dead: false
-
-  sidekiq_retry_in do |count|
-    5 * (count + 1)
-  end
-
-  attr_reader :subscription, :payload
-
-  def perform(subscription_id, payload)
-    @subscription = Subscription.find(subscription_id)
-    @payload = payload
-    process_delivery unless blocked_domain?
-  rescue => e
-    raise e.class, "Delivery failed for #{subscription&.callback_url}: #{e.message}", e.backtrace[0]
-  end
-
-  private
-
-  def process_delivery
-    callback_post_payload do |payload_delivery|
-      raise Mastodon::UnexpectedResponseError, payload_delivery unless response_successful? payload_delivery
-    end
-
-    subscription.touch(:last_successful_delivery_at)
-  end
-
-  def callback_post_payload(&block)
-    request = Request.new(:post, subscription.callback_url, body: payload)
-    request.add_headers(headers)
-    request.perform(&block)
-  end
-
-  def blocked_domain?
-    DomainBlock.blocked?(host)
-  end
-
-  def host
-    Addressable::URI.parse(subscription.callback_url).normalized_host
-  end
-
-  def headers
-    {
-      'Content-Type' => 'application/atom+xml',
-      'Link' => link_header,
-    }.merge(signature_headers.to_h)
-  end
-
-  def link_header
-    LinkHeader.new([hub_link_header, self_link_header]).to_s
-  end
-
-  def hub_link_header
-    [api_push_url, [%w(rel hub)]]
-  end
-
-  def self_link_header
-    [account_url(subscription.account, format: :atom), [%w(rel self)]]
-  end
-
-  def signature_headers
-    { 'X-Hub-Signature' => payload_signature } if subscription.secret?
-  end
-
-  def payload_signature
-    "sha1=#{hmac_payload_digest}"
-  end
-
-  def hmac_payload_digest
-    OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), subscription.secret, payload)
-  end
-
-  def response_successful?(payload_delivery)
-    payload_delivery.code > 199 && payload_delivery.code < 300
-  end
-end
diff --git a/app/workers/pubsubhubbub/distribution_worker.rb b/app/workers/pubsubhubbub/distribution_worker.rb
deleted file mode 100644
index fed5e917d..000000000
--- a/app/workers/pubsubhubbub/distribution_worker.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-class Pubsubhubbub::DistributionWorker
-  include Sidekiq::Worker
-
-  sidekiq_options queue: 'push'
-
-  def perform(stream_entry_ids)
-    stream_entries = StreamEntry.where(id: stream_entry_ids).includes(:status).reject { |e| e.status.nil? || e.status.hidden? }
-
-    return if stream_entries.empty?
-
-    @account       = stream_entries.first.account
-    @subscriptions = active_subscriptions.to_a
-
-    distribute_public!(stream_entries)
-  end
-
-  private
-
-  def distribute_public!(stream_entries)
-    @payload = OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, stream_entries))
-
-    Pubsubhubbub::DeliveryWorker.push_bulk(@subscriptions) do |subscription_id|
-      [subscription_id, @payload]
-    end
-  end
-
-  def active_subscriptions
-    Subscription.where(account: @account).active.pluck(:id)
-  end
-end
diff --git a/app/workers/pubsubhubbub/raw_distribution_worker.rb b/app/workers/pubsubhubbub/raw_distribution_worker.rb
deleted file mode 100644
index 16962a623..000000000
--- a/app/workers/pubsubhubbub/raw_distribution_worker.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-class Pubsubhubbub::RawDistributionWorker
-  include Sidekiq::Worker
-
-  sidekiq_options queue: 'push'
-
-  def perform(xml, source_account_id)
-    @account       = Account.find(source_account_id)
-    @subscriptions = active_subscriptions.to_a
-
-    Pubsubhubbub::DeliveryWorker.push_bulk(@subscriptions) do |subscription|
-      [subscription.id, xml]
-    end
-  end
-
-  private
-
-  def active_subscriptions
-    Subscription.where(account: @account).active.select('id, callback_url, domain')
-  end
-end
diff --git a/app/workers/pubsubhubbub/subscribe_worker.rb b/app/workers/pubsubhubbub/subscribe_worker.rb
deleted file mode 100644
index 2e176d1c1..000000000
--- a/app/workers/pubsubhubbub/subscribe_worker.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# frozen_string_literal: true
-
-class Pubsubhubbub::SubscribeWorker
-  include Sidekiq::Worker
-
-  sidekiq_options queue: 'push', retry: 10, unique: :until_executed, dead: false
-
-  sidekiq_retry_in do |count|
-    case count
-    when 0
-      30.minutes.seconds
-    when 1
-      2.hours.seconds
-    when 2
-      12.hours.seconds
-    else
-      24.hours.seconds * (count - 2)
-    end
-  end
-
-  sidekiq_retries_exhausted do |msg, _e|
-    account = Account.find(msg['args'].first)
-    Sidekiq.logger.error "PuSH subscription attempts for #{account.acct} exhausted. Unsubscribing"
-    ::UnsubscribeService.new.call(account)
-  end
-
-  def perform(account_id)
-    account = Account.find(account_id)
-    logger.debug "PuSH re-subscribing to #{account.acct}"
-    ::SubscribeService.new.call(account)
-  rescue => e
-    raise e.class, "Subscribe failed for #{account&.acct}: #{e.message}", e.backtrace[0]
-  end
-end
diff --git a/app/workers/pubsubhubbub/unsubscribe_worker.rb b/app/workers/pubsubhubbub/unsubscribe_worker.rb
deleted file mode 100644
index a271715b7..000000000
--- a/app/workers/pubsubhubbub/unsubscribe_worker.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# frozen_string_literal: true
-
-class Pubsubhubbub::UnsubscribeWorker
-  include Sidekiq::Worker
-
-  sidekiq_options queue: 'push', retry: false, unique: :until_executed, dead: false
-
-  def perform(account_id)
-    account = Account.find(account_id)
-    logger.debug "PuSH unsubscribing from #{account.acct}"
-    ::UnsubscribeService.new.call(account)
-  rescue ActiveRecord::RecordNotFound
-    true
-  end
-end
diff --git a/app/workers/refollow_worker.rb b/app/workers/refollow_worker.rb
index 12f2bf671..eb659a72e 100644
--- a/app/workers/refollow_worker.rb
+++ b/app/workers/refollow_worker.rb
@@ -7,7 +7,6 @@ class RefollowWorker
 
   def perform(target_account_id)
     target_account = Account.find(target_account_id)
-    return unless target_account.protocol == :activitypub
 
     target_account.followers.where(domain: nil).reorder(nil).find_each do |follower|
       # Locally unfollow remote account
diff --git a/app/workers/remote_profile_update_worker.rb b/app/workers/remote_profile_update_worker.rb
deleted file mode 100644
index 03585ad2d..000000000
--- a/app/workers/remote_profile_update_worker.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-class RemoteProfileUpdateWorker
-  include Sidekiq::Worker
-
-  sidekiq_options queue: 'pull'
-
-  def perform(account_id, body, resubscribe)
-    UpdateRemoteProfileService.new.call(body, Account.find(account_id), resubscribe)
-  rescue ActiveRecord::RecordNotFound
-    true
-  end
-end
diff --git a/app/workers/salmon_worker.rb b/app/workers/salmon_worker.rb
deleted file mode 100644
index d37d40432..000000000
--- a/app/workers/salmon_worker.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-class SalmonWorker
-  include Sidekiq::Worker
-
-  sidekiq_options backtrace: true
-
-  def perform(account_id, body)
-    ProcessInteractionService.new.call(body, Account.find(account_id))
-  rescue Nokogiri::XML::XPath::SyntaxError, ActiveRecord::RecordNotFound
-    true
-  end
-end
diff --git a/app/workers/scheduler/subscriptions_scheduler.rb b/app/workers/scheduler/subscriptions_scheduler.rb
deleted file mode 100644
index d5873bccb..000000000
--- a/app/workers/scheduler/subscriptions_scheduler.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-class Scheduler::SubscriptionsScheduler
-  include Sidekiq::Worker
-
-  sidekiq_options unique: :until_executed, retry: 0
-
-  def perform
-    Pubsubhubbub::SubscribeWorker.push_bulk(expiring_accounts.pluck(:id))
-  end
-
-  private
-
-  def expiring_accounts
-    Account.expiring(1.day.from_now).partitioned
-  end
-end