about summary refs log tree commit diff
diff options
context:
space:
mode:
authormultiple creatures <dev@multiple-creature.party>2019-05-06 20:51:20 -0500
committermultiple creatures <dev@multiple-creature.party>2019-05-21 03:16:23 -0500
commit6c374b51537126a2cba29f3eaf74faf1fc64ba96 (patch)
tree776239f0aaf7a0abed2d09440eccbb1d6d53a7a2
parent6e8ec7f0a538b5383da49c4435835b78c61da0bc (diff)
Drop OStatus support. Fix some of the Rspec tests.
-rw-r--r--Gemfile1
-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
-rw-r--r--config/routes.rb10
-rw-r--r--db/schema.rb1
-rw-r--r--spec/controllers/accounts_controller_spec.rb31
-rw-r--r--spec/controllers/api/push_controller_spec.rb59
-rw-r--r--spec/controllers/api/salmon_controller_spec.rb65
-rw-r--r--spec/controllers/api/subscriptions_controller_spec.rb68
-rw-r--r--spec/controllers/stream_entries_controller_spec.rb8
-rw-r--r--spec/lib/activitypub/activity/undo_spec.rb12
-rw-r--r--spec/lib/ostatus/atom_serializer_spec.rb1560
-rw-r--r--spec/models/account_spec.rb7
-rw-r--r--spec/models/remote_profile_spec.rb143
-rw-r--r--spec/services/authorize_follow_service_spec.rb25
-rw-r--r--spec/services/batched_remove_status_service_spec.rb17
-rw-r--r--spec/services/favourite_service_spec.rb21
-rw-r--r--spec/services/fetch_atom_service_spec.rb14
-rw-r--r--spec/services/fetch_remote_account_service_spec.rb45
-rw-r--r--spec/services/fetch_remote_status_service_spec.rb55
-rw-r--r--spec/services/follow_service_spec.rb68
-rw-r--r--spec/services/process_feed_service_spec.rb252
-rw-r--r--spec/services/process_interaction_service_spec.rb151
-rw-r--r--spec/services/process_mentions_service_spec.rb39
-rw-r--r--spec/services/reblog_service_spec.rb20
-rw-r--r--spec/services/reject_follow_service_spec.rb25
-rw-r--r--spec/services/remove_status_service_spec.rb17
-rw-r--r--spec/services/resolve_account_service_spec.rb51
-rw-r--r--spec/services/send_interaction_service_spec.rb7
-rw-r--r--spec/services/unblock_service_spec.rb21
-rw-r--r--spec/services/unfollow_service_spec.rb21
-rw-r--r--spec/services/update_remote_profile_service_spec.rb84
-rw-r--r--spec/workers/pubsubhubbub/confirmation_worker_spec.rb88
-rw-r--r--spec/workers/pubsubhubbub/delivery_worker_spec.rb68
-rw-r--r--spec/workers/pubsubhubbub/distribution_worker_spec.rb46
-rw-r--r--spec/workers/scheduler/subscriptions_scheduler_spec.rb19
115 files changed, 61 insertions, 5488 deletions
diff --git a/Gemfile b/Gemfile
index 6c7bef290..f488116a7 100644
--- a/Gemfile
+++ b/Gemfile
@@ -62,7 +62,6 @@ gem 'mime-types', '~> 3.2', require: 'mime/types/columnar'
 gem 'nokogiri', '~> 1.10'
 gem 'nsa', '~> 0.2'
 gem 'oj', '~> 3.7'
-gem 'ostatus2', '~> 2.0'
 gem 'ox', '~> 2.10'
 gem 'posix-spawn', git: 'https://github.com/rtomayko/posix-spawn', ref: '58465d2e213991f8afb13b984854a49fcdcc980c'
 gem 'pundit', '~> 2.0'
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
diff --git a/config/routes.rb b/config/routes.rb
index 83ef69f15..aaa2802a9 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -251,16 +251,6 @@ Rails.application.routes.draw do
   get '/admin', to: redirect('/admin/dashboard', status: 302)
 
   namespace :api do
-    # PubSubHubbub outgoing subscriptions
-    resources :subscriptions, only: [:show]
-    post '/subscriptions/:id', to: 'subscriptions#update'
-
-    # PubSubHubbub incoming subscriptions
-    post '/push', to: 'push#update', as: :push
-
-    # Salmon
-    post '/salmon/:id', to: 'salmon#update', as: :salmon
-
     # OEmbed
     get '/oembed', to: 'oembed#show', as: :oembed
 
diff --git a/db/schema.rb b/db/schema.rb
index 747d3f202..4e824c868 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -138,7 +138,6 @@ ActiveRecord::Schema.define(version: 2019_05_19_130537) do
     t.string "outbox_url", default: "", null: false
     t.string "shared_inbox_url", default: "", null: false
     t.string "followers_url", default: "", null: false
-    t.integer "protocol", default: 0, null: false
     t.boolean "memorial", default: false, null: false
     t.bigint "moved_to_account_id"
     t.string "featured_collection_url"
diff --git a/spec/controllers/accounts_controller_spec.rb b/spec/controllers/accounts_controller_spec.rb
index b728d719f..3d2a0665d 100644
--- a/spec/controllers/accounts_controller_spec.rb
+++ b/spec/controllers/accounts_controller_spec.rb
@@ -48,37 +48,6 @@ RSpec.describe AccountsController, type: :controller do
       end
     end
 
-    context 'atom' do
-      let(:format) { 'atom' }
-      let(:content_type) { 'application/atom+xml' }
-
-      shared_examples 'responsed streams' do
-        it 'assigns @entries' do
-          entries = assigns(:entries).to_a
-          expect(entries.size).to eq expected_statuses.size
-          entries.each.zip(expected_statuses.each) do |entry, expected_status|
-            expect(entry.status).to eq expected_status
-          end
-        end
-      end
-
-      include_examples 'responses'
-
-      context 'without max_id nor since_id' do
-        let(:expected_statuses) { [status7, status6, status5, status4, status3, status2, status1] }
-
-        include_examples 'responsed streams'
-      end
-
-      context 'with max_id and since_id' do
-        let(:max_id) { status4.stream_entry.id }
-        let(:since_id) { status1.stream_entry.id }
-        let(:expected_statuses) { [status3, status2] }
-
-        include_examples 'responsed streams'
-      end
-    end
-
     context 'activitystreams2' do
       let(:format) { 'json' }
       let(:content_type) { 'application/activity+json' }
diff --git a/spec/controllers/api/push_controller_spec.rb b/spec/controllers/api/push_controller_spec.rb
deleted file mode 100644
index d769d8554..000000000
--- a/spec/controllers/api/push_controller_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe Api::PushController, type: :controller do
-  describe 'POST #update' do
-    context 'with hub.mode=subscribe' do
-      it 'creates a subscription' do
-        service = double(call: ['', 202])
-        allow(Pubsubhubbub::SubscribeService).to receive(:new).and_return(service)
-        account = Fabricate(:account)
-        account_topic_url = "https://#{Rails.configuration.x.local_domain}/users/#{account.username}.atom"
-        post :update, params: {
-          'hub.mode' => 'subscribe',
-          'hub.topic' => account_topic_url,
-          'hub.callback' => 'https://callback.host/api',
-          'hub.lease_seconds' => '3600',
-          'hub.secret' => 'as1234df',
-        }
-
-        expect(service).to have_received(:call).with(
-          account,
-          'https://callback.host/api',
-          'as1234df',
-          '3600',
-          nil
-        )
-        expect(response).to have_http_status(202)
-      end
-    end
-
-    context 'with hub.mode=unsubscribe' do
-      it 'unsubscribes the account' do
-        service = double(call: ['', 202])
-        allow(Pubsubhubbub::UnsubscribeService).to receive(:new).and_return(service)
-        account = Fabricate(:account)
-        account_topic_url = "https://#{Rails.configuration.x.local_domain}/users/#{account.username}.atom"
-        post :update, params: {
-          'hub.mode' => 'unsubscribe',
-          'hub.topic' => account_topic_url,
-          'hub.callback' => 'https://callback.host/api',
-        }
-
-        expect(service).to have_received(:call).with(
-          account,
-          'https://callback.host/api',
-        )
-        expect(response).to have_http_status(202)
-      end
-    end
-
-    context 'with unknown mode' do
-      it 'returns an unknown mode error' do
-        post :update, params: { 'hub.mode' => 'fake' }
-
-        expect(response).to have_http_status(422)
-        expect(response.body).to match(/Unknown mode/)
-      end
-    end
-  end
-end
diff --git a/spec/controllers/api/salmon_controller_spec.rb b/spec/controllers/api/salmon_controller_spec.rb
deleted file mode 100644
index 235a29af0..000000000
--- a/spec/controllers/api/salmon_controller_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe Api::SalmonController, type: :controller do
-  render_views
-
-  let(:account) { Fabricate(:user, account: Fabricate(:account, username: 'catsrgr8')).account }
-
-  before do
-    stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
-    stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
-    stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
-    stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
-  end
-
-  describe 'POST #update' do
-    context 'with valid post data' do
-      before do
-        post :update, params: { id: account.id }, body: File.read(Rails.root.join('spec', 'fixtures', 'salmon', 'mention.xml'))
-      end
-
-      it 'contains XML in the request body' do
-        expect(request.body.read).to be_a String
-      end
-
-      it 'returns http success' do
-        expect(response).to have_http_status(202)
-      end
-
-      it 'creates remote account' do
-        expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil
-      end
-
-      it 'creates status' do
-        expect(Status.find_by(uri: 'tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note')).to_not be_nil
-      end
-
-      it 'creates mention for target account' do
-        expect(account.mentions.count).to eq 1
-      end
-    end
-
-    context 'with empty post data' do
-      before do
-        post :update, params: { id: account.id }, body: ''
-      end
-
-      it 'returns http client error' do
-        expect(response).to have_http_status(400)
-      end
-    end
-
-    context 'with invalid post data' do
-      before do
-        service = double(call: false)
-        allow(VerifySalmonService).to receive(:new).and_return(service)
-
-        post :update, params: { id: account.id }, body: File.read(Rails.root.join('spec', 'fixtures', 'salmon', 'mention.xml'))
-      end
-
-      it 'returns http client error' do
-        expect(response).to have_http_status(401)
-      end
-    end
-  end
-end
diff --git a/spec/controllers/api/subscriptions_controller_spec.rb b/spec/controllers/api/subscriptions_controller_spec.rb
deleted file mode 100644
index 7a4252fe6..000000000
--- a/spec/controllers/api/subscriptions_controller_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe Api::SubscriptionsController, type: :controller do
-  render_views
-
-  let(:account) { Fabricate(:account, username: 'gargron', domain: 'quitter.no', remote_url: 'topic_url', secret: 'abc') }
-
-  describe 'GET #show' do
-    context 'with valid subscription' do
-      before do
-        get :show, params: { :id => account.id, 'hub.topic' => 'topic_url', 'hub.challenge' => '456', 'hub.lease_seconds' => "#{86400 * 30}" }
-      end
-
-      it 'returns http success' do
-        expect(response).to have_http_status(200)
-      end
-
-      it 'echoes back the challenge' do
-        expect(response.body).to match '456'
-      end
-    end
-
-    context 'with invalid subscription' do
-      before do
-        expect_any_instance_of(Account).to receive_message_chain(:subscription, :valid?).and_return(false)
-        get :show, params: { :id => account.id }
-      end
-
-      it 'returns http success' do
-        expect(response).to have_http_status(404)
-      end
-    end
-  end
-
-  describe 'POST #update' do
-    let(:feed) { File.read(Rails.root.join('spec', 'fixtures', 'push', 'feed.atom')) }
-
-    before do
-      stub_request(:post, "https://quitter.no/main/push/hub").to_return(:status => 200, :body => "", :headers => {})
-      stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
-      stub_request(:get, "https://quitter.no/notice/1269244").to_return(status: 404)
-      stub_request(:get, "https://quitter.no/notice/1265331").to_return(status: 404)
-      stub_request(:get, "https://community.highlandarrow.com/notice/54411").to_return(status: 404)
-      stub_request(:get, "https://community.highlandarrow.com/notice/53857").to_return(status: 404)
-      stub_request(:get, "https://community.highlandarrow.com/notice/51852").to_return(status: 404)
-      stub_request(:get, "https://social.umeahackerspace.se/notice/424348").to_return(status: 404)
-      stub_request(:get, "https://community.highlandarrow.com/notice/50467").to_return(status: 404)
-      stub_request(:get, "https://quitter.no/notice/1243309").to_return(status: 404)
-      stub_request(:get, "https://quitter.no/user/7477").to_return(status: 404)
-      stub_request(:any, "https://community.highlandarrow.com/user/1").to_return(status: 404)
-      stub_request(:any, "https://social.umeahackerspace.se/user/2").to_return(status: 404)
-      stub_request(:any, "https://gs.kawa-kun.com/user/2").to_return(status: 404)
-      stub_request(:any, "https://mastodon.social/users/Gargron").to_return(status: 404)
-
-      request.env['HTTP_X_HUB_SIGNATURE'] = "sha1=#{OpenSSL::HMAC.hexdigest('sha1', 'abc', feed)}"
-
-      post :update, params: { id: account.id }, body: feed
-    end
-
-    it 'returns http success' do
-      expect(response).to have_http_status(200)
-    end
-
-    it 'creates statuses for feed' do
-      expect(account.statuses.count).to_not eq 0
-    end
-  end
-end
diff --git a/spec/controllers/stream_entries_controller_spec.rb b/spec/controllers/stream_entries_controller_spec.rb
index eb7fdf9d7..46bbbe1f1 100644
--- a/spec/controllers/stream_entries_controller_spec.rb
+++ b/spec/controllers/stream_entries_controller_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe StreamEntriesController, type: :controller do
 
         get route, params: { account_username: alice.username, id: status.stream_entry.id }
 
-        expect(response.headers['Link'].to_s).to eq "<http://test.host/users/alice/updates/#{status.stream_entry.id}.atom>; rel=\"alternate\"; type=\"application/atom+xml\", <https://cb6e6126.ngrok.io/users/alice/statuses/#{status.id}>; rel=\"alternate\"; type=\"application/activity+json\""
+        expect(response.headers['Link'].to_s).to eq "<https://cb6e6126.ngrok.io/users/alice/statuses/#{status.id}>; rel=\"alternate\"; type=\"application/activity+json\""
       end
     end
 
@@ -73,12 +73,6 @@ RSpec.describe StreamEntriesController, type: :controller do
 
       expect(response).to redirect_to(short_account_status_url(status.account, status))
     end
-
-    it 'returns http success with Atom' do
-      status = Fabricate(:status)
-      get :show, params: { account_username: status.account.username, id: status.stream_entry.id }, format: 'atom'
-      expect(response).to have_http_status(200)
-    end
   end
 
   describe 'GET #embed' do
diff --git a/spec/lib/activitypub/activity/undo_spec.rb b/spec/lib/activitypub/activity/undo_spec.rb
index 9545e1f46..9c76fabe9 100644
--- a/spec/lib/activitypub/activity/undo_spec.rb
+++ b/spec/lib/activitypub/activity/undo_spec.rb
@@ -25,7 +25,6 @@ RSpec.describe ActivityPub::Activity::Undo do
           type: 'Announce',
           actor: ActivityPub::TagManager.instance.uri_for(sender),
           object: ActivityPub::TagManager.instance.uri_for(status),
-          atomUri: 'barbar',
         }
       end
 
@@ -39,17 +38,6 @@ RSpec.describe ActivityPub::Activity::Undo do
           expect(sender.reblogged?(status)).to be false
         end
       end
-
-      context 'with atomUri' do
-        before do
-          Fabricate(:status, reblog: status, account: sender, uri: 'barbar')
-        end
-
-        it 'deletes the reblog by atomUri' do
-          subject.perform
-          expect(sender.reblogged?(status)).to be false
-        end
-      end
     end
 
     context 'with Accept' do
diff --git a/spec/lib/ostatus/atom_serializer_spec.rb b/spec/lib/ostatus/atom_serializer_spec.rb
deleted file mode 100644
index 891871c1c..000000000
--- a/spec/lib/ostatus/atom_serializer_spec.rb
+++ /dev/null
@@ -1,1560 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe OStatus::AtomSerializer do
-  shared_examples 'follow request salmon' do
-    it 'appends author element with account' do
-      account = Fabricate(:account, domain: nil, username: 'username')
-      follow_request = Fabricate(:follow_request, account: account)
-
-      follow_request_salmon = serialize(follow_request)
-
-      expect(follow_request_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
-    end
-
-    it 'appends activity:object-type element with activity type' do
-      follow_request = Fabricate(:follow_request)
-
-      follow_request_salmon = serialize(follow_request)
-
-      object_type = follow_request_salmon.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
-    end
-
-    it 'appends activity:verb element with request_friend type' do
-      follow_request = Fabricate(:follow_request)
-
-      follow_request_salmon = serialize(follow_request)
-
-      verb = follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }
-      expect(verb.text).to eq OStatus::TagManager::VERBS[:request_friend]
-    end
-
-    it 'appends activity:object with target account' do
-      target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')
-      follow_request = Fabricate(:follow_request, target_account: target_account)
-
-      follow_request_salmon = serialize(follow_request)
-
-      object = follow_request_salmon.nodes.find { |node| node.name == 'activity:object' }
-      expect(object.id.text).to eq 'https://domain.test/id'
-    end
-  end
-
-  shared_examples 'namespaces' do
-    it 'adds namespaces' do
-      element = serialize
-
-      expect(element['xmlns']).to eq OStatus::TagManager::XMLNS
-      expect(element['xmlns:thr']).to eq OStatus::TagManager::THR_XMLNS
-      expect(element['xmlns:activity']).to eq OStatus::TagManager::AS_XMLNS
-      expect(element['xmlns:poco']).to eq OStatus::TagManager::POCO_XMLNS
-      expect(element['xmlns:media']).to eq OStatus::TagManager::MEDIA_XMLNS
-      expect(element['xmlns:ostatus']).to eq OStatus::TagManager::OS_XMLNS
-      expect(element['xmlns:mastodon']).to eq OStatus::TagManager::MTDN_XMLNS
-    end
-  end
-
-  shared_examples 'no namespaces' do
-    it 'does not add namespaces' do
-      expect(serialize['xmlns']).to eq nil
-    end
-  end
-
-  shared_examples 'status attributes' do
-    it 'appends summary element with spoiler text if present' do
-      status = Fabricate(:status, language: :ca, spoiler_text: 'spoiler text')
-
-      element = serialize(status)
-
-      summary = element.summary
-      expect(summary['xml:lang']).to eq 'ca'
-      expect(summary.text).to eq 'spoiler text'
-    end
-
-    it 'does not append summary element with spoiler text if not present' do
-      status = Fabricate(:status, spoiler_text: '')
-      element = serialize(status)
-      element.nodes.each { |node| expect(node.name).not_to eq 'summary' }
-    end
-
-    it 'appends content element with formatted status' do
-      status = Fabricate(:status, language: :ca, text: 'text')
-
-      element = serialize(status)
-
-      content = element.content
-      expect(content[:type]).to eq 'html'
-      expect(content['xml:lang']).to eq 'ca'
-      expect(content.text).to eq '<p>text</p>'
-    end
-
-    it 'appends link elements for mentioned accounts' do
-      account = Fabricate(:account, username: 'username')
-      status = Fabricate(:status)
-      Fabricate(:mention, account: account, status: status)
-
-      element = serialize(status)
-
-      mentioned = element.nodes.find do |node|
-        node.name == 'link' &&
-          node[:rel] == 'mentioned' &&
-          node['ostatus:object-type'] == OStatus::TagManager::TYPES[:person]
-      end
-
-      expect(mentioned[:href]).to eq 'https://cb6e6126.ngrok.io/users/username'
-    end
-
-    it 'appends link elements for emojis' do
-      Fabricate(:custom_emoji)
-
-      status  = Fabricate(:status, text: ':coolcat:')
-      element = serialize(status)
-      emoji   = element.nodes.find { |node| node.name == 'link' && node[:rel] == 'emoji' }
-
-      expect(emoji[:name]).to eq 'coolcat'
-      expect(emoji[:href]).to_not be_blank
-    end
-  end
-
-  describe 'render' do
-    it 'returns XML with emojis' do
-      element = Ox::Element.new('tag')
-      element << '💩'
-      xml = OStatus::AtomSerializer.render(element)
-
-      expect(xml).to eq "<?xml version=\"1.0\"?>\n<tag>💩</tag>\n"
-    end
-
-    it 'returns XML, stripping invalid characters like \b and \v' do
-      element = Ox::Element.new('tag')
-      element << "im l33t\b haxo\b\vr"
-      xml = OStatus::AtomSerializer.render(element)
-
-      expect(xml).to eq "<?xml version=\"1.0\"?>\n<tag>im l33t haxor</tag>\n"
-    end
-  end
-
-  describe '#author' do
-    context 'when note is present' do
-      it 'appends poco:note element with note for local account' do
-        account = Fabricate(:account, domain: nil, note: '<p>note</p>')
-
-        author = OStatus::AtomSerializer.new.author(account)
-
-        note = author.nodes.find { |node| node.name == 'poco:note' }
-        expect(note.text).to eq '<p>note</p>'
-      end
-
-      it 'appends poco:note element with tags-stripped note for remote account' do
-        account = Fabricate(:account, domain: 'remote', note: '<p>note</p>')
-
-        author = OStatus::AtomSerializer.new.author(account)
-
-        note = author.nodes.find { |node| node.name == 'poco:note' }
-        expect(note.text).to eq 'note'
-      end
-
-      it 'appends summary element with type attribute and simplified note if present' do
-        account = Fabricate(:account, note: 'note')
-        author = OStatus::AtomSerializer.new.author(account)
-        expect(author.summary.text).to eq '<p>note</p>'
-        expect(author.summary[:type]).to eq 'html'
-      end
-    end
-
-    context 'when note is not present' do
-      it 'does not append poco:note element' do
-        account = Fabricate(:account, note: '')
-        author = OStatus::AtomSerializer.new.author(account)
-        author.nodes.each { |node| expect(node.name).not_to eq 'poco:note' }
-      end
-
-      it 'does not append summary element' do
-        account = Fabricate(:account, note: '')
-        author = OStatus::AtomSerializer.new.author(account)
-        author.nodes.each { |node| expect(node.name).not_to eq 'summary' }
-      end
-    end
-
-    it 'returns author element' do
-      account = Fabricate(:account)
-      author = OStatus::AtomSerializer.new.author(account)
-      expect(author.name).to eq 'author'
-    end
-
-    it 'appends activity:object-type element with person type' do
-      account = Fabricate(:account, domain: nil, username: 'username')
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      object_type = author.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq OStatus::TagManager::TYPES[:person]
-    end
-
-    it 'appends email element with username and domain for local account' do
-      account = Fabricate(:account, username: 'username')
-      author = OStatus::AtomSerializer.new.author(account)
-      expect(author.email.text).to eq 'username@cb6e6126.ngrok.io'
-    end
-
-    it 'appends email element with username and domain for remote user' do
-      account = Fabricate(:account, domain: 'domain', username: 'username')
-      author = OStatus::AtomSerializer.new.author(account)
-      expect(author.email.text).to eq 'username@domain'
-    end
-
-    it 'appends link element for an alternative' do
-      account = Fabricate(:account, domain: nil, username: 'username')
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }
-      expect(link[:type]).to eq 'text/html'
-      expect(link[:rel]).to eq 'alternate'
-      expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/@username'
-    end
-
-    it 'has link element for avatar if present' do
-      account = Fabricate(:account, avatar: attachment_fixture('avatar.gif'))
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'avatar' }
-      expect(link[:type]).to eq 'image/gif'
-      expect(link['media:width']).to eq '120'
-      expect(link['media:height']).to eq '120'
-      expect(link[:href]).to match  /^https:\/\/cb6e6126.ngrok.io\/system\/accounts\/avatars\/.+\/original\/avatar.gif/
-    end
-
-    it 'does not have link element for avatar if not present' do
-      account = Fabricate(:account, avatar: nil)
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      author.nodes.each do |node|
-        expect(node[:rel]).not_to eq 'avatar' if node.name == 'link'
-      end
-    end
-
-    it 'appends link element for header if present' do
-      account = Fabricate(:account, header: attachment_fixture('avatar.gif'))
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      link = author.nodes.find { |node| node.name == 'link' && node[:rel] == 'header' }
-      expect(link[:type]).to eq 'image/gif'
-      expect(link['media:width']).to eq '700'
-      expect(link['media:height']).to eq '335'
-      expect(link[:href]).to match  /^https:\/\/cb6e6126.ngrok.io\/system\/accounts\/headers\/.+\/original\/avatar.gif/
-    end
-
-    it 'does not append link element for header if not present' do
-      account = Fabricate(:account, header: nil)
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      author.nodes.each do |node|
-        expect(node[:rel]).not_to eq 'header' if node.name == 'link'
-      end
-    end
-
-    it 'appends poco:displayName element with display name if present' do
-      account = Fabricate(:account, display_name: 'display name')
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      display_name = author.nodes.find { |node| node.name == 'poco:displayName' }
-      expect(display_name.text).to eq 'display name'
-    end
-
-    it 'does not append poco:displayName element with display name if not present' do
-      account = Fabricate(:account, display_name: '')
-      author = OStatus::AtomSerializer.new.author(account)
-      author.nodes.each { |node| expect(node.name).not_to eq 'poco:displayName' }
-    end
-
-    it "appends mastodon:scope element with 'private' if locked" do
-      account = Fabricate(:account, locked: true)
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      scope = author.nodes.find { |node| node.name == 'mastodon:scope' }
-      expect(scope.text).to eq 'private'
-    end
-
-    it "appends mastodon:scope element with 'public' if unlocked" do
-      account = Fabricate(:account, locked: false)
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      scope = author.nodes.find { |node| node.name == 'mastodon:scope' }
-      expect(scope.text).to eq 'public'
-    end
-
-    it 'includes URI' do
-      account = Fabricate(:account, domain: nil, username: 'username')
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      expect(author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
-      expect(author.uri.text).to eq 'https://cb6e6126.ngrok.io/users/username'
-    end
-
-    it 'includes username' do
-      account = Fabricate(:account, username: 'username')
-
-      author = OStatus::AtomSerializer.new.author(account)
-
-      name = author.nodes.find { |node| node.name == 'name' }
-      username = author.nodes.find { |node| node.name == 'poco:preferredUsername' }
-      expect(name.text).to eq 'username'
-      expect(username.text).to eq 'username'
-    end
-  end
-
-  describe '#entry' do
-    shared_examples 'not root' do
-      include_examples 'no namespaces' do
-        def serialize
-          subject
-        end
-      end
-
-      it 'does not append author element' do
-        subject.nodes.each { |node| expect(node.name).not_to eq 'author' }
-      end
-    end
-
-    context 'it is root' do
-      include_examples 'namespaces' do
-        def serialize
-          stream_entry = Fabricate(:stream_entry)
-          OStatus::AtomSerializer.new.entry(stream_entry, true)
-        end
-      end
-
-      it 'appends author element' do
-        account = Fabricate(:account, username: 'username')
-        status = Fabricate(:status, account: account)
-
-        entry = OStatus::AtomSerializer.new.entry(status.stream_entry, true)
-
-        expect(entry.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
-      end
-    end
-
-    context 'if status is present' do
-      include_examples 'status attributes' do
-        def serialize(status)
-          OStatus::AtomSerializer.new.entry(status.stream_entry, true)
-        end
-      end
-
-      it 'appends link element for the public collection if status is publicly visible' do
-        status = Fabricate(:status, visibility: :public)
-
-        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-        mentioned_person = entry.nodes.find do |node|
-          node.name == 'link' &&
-          node[:rel] == 'mentioned' &&
-          node['ostatus:object-type'] == OStatus::TagManager::TYPES[:collection]
-        end
-        expect(mentioned_person[:href]).to eq OStatus::TagManager::COLLECTIONS[:public]
-      end
-
-      it 'does not append link element for the public collection if status is not publicly visible' do
-        status = Fabricate(:status, visibility: :private)
-
-        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-        entry.nodes.each do |node|
-          if node.name == 'link' &&
-             node[:rel] == 'mentioned' &&
-             node['ostatus:object-type'] == OStatus::TagManager::TYPES[:collection]
-            expect(mentioned_collection[:href]).not_to eq OStatus::TagManager::COLLECTIONS[:public]
-          end
-        end
-      end
-
-      it 'appends category elements for tags' do
-        tag = Fabricate(:tag, name: 'tag')
-        status = Fabricate(:status, tags: [ tag ])
-
-        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-        expect(entry.category[:term]).to eq 'tag'
-      end
-
-      it 'appends link elements for media attachments' do
-        file = attachment_fixture('attachment.jpg')
-        media_attachment = Fabricate(:media_attachment, file: file)
-        status = Fabricate(:status, media_attachments: [ media_attachment ])
-
-        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-        enclosure = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'enclosure' }
-        expect(enclosure[:type]).to eq 'image/jpeg'
-        expect(enclosure[:href]).to match /^https:\/\/cb6e6126.ngrok.io\/system\/media_attachments\/files\/.+\/original\/attachment.jpg$/
-      end
-
-      it 'appends mastodon:scope element with visibility' do
-        status = Fabricate(:status, visibility: :public)
-
-        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-        scope = entry.nodes.find { |node| node.name == 'mastodon:scope' }
-        expect(scope.text).to eq 'public'
-      end
-
-      it 'returns element whose rendered view triggers creation when processed' do
-        remote_account = Account.create!(username: 'username')
-        remote_status = Fabricate(:status, account: remote_account, created_at: '2000-01-01T00:00:00Z')
-
-        entry = OStatus::AtomSerializer.new.entry(remote_status.stream_entry, true)
-        entry.nodes.delete_if { |node| node[:type] == 'application/activity+json' } # Remove ActivityPub link to simplify test
-        xml = OStatus::AtomSerializer.render(entry).gsub('cb6e6126.ngrok.io', 'remote.test')
-
-        remote_status.destroy!
-        remote_account.destroy!
-
-        account = Account.create!(
-          domain: 'remote.test',
-          username: 'username',
-          last_webfingered_at: Time.now.utc
-        )
-
-        ProcessFeedService.new.call(xml, account)
-
-        expect(Status.find_by(uri: "https://remote.test/users/#{remote_status.account.to_param}/statuses/#{remote_status.id}")).to be_instance_of Status
-      end
-    end
-
-    context 'if status is not present' do
-      it 'appends content element saying status is deleted' do
-        status = Fabricate(:status)
-        status.destroy!
-
-        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-        expect(entry.content.text).to eq 'Deleted status'
-      end
-
-      it 'appends title element saying the status is deleted' do
-        account = Fabricate(:account, username: 'username')
-        status = Fabricate(:status, account: account)
-        status.destroy!
-
-        entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-        expect(entry.title.text).to eq 'username deleted status'
-      end
-    end
-
-    context 'it is not root' do
-      let(:stream_entry) { Fabricate(:stream_entry) }
-      subject { OStatus::AtomSerializer.new.entry(stream_entry, false) }
-      include_examples 'not root'
-    end
-
-    context 'without root parameter' do
-      let(:stream_entry) { Fabricate(:stream_entry) }
-      subject { OStatus::AtomSerializer.new.entry(stream_entry) }
-      include_examples 'not root'
-    end
-
-    it 'returns entry element' do
-      stream_entry = Fabricate(:stream_entry)
-      entry = OStatus::AtomSerializer.new.entry(stream_entry)
-      expect(entry.name).to eq 'entry'
-    end
-
-    it 'appends id element with unique tag' do
-      status = Fabricate(:status, reblog_of_id: nil, created_at: '2000-01-01T00:00:00Z')
-
-      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-      expect(entry.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
-    end
-
-    it 'appends published element with created date' do
-      stream_entry = Fabricate(:stream_entry, created_at: '2000-01-01T00:00:00Z')
-      entry = OStatus::AtomSerializer.new.entry(stream_entry)
-      expect(entry.published.text).to eq '2000-01-01T00:00:00Z'
-    end
-
-    it 'appends updated element with updated date' do
-      stream_entry = Fabricate(:stream_entry, updated_at: '2000-01-01T00:00:00Z')
-      entry = OStatus::AtomSerializer.new.entry(stream_entry)
-      expect(entry.updated.text).to eq '2000-01-01T00:00:00Z'
-    end
-
-    it 'appends title element with status title' do
-      account = Fabricate(:account, username: 'username')
-      status = Fabricate(:status, account: account, reblog_of_id: nil)
-      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-      expect(entry.title.text).to eq 'New status by username'
-    end
-
-    it 'appends activity:object-type element with object type' do
-      status = Fabricate(:status)
-      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-      object_type = entry.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq OStatus::TagManager::TYPES[:note]
-    end
-
-    it 'appends activity:verb element with object type' do
-      status = Fabricate(:status)
-
-      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-      object_type = entry.nodes.find { |node| node.name == 'activity:verb' }
-      expect(object_type.text).to eq OStatus::TagManager::VERBS[:post]
-    end
-
-    it 'appends activity:object element with target if present' do
-      reblogged = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
-      reblog = Fabricate(:status, reblog: reblogged)
-
-      entry = OStatus::AtomSerializer.new.entry(reblog.stream_entry)
-
-      object = entry.nodes.find { |node| node.name == 'activity:object' }
-      expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{reblogged.account.to_param}/statuses/#{reblogged.id}"
-    end
-
-    it 'does not append activity:object element if target is not present' do
-      status = Fabricate(:status, reblog_of_id: nil)
-      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-      entry.nodes.each { |node| expect(node.name).not_to eq 'activity:object' }
-    end
-
-    it 'appends link element for an alternative' do
-      account = Fabricate(:account, username: 'username')
-      status = Fabricate(:status, account: account)
-
-      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-      link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }
-      expect(link[:type]).to eq 'text/html'
-      expect(link[:href]).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
-    end
-
-    it 'appends link element for itself' do
-      account = Fabricate(:account, username: 'username')
-      status = Fabricate(:status, account: account)
-
-      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-      link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'self' }
-      expect(link[:type]).to eq 'application/atom+xml'
-      expect(link[:href]).to eq "https://cb6e6126.ngrok.io/users/username/updates/#{status.stream_entry.id}.atom"
-    end
-
-    it 'appends thr:in-reply-to element if threaded' do
-      in_reply_to_status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z', reblog_of_id: nil)
-      reply_status = Fabricate(:status, in_reply_to_id: in_reply_to_status.id)
-
-      entry = OStatus::AtomSerializer.new.entry(reply_status.stream_entry)
-
-      in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' }
-      expect(in_reply_to[:ref]).to eq "https://cb6e6126.ngrok.io/users/#{in_reply_to_status.account.to_param}/statuses/#{in_reply_to_status.id}"
-    end
-
-    it 'does not append thr:in-reply-to element if not threaded' do
-      status = Fabricate(:status)
-      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-      entry.nodes.each { |node| expect(node.name).not_to eq 'thr:in-reply-to' }
-    end
-
-    it 'appends ostatus:conversation if conversation id is present' do
-      status = Fabricate(:status)
-      status.conversation.update!(created_at: '2000-01-01T00:00:00Z')
-
-      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-      conversation = entry.nodes.find { |node| node.name == 'ostatus:conversation' }
-      expect(conversation[:ref]).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.conversation_id}:objectType=Conversation"
-    end
-
-    it 'does not append ostatus:conversation if conversation id is not present' do
-      status = Fabricate.build(:status, conversation_id: nil)
-      status.save!(validate: false)
-
-      entry = OStatus::AtomSerializer.new.entry(status.stream_entry)
-
-      entry.nodes.each { |node| expect(node.name).not_to eq 'ostatus:conversation' }
-    end
-  end
-
-  describe '#feed' do
-    include_examples 'namespaces' do
-      def serialize
-        account = Fabricate(:account)
-        OStatus::AtomSerializer.new.feed(account, [])
-      end
-    end
-
-    it 'returns feed element' do
-      account = Fabricate(:account)
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-      expect(feed.name).to eq 'feed'
-    end
-
-    it 'appends id element with account Atom URL' do
-      account = Fabricate(:account, username: 'username')
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-      expect(feed.id.text).to eq 'https://cb6e6126.ngrok.io/users/username.atom'
-    end
-
-    it 'appends title element with account display name if present' do
-      account = Fabricate(:account, display_name: 'display name')
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-      expect(feed.title.text).to eq 'display name'
-    end
-
-    it 'does not append title element with account username if account display name is not present' do
-      account = Fabricate(:account, display_name: '', username: 'username')
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-      expect(feed.title.text).to eq 'username'
-    end
-
-    it 'appends subtitle element with account note' do
-      account = Fabricate(:account, note: 'note')
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-      expect(feed.subtitle.text).to eq 'note'
-    end
-
-    it 'appends updated element with date account got updated' do
-      account = Fabricate(:account, updated_at: '2000-01-01T00:00:00Z')
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-      expect(feed.updated.text).to eq '2000-01-01T00:00:00Z'
-    end
-
-    it 'appends logo element with full asset URL for original account avatar' do
-      account = Fabricate(:account, avatar: attachment_fixture('avatar.gif'))
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-      expect(feed.logo.text).to match /^https:\/\/cb6e6126.ngrok.io\/system\/accounts\/avatars\/.+\/original\/avatar.gif/
-    end
-
-    it 'appends author element' do
-      account = Fabricate(:account, username: 'username')
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-      expect(feed.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
-    end
-
-    it 'appends link element for an alternative' do
-      account = Fabricate(:account, username: 'username')
-
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-
-      link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }
-      expect(link[:type]).to eq 'text/html'
-      expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/@username'
-    end
-
-    it 'appends link element for itself' do
-      account = Fabricate(:account, username: 'username')
-
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-
-      link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'self' }
-      expect(link[:type]).to eq 'application/atom+xml'
-      expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/users/username.atom'
-    end
-
-    it 'appends link element for the next if it has 20 stream entries' do
-      account = Fabricate(:account, username: 'username')
-      stream_entry = Fabricate(:stream_entry)
-
-      feed = OStatus::AtomSerializer.new.feed(account, Array.new(20, stream_entry))
-
-      link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'next' }
-      expect(link[:type]).to eq 'application/atom+xml'
-      expect(link[:href]).to eq "https://cb6e6126.ngrok.io/users/username.atom?max_id=#{stream_entry.id}"
-    end
-
-    it 'does not append link element for the next if it does not have 20 stream entries' do
-      account = Fabricate(:account, username: 'username')
-
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-
-      feed.nodes.each do |node|
-        expect(node[:rel]).not_to eq 'next' if node.name == 'link'
-      end
-    end
-
-    it 'appends link element for hub' do
-      account = Fabricate(:account, username: 'username')
-
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-
-      link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'hub' }
-      expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/api/push'
-    end
-
-    it 'appends link element for Salmon' do
-      account = Fabricate(:account, username: 'username')
-
-      feed = OStatus::AtomSerializer.new.feed(account, [])
-
-      link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'salmon' }
-      expect(link[:href]).to start_with 'https://cb6e6126.ngrok.io/api/salmon/'
-    end
-
-    it 'appends stream entries' do
-      account = Fabricate(:account, username: 'username')
-      status = Fabricate(:status, account: account)
-
-      feed = OStatus::AtomSerializer.new.feed(account, [status.stream_entry])
-
-      expect(feed.entry.title.text).to eq 'New status by username'
-    end
-  end
-
-  describe '#block_salmon' do
-    include_examples 'namespaces' do
-      def serialize
-        block = Fabricate(:block)
-        OStatus::AtomSerializer.new.block_salmon(block)
-      end
-    end
-
-    it 'returns entry element' do
-      block = Fabricate(:block)
-      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
-      expect(block_salmon.name).to eq 'entry'
-    end
-
-    it 'appends id element with unique tag' do
-      block = Fabricate(:block)
-
-      time_before = Time.zone.now
-      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
-      time_after = Time.zone.now
-
-      expect(block_salmon.id.text).to(
-        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, block.id, 'Block'))
-          .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, block.id, 'Block')))
-      )
-    end
-
-    it 'appends title element with description' do
-      account = Fabricate(:account, domain: nil, username: 'account')
-      target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
-      block = Fabricate(:block, account: account, target_account: target_account)
-
-      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
-
-      expect(block_salmon.title.text).to eq 'account no longer wishes to interact with target_account@remote'
-    end
-
-    it 'appends author element with account' do
-      account = Fabricate(:account, domain: nil, username: 'account')
-      block = Fabricate(:block, account: account)
-
-      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
-
-      expect(block_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/account'
-    end
-
-    it 'appends activity:object-type element with activity type' do
-      block = Fabricate(:block)
-
-      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
-
-      object_type = block_salmon.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
-    end
-
-    it 'appends activity:verb element with block' do
-      block = Fabricate(:block)
-
-      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
-
-      verb = block_salmon.nodes.find { |node| node.name == 'activity:verb' }
-      expect(verb.text).to eq OStatus::TagManager::VERBS[:block]
-    end
-
-    it 'appends activity:object element with target account' do
-      target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')
-      block = Fabricate(:block, target_account: target_account)
-
-      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
-
-      object = block_salmon.nodes.find { |node| node.name == 'activity:object' }
-      expect(object.id.text).to eq 'https://domain.test/id'
-    end
-
-    it 'returns element whose rendered view triggers block when processed' do
-      block = Fabricate(:block)
-      block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
-      xml = OStatus::AtomSerializer.render(block_salmon)
-      envelope = OStatus2::Salmon.new.pack(xml, block.account.keypair)
-      block.destroy!
-
-      ProcessInteractionService.new.call(envelope, block.target_account)
-
-      expect(block.account.blocking?(block.target_account)).to be true
-    end
-  end
-
-  describe '#unblock_salmon' do
-    include_examples 'namespaces' do
-      def serialize
-        block = Fabricate(:block)
-        OStatus::AtomSerializer.new.unblock_salmon(block)
-      end
-    end
-
-    it 'returns entry element' do
-      block = Fabricate(:block)
-      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
-      expect(unblock_salmon.name).to eq 'entry'
-    end
-
-    it 'appends id element with unique tag' do
-      block = Fabricate(:block)
-
-      time_before = Time.zone.now
-      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
-      time_after = Time.zone.now
-
-      expect(unblock_salmon.id.text).to(
-        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, block.id, 'Block'))
-          .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, block.id, 'Block')))
-      )
-    end
-
-    it 'appends title element with description' do
-      account = Fabricate(:account, domain: nil, username: 'account')
-      target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
-      block = Fabricate(:block, account: account, target_account: target_account)
-
-      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
-
-      expect(unblock_salmon.title.text).to eq 'account no longer blocks target_account@remote'
-    end
-
-    it 'appends author element with account' do
-      account = Fabricate(:account, domain: nil, username: 'account')
-      block = Fabricate(:block, account: account)
-
-      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
-
-      expect(unblock_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/account'
-    end
-
-    it 'appends activity:object-type element with activity type' do
-      block = Fabricate(:block)
-
-      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
-
-      object_type = unblock_salmon.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
-    end
-
-    it 'appends activity:verb element with block' do
-      block = Fabricate(:block)
-
-      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
-
-      verb = unblock_salmon.nodes.find { |node| node.name == 'activity:verb' }
-      expect(verb.text).to eq OStatus::TagManager::VERBS[:unblock]
-    end
-
-    it 'appends activity:object element with target account' do
-      target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')
-      block = Fabricate(:block, target_account: target_account)
-
-      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
-
-      object = unblock_salmon.nodes.find { |node| node.name == 'activity:object' }
-      expect(object.id.text).to eq 'https://domain.test/id'
-    end
-
-    it 'returns element whose rendered view triggers block when processed' do
-      block = Fabricate(:block)
-      unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
-      xml = OStatus::AtomSerializer.render(unblock_salmon)
-      envelope = OStatus2::Salmon.new.pack(xml, block.account.keypair)
-
-      ProcessInteractionService.new.call(envelope, block.target_account)
-
-      expect { block.reload }.to raise_error ActiveRecord::RecordNotFound
-    end
-  end
-
-  describe '#favourite_salmon' do
-    include_examples 'namespaces' do
-      def serialize
-        favourite = Fabricate(:favourite)
-        OStatus::AtomSerializer.new.favourite_salmon(favourite)
-      end
-    end
-
-    it 'returns entry element' do
-      favourite = Fabricate(:favourite)
-      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
-      expect(favourite_salmon.name).to eq 'entry'
-    end
-
-    it 'appends id element with unique tag' do
-      favourite = Fabricate(:favourite, created_at: '2000-01-01T00:00:00Z')
-      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
-      expect(favourite_salmon.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{favourite.id}:objectType=Favourite"
-    end
-
-    it 'appends author element with account' do
-      account = Fabricate(:account, domain: nil, username: 'username')
-      favourite = Fabricate(:favourite, account: account)
-
-      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
-
-      expect(favourite_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
-    end
-
-    it 'appends activity:object-type element with activity type' do
-      favourite = Fabricate(:favourite)
-
-      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
-
-      object_type = favourite_salmon.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq 'http://activitystrea.ms/schema/1.0/activity'
-    end
-
-    it 'appends activity:verb element with favorite' do
-      favourite = Fabricate(:favourite)
-
-      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
-
-      verb = favourite_salmon.nodes.find { |node| node.name == 'activity:verb' }
-      expect(verb.text).to eq OStatus::TagManager::VERBS[:favorite]
-    end
-
-    it 'appends activity:object element with status' do
-      status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
-      favourite = Fabricate(:favourite, status: status)
-
-      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
-
-      object = favourite_salmon.nodes.find { |node| node.name == 'activity:object' }
-      expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
-    end
-
-    it 'appends thr:in-reply-to element for status' do
-      status_account = Fabricate(:account, username: 'username')
-      status = Fabricate(:status, account: status_account, created_at: '2000-01-01T00:00:00Z')
-      favourite = Fabricate(:favourite, status: status)
-
-      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
-
-      in_reply_to = favourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' }
-      expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
-      expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
-    end
-
-    it 'includes description' do
-      account = Fabricate(:account, domain: nil, username: 'account')
-      status_account = Fabricate(:account, domain: 'remote', username: 'status_account')
-      status = Fabricate(:status, account: status_account)
-      favourite = Fabricate(:favourite, account: account, status: status)
-
-      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
-
-      expect(favourite_salmon.title.text).to eq 'account favourited a status by status_account@remote'
-      expect(favourite_salmon.content.text).to eq 'account favourited a status by status_account@remote'
-    end
-
-    it 'returns element whose rendered view triggers favourite when processed' do
-      favourite = Fabricate(:favourite)
-      favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
-      xml = OStatus::AtomSerializer.render(favourite_salmon)
-      envelope = OStatus2::Salmon.new.pack(xml, favourite.account.keypair)
-      favourite.destroy!
-
-      ProcessInteractionService.new.call(envelope, favourite.status.account)
-      expect(favourite.account.favourited?(favourite.status)).to be true
-    end
-  end
-
-  describe '#unfavourite_salmon' do
-    include_examples 'namespaces' do
-      def serialize
-        favourite = Fabricate(:favourite)
-        OStatus::AtomSerializer.new.favourite_salmon(favourite)
-      end
-    end
-
-    it 'returns entry element' do
-      favourite = Fabricate(:favourite)
-      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
-      expect(unfavourite_salmon.name).to eq 'entry'
-    end
-
-    it 'appends id element with unique tag' do
-      favourite = Fabricate(:favourite)
-
-      time_before = Time.zone.now
-      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
-      time_after = Time.zone.now
-
-      expect(unfavourite_salmon.id.text).to(
-        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, favourite.id, 'Favourite'))
-          .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, favourite.id, 'Favourite')))
-      )
-    end
-
-    it 'appends author element with account' do
-      account = Fabricate(:account, domain: nil, username: 'username')
-      favourite = Fabricate(:favourite, account: account)
-
-      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
-
-      expect(unfavourite_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
-    end
-
-    it 'appends activity:object-type element with activity type' do
-      favourite = Fabricate(:favourite)
-
-      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
-
-      object_type = unfavourite_salmon.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq 'http://activitystrea.ms/schema/1.0/activity'
-    end
-
-    it 'appends activity:verb element with favorite' do
-      favourite = Fabricate(:favourite)
-
-      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
-
-      verb = unfavourite_salmon.nodes.find { |node| node.name == 'activity:verb' }
-      expect(verb.text).to eq OStatus::TagManager::VERBS[:unfavorite]
-    end
-
-    it 'appends activity:object element with status' do
-      status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
-      favourite = Fabricate(:favourite, status: status)
-
-      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
-
-      object = unfavourite_salmon.nodes.find { |node| node.name == 'activity:object' }
-      expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
-    end
-
-    it 'appends thr:in-reply-to element for status' do
-      status_account = Fabricate(:account, username: 'username')
-      status = Fabricate(:status, account: status_account, created_at: '2000-01-01T00:00:00Z')
-      favourite = Fabricate(:favourite, status: status)
-
-      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
-
-      in_reply_to = unfavourite_salmon.nodes.find { |node| node.name == 'thr:in-reply-to' }
-      expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
-      expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
-    end
-
-    it 'includes description' do
-      account = Fabricate(:account, domain: nil, username: 'account')
-      status_account = Fabricate(:account, domain: 'remote', username: 'status_account')
-      status = Fabricate(:status, account: status_account)
-      favourite = Fabricate(:favourite, account: account, status: status)
-
-      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
-
-      expect(unfavourite_salmon.title.text).to eq 'account no longer favourites a status by status_account@remote'
-      expect(unfavourite_salmon.content.text).to eq 'account no longer favourites a status by status_account@remote'
-    end
-
-    it 'returns element whose rendered view triggers unfavourite when processed' do
-      favourite = Fabricate(:favourite)
-      unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
-      xml = OStatus::AtomSerializer.render(unfavourite_salmon)
-      envelope = OStatus2::Salmon.new.pack(xml, favourite.account.keypair)
-
-      ProcessInteractionService.new.call(envelope, favourite.status.account)
-      expect { favourite.reload }.to raise_error ActiveRecord::RecordNotFound
-    end
-  end
-
-  describe '#follow_salmon' do
-    include_examples 'namespaces' do
-      def serialize
-        follow = Fabricate(:follow)
-        OStatus::AtomSerializer.new.follow_salmon(follow)
-      end
-    end
-
-    it 'returns entry element' do
-      follow = Fabricate(:follow)
-      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
-      expect(follow_salmon.name).to eq 'entry'
-    end
-
-    it 'appends id element with unique tag' do
-      follow = Fabricate(:follow, created_at: '2000-01-01T00:00:00Z')
-      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
-      expect(follow_salmon.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{follow.id}:objectType=Follow"
-    end
-
-    it 'appends author element with account' do
-      account = Fabricate(:account, domain: nil, username: 'username')
-      follow = Fabricate(:follow, account: account)
-
-      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
-
-      expect(follow_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
-    end
-
-    it 'appends activity:object-type element with activity type' do
-      follow = Fabricate(:follow)
-
-      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
-
-      object_type = follow_salmon.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
-    end
-
-    it 'appends activity:verb element with follow' do
-      follow = Fabricate(:follow)
-
-      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
-
-      verb = follow_salmon.nodes.find { |node| node.name == 'activity:verb' }
-      expect(verb.text).to eq OStatus::TagManager::VERBS[:follow]
-    end
-
-    it 'appends activity:object element with target account' do
-      target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')
-      follow = Fabricate(:follow, target_account: target_account)
-
-      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
-
-      object = follow_salmon.nodes.find { |node| node.name == 'activity:object' }
-      expect(object.id.text).to eq 'https://domain.test/id'
-    end
-
-    it 'includes description' do
-      account = Fabricate(:account, domain: nil, username: 'account')
-      target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
-      follow = Fabricate(:follow, account: account, target_account: target_account)
-
-      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
-
-      expect(follow_salmon.title.text).to eq 'account started following target_account@remote'
-      expect(follow_salmon.content.text).to eq 'account started following target_account@remote'
-    end
-
-    it 'returns element whose rendered view triggers follow when processed' do
-      follow = Fabricate(:follow)
-      follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
-      xml = OStatus::AtomSerializer.render(follow_salmon)
-      follow.destroy!
-      envelope = OStatus2::Salmon.new.pack(xml, follow.account.keypair)
-
-      ProcessInteractionService.new.call(envelope, follow.target_account)
-
-      expect(follow.account.following?(follow.target_account)).to be true
-    end
-  end
-
-  describe '#unfollow_salmon' do
-    include_examples 'namespaces' do
-      def serialize
-        follow = Fabricate(:follow)
-        follow.destroy!
-        OStatus::AtomSerializer.new.unfollow_salmon(follow)
-      end
-    end
-
-    it 'returns entry element' do
-      follow = Fabricate(:follow)
-      follow.destroy!
-
-      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
-
-      expect(unfollow_salmon.name).to eq 'entry'
-    end
-
-    it 'appends id element with unique tag' do
-      follow = Fabricate(:follow)
-      follow.destroy!
-
-      time_before = Time.zone.now
-      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
-      time_after = Time.zone.now
-
-      expect(unfollow_salmon.id.text).to(
-        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, follow.id, 'Follow'))
-          .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, follow.id, 'Follow')))
-      )
-    end
-
-    it 'appends title element with description' do
-      account = Fabricate(:account, domain: nil, username: 'account')
-      target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
-      follow = Fabricate(:follow, account: account, target_account: target_account)
-      follow.destroy!
-
-      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
-
-      expect(unfollow_salmon.title.text).to eq 'account is no longer following target_account@remote'
-    end
-
-    it 'appends content element with description' do
-      account = Fabricate(:account, domain: nil, username: 'account')
-      target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
-      follow = Fabricate(:follow, account: account, target_account: target_account)
-      follow.destroy!
-
-      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
-
-      expect(unfollow_salmon.content.text).to eq 'account is no longer following target_account@remote'
-    end
-
-    it 'appends author element with account' do
-      account = Fabricate(:account, domain: nil, username: 'username')
-      follow = Fabricate(:follow, account: account)
-      follow.destroy!
-
-      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
-
-      expect(unfollow_salmon.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
-    end
-
-    it 'appends activity:object-type element with activity type' do
-      follow = Fabricate(:follow)
-      follow.destroy!
-
-      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
-
-      object_type = unfollow_salmon.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
-    end
-
-    it 'appends activity:verb element with follow' do
-      follow = Fabricate(:follow)
-      follow.destroy!
-
-      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
-
-      verb = unfollow_salmon.nodes.find { |node| node.name == 'activity:verb' }
-      expect(verb.text).to eq OStatus::TagManager::VERBS[:unfollow]
-    end
-
-    it 'appends activity:object element with target account' do
-      target_account = Fabricate(:account, domain: 'domain.test', uri: 'https://domain.test/id')
-      follow = Fabricate(:follow, target_account: target_account)
-      follow.destroy!
-
-      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
-
-      object = unfollow_salmon.nodes.find { |node| node.name == 'activity:object' }
-      expect(object.id.text).to eq 'https://domain.test/id'
-    end
-
-    it 'returns element whose rendered view triggers unfollow when processed' do
-      follow = Fabricate(:follow)
-      follow.destroy!
-      unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
-      xml = OStatus::AtomSerializer.render(unfollow_salmon)
-      follow.account.follow!(follow.target_account)
-      envelope = OStatus2::Salmon.new.pack(xml, follow.account.keypair)
-
-      ProcessInteractionService.new.call(envelope, follow.target_account)
-
-      expect(follow.account.following?(follow.target_account)).to be false
-    end
-  end
-
-  describe '#follow_request_salmon' do
-    include_examples 'namespaces' do
-      def serialize
-        follow_request = Fabricate(:follow_request)
-        OStatus::AtomSerializer.new.follow_request_salmon(follow_request)
-      end
-    end
-
-    context do
-      def serialize(follow_request)
-        OStatus::AtomSerializer.new.follow_request_salmon(follow_request)
-      end
-
-      it_behaves_like 'follow request salmon'
-
-      it 'appends id element with unique tag' do
-        follow_request = Fabricate(:follow_request, created_at: '2000-01-01T00:00:00Z')
-        follow_request_salmon = serialize(follow_request)
-        expect(follow_request_salmon.id.text).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{follow_request.id}:objectType=FollowRequest"
-      end
-
-      it 'appends title element with description' do
-        account = Fabricate(:account, domain: nil, username: 'account')
-        target_account = Fabricate(:account, domain: 'remote', username: 'target_account')
-        follow_request = Fabricate(:follow_request, account: account, target_account: target_account)
-        follow_request_salmon = serialize(follow_request)
-        expect(follow_request_salmon.title.text).to eq 'account requested to follow target_account@remote'
-      end
-
-      it 'returns element whose rendered view triggers follow request when processed' do
-        follow_request = Fabricate(:follow_request)
-        follow_request_salmon = serialize(follow_request)
-        xml = OStatus::AtomSerializer.render(follow_request_salmon)
-        envelope = OStatus2::Salmon.new.pack(xml, follow_request.account.keypair)
-        follow_request.destroy!
-
-        ProcessInteractionService.new.call(envelope, follow_request.target_account)
-
-        expect(follow_request.account.requested?(follow_request.target_account)).to eq true
-      end
-    end
-  end
-
-  describe '#authorize_follow_request_salmon' do
-    include_examples 'namespaces' do
-      def serialize
-        follow_request = Fabricate(:follow_request)
-        OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
-      end
-    end
-
-    it_behaves_like 'follow request salmon' do
-      def serialize(follow_request)
-        authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
-        authorize_follow_request_salmon.nodes.find { |node| node.name == 'activity:object' }
-      end
-    end
-
-    it 'appends id element with unique tag' do
-      follow_request = Fabricate(:follow_request)
-
-      time_before = Time.zone.now
-      authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
-      time_after = Time.zone.now
-
-      expect(authorize_follow_request_salmon.id.text).to(
-        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, follow_request.id, 'FollowRequest'))
-          .or(eq(OStatus::TagManager.instance.unique_tag(time_after.utc, follow_request.id, 'FollowRequest')))
-      )
-    end
-
-    it 'appends title element with description' do
-      account = Fabricate(:account, domain: 'remote', username: 'account')
-      target_account = Fabricate(:account, domain: nil, username: 'target_account')
-      follow_request = Fabricate(:follow_request, account: account, target_account: target_account)
-
-      authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
-
-      expect(authorize_follow_request_salmon.title.text).to eq 'target_account authorizes follow request by account@remote'
-    end
-
-    it 'appends activity:object-type element with activity type' do
-      follow_request = Fabricate(:follow_request)
-
-      authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
-
-      object_type = authorize_follow_request_salmon.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
-    end
-
-    it 'appends activity:verb element with authorize' do
-      follow_request = Fabricate(:follow_request)
-
-      authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
-
-      verb = authorize_follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }
-      expect(verb.text).to eq OStatus::TagManager::VERBS[:authorize]
-    end
-
-    it 'returns element whose rendered view creates follow from follow request when processed' do
-      follow_request = Fabricate(:follow_request)
-      authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
-      xml = OStatus::AtomSerializer.render(authorize_follow_request_salmon)
-      envelope = OStatus2::Salmon.new.pack(xml, follow_request.target_account.keypair)
-
-      ProcessInteractionService.new.call(envelope, follow_request.account)
-
-      expect(follow_request.account.following?(follow_request.target_account)).to eq true
-      expect { follow_request.reload }.to raise_error ActiveRecord::RecordNotFound
-    end
-  end
-
-  describe '#reject_follow_request_salmon' do
-    include_examples 'namespaces' do
-      def serialize
-        follow_request = Fabricate(:follow_request)
-        OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
-      end
-    end
-
-    it_behaves_like 'follow request salmon' do
-      def serialize(follow_request)
-        reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
-        reject_follow_request_salmon.nodes.find { |node| node.name == 'activity:object' }
-      end
-    end
-
-    it 'appends id element with unique tag' do
-      follow_request = Fabricate(:follow_request)
-
-      time_before = Time.zone.now
-      reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
-      time_after = Time.zone.now
-
-      expect(reject_follow_request_salmon.id.text).to(
-        eq(OStatus::TagManager.instance.unique_tag(time_before.utc, follow_request.id, 'FollowRequest'))
-          .or(OStatus::TagManager.instance.unique_tag(time_after.utc, follow_request.id, 'FollowRequest'))
-      )
-    end
-
-    it 'appends title element with description' do
-      account = Fabricate(:account, domain: 'remote', username: 'account')
-      target_account = Fabricate(:account, domain: nil, username: 'target_account')
-      follow_request = Fabricate(:follow_request, account: account, target_account: target_account)
-      reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
-      expect(reject_follow_request_salmon.title.text).to eq 'target_account rejects follow request by account@remote'
-    end
-
-    it 'appends activity:object-type element with activity type' do
-      follow_request = Fabricate(:follow_request)
-      reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
-      object_type = reject_follow_request_salmon.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq OStatus::TagManager::TYPES[:activity]
-    end
-
-    it 'appends activity:verb element with authorize' do
-      follow_request = Fabricate(:follow_request)
-      reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
-      verb = reject_follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }
-      expect(verb.text).to eq OStatus::TagManager::VERBS[:reject]
-    end
-
-    it 'returns element whose rendered view deletes follow request when processed' do
-      follow_request = Fabricate(:follow_request)
-      reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
-      xml = OStatus::AtomSerializer.render(reject_follow_request_salmon)
-      envelope = OStatus2::Salmon.new.pack(xml, follow_request.target_account.keypair)
-
-      ProcessInteractionService.new.call(envelope, follow_request.account)
-
-      expect(follow_request.account.following?(follow_request.target_account)).to eq false
-      expect { follow_request.reload }.to raise_error ActiveRecord::RecordNotFound
-    end
-  end
-
-  describe '#object' do
-    include_examples 'status attributes' do
-      def serialize(status)
-        OStatus::AtomSerializer.new.object(status)
-      end
-    end
-
-    it 'returns activity:object element' do
-      status = Fabricate(:status)
-      object = OStatus::AtomSerializer.new.object(status)
-      expect(object.name).to eq 'activity:object'
-    end
-
-    it 'appends id element with URL for status' do
-      status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
-      object = OStatus::AtomSerializer.new.object(status)
-      expect(object.id.text).to eq "https://cb6e6126.ngrok.io/users/#{status.account.to_param}/statuses/#{status.id}"
-    end
-
-    it 'appends published element with created date' do
-      status = Fabricate(:status, created_at: '2000-01-01T00:00:00Z')
-      object = OStatus::AtomSerializer.new.object(status)
-      expect(object.published.text).to eq '2000-01-01T00:00:00Z'
-    end
-
-    it 'appends updated element with updated date' do
-      status = Fabricate(:status)
-      status.updated_at = '2000-01-01T00:00:00Z'
-      object = OStatus::AtomSerializer.new.object(status)
-      expect(object.updated.text).to eq '2000-01-01T00:00:00Z'
-    end
-
-    it 'appends title element with title' do
-      account = Fabricate(:account, username: 'username')
-      status = Fabricate(:status, account: account)
-
-      object = OStatus::AtomSerializer.new.object(status)
-
-      expect(object.title.text).to eq 'New status by username'
-    end
-
-    it 'appends author element with account' do
-      account = Fabricate(:account, username: 'username')
-      status = Fabricate(:status, account: account)
-
-      entry = OStatus::AtomSerializer.new.object(status)
-
-      expect(entry.author.id.text).to eq 'https://cb6e6126.ngrok.io/users/username'
-    end
-
-    it 'appends activity:object-type element with object type' do
-      status = Fabricate(:status)
-
-      entry = OStatus::AtomSerializer.new.object(status)
-
-      object_type = entry.nodes.find { |node| node.name == 'activity:object-type' }
-      expect(object_type.text).to eq OStatus::TagManager::TYPES[:note]
-    end
-
-    it 'appends activity:verb element with verb' do
-      status = Fabricate(:status)
-
-      entry = OStatus::AtomSerializer.new.object(status)
-
-      object_type = entry.nodes.find { |node| node.name == 'activity:verb' }
-      expect(object_type.text).to eq OStatus::TagManager::VERBS[:post]
-    end
-
-    it 'appends link element for an alternative' do
-      account = Fabricate(:account, username: 'username')
-      status = Fabricate(:status, account: account)
-
-      entry = OStatus::AtomSerializer.new.object(status)
-
-      link = entry.nodes.find { |node| node.name == 'link' && node[:rel] == 'alternate' && node[:type] == 'text/html' }
-      expect(link[:type]).to eq 'text/html'
-      expect(link[:href]).to eq "https://cb6e6126.ngrok.io/@username/#{status.id}"
-    end
-
-    it 'appends thr:in-reply-to element if it is a reply and thread is not nil' do
-      account = Fabricate(:account, username: 'username')
-      thread = Fabricate(:status, account: account, created_at: '2000-01-01T00:00:00Z')
-      reply = Fabricate(:status, thread: thread)
-
-      entry = OStatus::AtomSerializer.new.object(reply)
-
-      in_reply_to = entry.nodes.find { |node| node.name == 'thr:in-reply-to' }
-      expect(in_reply_to.ref).to eq "https://cb6e6126.ngrok.io/users/#{thread.account.to_param}/statuses/#{thread.id}"
-      expect(in_reply_to.href).to eq "https://cb6e6126.ngrok.io/@username/#{thread.id}"
-    end
-
-    it 'does not append thr:in-reply-to element if thread is nil' do
-      status = Fabricate(:status, thread: nil)
-      entry = OStatus::AtomSerializer.new.object(status)
-      entry.nodes.each { |node| expect(node.name).not_to eq 'thr:in-reply-to' }
-    end
-
-    it 'does not append ostatus:conversation element if conversation_id is nil' do
-      status = Fabricate.build(:status, conversation_id: nil)
-      status.save!(validate: false)
-
-      entry = OStatus::AtomSerializer.new.object(status)
-
-      entry.nodes.each { |node| expect(node.name).not_to eq 'ostatus:conversation' }
-    end
-
-    it 'appends ostatus:conversation element if conversation_id is not nil' do
-      status = Fabricate(:status)
-      status.conversation.update!(created_at: '2000-01-01T00:00:00Z')
-
-      entry = OStatus::AtomSerializer.new.object(status)
-
-      conversation = entry.nodes.find { |node| node.name == 'ostatus:conversation' }
-      expect(conversation[:ref]).to eq "tag:cb6e6126.ngrok.io,2000-01-01:objectId=#{status.conversation.id}:objectType=Conversation"
-    end
-  end
-end
diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb
index 379872316..8167e3a91 100644
--- a/spec/models/account_spec.rb
+++ b/spec/models/account_spec.rb
@@ -215,13 +215,6 @@ RSpec.describe Account, type: :model do
     end
   end
 
-  describe '#subscription' do
-    it 'returns an OStatus subscription' do
-      account = Fabricate(:account)
-      expect(account.subscription('')).to be_instance_of OStatus2::Subscription
-    end
-  end
-
   describe '#object_type' do
     it 'is always a person' do
       account = Fabricate(:account)
diff --git a/spec/models/remote_profile_spec.rb b/spec/models/remote_profile_spec.rb
deleted file mode 100644
index da5048f0a..000000000
--- a/spec/models/remote_profile_spec.rb
+++ /dev/null
@@ -1,143 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-RSpec.describe RemoteProfile do
-  let(:remote_profile) { RemoteProfile.new(body) }
-  let(:body) do
-    <<-XML
-      <feed xmlns="http://www.w3.org/2005/Atom">
-      <author>John</author>
-    XML
-  end
-
-  describe '.initialize' do
-    it 'calls Nokogiri::XML.parse' do
-      expect(Nokogiri::XML).to receive(:parse).with(body, nil, 'utf-8')
-      RemoteProfile.new(body)
-    end
-
-    it 'sets document' do
-      remote_profile = RemoteProfile.new(body)
-      expect(remote_profile).not_to be nil
-    end
-  end
-
-  describe '#root' do
-    let(:document) { remote_profile.document }
-
-    it 'callse document.at_xpath' do
-      expect(document).to receive(:at_xpath).with(
-        '/atom:feed|/atom:entry',
-        atom: OStatus::TagManager::XMLNS
-      )
-
-      remote_profile.root
-    end
-  end
-
-  describe '#author' do
-    let(:root) { remote_profile.root }
-
-    it 'calls root.at_xpath' do
-      expect(root).to receive(:at_xpath).with(
-        './atom:author|./dfrn:owner',
-        atom: OStatus::TagManager::XMLNS,
-        dfrn: OStatus::TagManager::DFRN_XMLNS
-      )
-
-      remote_profile.author
-    end
-  end
-
-  describe '#hub_link' do
-    let(:root) { remote_profile.root }
-
-    it 'calls #link_href_from_xml' do
-      expect(remote_profile).to receive(:link_href_from_xml).with(root, 'hub')
-      remote_profile.hub_link
-    end
-  end
-
-  describe '#display_name' do
-    let(:author) { remote_profile.author }
-
-    it 'calls author.at_xpath.content' do
-      expect(author).to receive_message_chain(:at_xpath, :content).with(
-        './poco:displayName',
-        poco: OStatus::TagManager::POCO_XMLNS
-      ).with(no_args)
-
-      remote_profile.display_name
-    end
-  end
-
-  describe '#note' do
-    let(:author) { remote_profile.author }
-
-    it 'calls author.at_xpath.content' do
-      expect(author).to receive_message_chain(:at_xpath, :content).with(
-        './atom:summary|./poco:note',
-        atom: OStatus::TagManager::XMLNS,
-        poco: OStatus::TagManager::POCO_XMLNS
-      ).with(no_args)
-
-      remote_profile.note
-    end
-  end
-
-  describe '#scope' do
-    let(:author) { remote_profile.author }
-
-    it 'calls author.at_xpath.content' do
-      expect(author).to receive_message_chain(:at_xpath, :content).with(
-        './mastodon:scope',
-        mastodon: OStatus::TagManager::MTDN_XMLNS
-      ).with(no_args)
-
-      remote_profile.scope
-    end
-  end
-
-  describe '#avatar' do
-    let(:author) { remote_profile.author }
-
-    it 'calls #link_href_from_xml' do
-      expect(remote_profile).to receive(:link_href_from_xml).with(author, 'avatar')
-      remote_profile.avatar
-    end
-  end
-
-  describe '#header' do
-    let(:author) { remote_profile.author }
-
-    it 'calls #link_href_from_xml' do
-      expect(remote_profile).to receive(:link_href_from_xml).with(author, 'header')
-      remote_profile.header
-    end
-  end
-
-  describe '#locked?' do
-    before do
-      allow(remote_profile).to receive(:scope).and_return(scope)
-    end
-
-    subject { remote_profile.locked? }
-
-    context 'scope is private' do
-      let(:scope) { 'private' }
-
-      it 'returns true' do
-        is_expected.to be true
-      end
-    end
-
-    context 'scope is not private' do
-      let(:scope) { 'public' }
-
-      it 'returns false' do
-        is_expected.to be false
-      end
-    end
-  end
-end
diff --git a/spec/services/authorize_follow_service_spec.rb b/spec/services/authorize_follow_service_spec.rb
index 562ef0041..8e5d8fb03 100644
--- a/spec/services/authorize_follow_service_spec.rb
+++ b/spec/services/authorize_follow_service_spec.rb
@@ -22,31 +22,6 @@ RSpec.describe AuthorizeFollowService, type: :service do
     end
   end
 
-  describe 'remote OStatus' do
-    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }
-
-    before do
-      FollowRequest.create(account: bob, target_account: sender)
-      stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
-      subject.call(bob, sender)
-    end
-
-    it 'removes follow request' do
-      expect(bob.requested?(sender)).to be false
-    end
-
-    it 'creates follow relation' do
-      expect(bob.following?(sender)).to be true
-    end
-
-    it 'sends a follow request authorization salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:authorize])
-      }).to have_been_made.once
-    end
-  end
-
   describe 'remote ActivityPub' do
     let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox')).account }
 
diff --git a/spec/services/batched_remove_status_service_spec.rb b/spec/services/batched_remove_status_service_spec.rb
index e53623449..6b0efb1cd 100644
--- a/spec/services/batched_remove_status_service_spec.rb
+++ b/spec/services/batched_remove_status_service_spec.rb
@@ -4,7 +4,6 @@ RSpec.describe BatchedRemoveStatusService, type: :service do
   subject { BatchedRemoveStatusService.new }
 
   let!(:alice)  { Fabricate(:account) }
-  let!(:bob)    { Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://example.com/salmon') }
   let!(:jeff)   { Fabricate(:user).account }
   let!(:hank)   { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
 
@@ -14,11 +13,8 @@ RSpec.describe BatchedRemoveStatusService, type: :service do
   before do
     allow(Redis.current).to receive_messages(publish: nil)
 
-    stub_request(:post, 'http://example.com/push').to_return(status: 200, body: '', headers: {})
-    stub_request(:post, 'http://example.com/salmon').to_return(status: 200, body: '', headers: {})
     stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
 
-    Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)
     jeff.user.update(current_sign_in_at: Time.zone.now)
     jeff.follow!(alice)
     hank.follow!(alice)
@@ -49,19 +45,6 @@ RSpec.describe BatchedRemoveStatusService, type: :service do
     expect(Redis.current).to have_received(:publish).with('timeline:public', any_args).at_least(:once)
   end
 
-  it 'sends PuSH update to PuSH subscribers' do
-    expect(a_request(:post, 'http://example.com/push').with { |req|
-      matches = req.body.match(OStatus::TagManager::VERBS[:delete])
-    }).to have_been_made.at_least_once
-  end
-
-  it 'sends Salmon slap to previously mentioned users' do
-    expect(a_request(:post, "http://example.com/salmon").with { |req|
-      xml = OStatus2::Salmon.new.unpack(req.body)
-      xml.match(OStatus::TagManager::VERBS[:delete])
-    }).to have_been_made.once
-  end
-
   it 'sends delete activity to followers' do
     expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.at_least_once
   end
diff --git a/spec/services/favourite_service_spec.rb b/spec/services/favourite_service_spec.rb
index 0a20ccf6e..fc7f58eb4 100644
--- a/spec/services/favourite_service_spec.rb
+++ b/spec/services/favourite_service_spec.rb
@@ -18,27 +18,6 @@ RSpec.describe FavouriteService, type: :service do
     end
   end
 
-  describe 'remote OStatus' do
-    let(:bob)    { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }
-    let(:status) { Fabricate(:status, account: bob, uri: 'tag:example.com:blahblah') }
-
-    before do
-      stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
-      subject.call(sender, status)
-    end
-
-    it 'creates a favourite' do
-      expect(status.favourites.first).to_not be_nil
-    end
-
-    it 'sends a salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:favorite])
-      }).to have_been_made.once
-    end
-  end
-
   describe 'remote ActivityPub' do
     let(:bob)    { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :activitypub, username: 'bob', domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }
     let(:status) { Fabricate(:status, account: bob) }
diff --git a/spec/services/fetch_atom_service_spec.rb b/spec/services/fetch_atom_service_spec.rb
index 495540004..32c284243 100644
--- a/spec/services/fetch_atom_service_spec.rb
+++ b/spec/services/fetch_atom_service_spec.rb
@@ -54,24 +54,18 @@ RSpec.describe FetchAtomService, type: :service do
         WebMock.stub_request(:get, url).to_return(status: 200, body: body, headers: headers)
       end
 
-      context 'content type is application/atom+xml' do
-        let(:content_type) { 'application/atom+xml' }
-
-        it { is_expected.to eq [url, { :prefetched_body => "" }, :ostatus] }
-      end
-
       context 'content_type is activity+json' do
         let(:content_type) { 'application/activity+json; charset=utf-8' }
         let(:body) { json }
 
-        it { is_expected.to eq [1, { prefetched_body: body, id: true }, :activitypub] }
+        it { is_expected.to eq [1, { prefetched_body: body, id: true }] }
       end
 
       context 'content_type is ld+json with profile' do
         let(:content_type) { 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' }
         let(:body) { json }
 
-        it { is_expected.to eq [1, { prefetched_body: body, id: true }, :activitypub] }
+        it { is_expected.to eq [1, { prefetched_body: body, id: true }] }
       end
 
       before do
@@ -82,14 +76,14 @@ RSpec.describe FetchAtomService, type: :service do
       context 'has link header' do
         let(:headers) { { 'Link' => '<http://example.com/foo>; rel="alternate"; type="application/activity+json"', } }
 
-        it { is_expected.to eq [1, { prefetched_body: json, id: true }, :activitypub] }
+        it { is_expected.to eq [1, { prefetched_body: json, id: true }] }
       end
 
       context 'content type is text/html' do
         let(:content_type) { 'text/html' }
         let(:body) { '<html><head><link rel="alternate" href="http://example.com/foo" type="application/activity+json"/></head></html>' }
 
-        it { is_expected.to eq [1, { prefetched_body: json, id: true }, :activitypub] }
+        it { is_expected.to eq [1, { prefetched_body: json, id: true }] }
       end
     end
   end
diff --git a/spec/services/fetch_remote_account_service_spec.rb b/spec/services/fetch_remote_account_service_spec.rb
index 3cd86708b..d536f9ed3 100644
--- a/spec/services/fetch_remote_account_service_spec.rb
+++ b/spec/services/fetch_remote_account_service_spec.rb
@@ -3,8 +3,7 @@ require 'rails_helper'
 RSpec.describe FetchRemoteAccountService, type: :service do
   let(:url) { 'https://example.com/alice' }
   let(:prefetched_body) { nil }
-  let(:protocol) { :ostatus }
-  subject { FetchRemoteAccountService.new.call(url, prefetched_body, protocol) }
+  subject { FetchRemoteAccountService.new.call(url, prefetched_body) }
 
   let(:actor) do
     {
@@ -19,7 +18,6 @@ RSpec.describe FetchRemoteAccountService, type: :service do
   end
 
   let(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
-  let(:xml) { File.read(Rails.root.join('spec', 'fixtures', 'xml', 'mastodon.atom')) }
 
   shared_examples 'return Account' do
     it { is_expected.to be_an Account }
@@ -27,7 +25,6 @@ RSpec.describe FetchRemoteAccountService, type: :service do
 
   context 'protocol is :activitypub' do
     let(:prefetched_body) { Oj.dump(actor) }
-    let(:protocol) { :activitypub }
 
     before do
       stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
@@ -36,36 +33,6 @@ RSpec.describe FetchRemoteAccountService, type: :service do
     include_examples 'return Account'
   end
 
-  context 'protocol is :ostatus' do
-    let(:prefetched_body) { xml }
-    let(:protocol) { :ostatus }
-
-    before do
-      stub_request(:get, "https://kickass.zone/.well-known/webfinger?resource=acct:localhost@kickass.zone").to_return(request_fixture('webfinger-hacker3.txt'))
-      stub_request(:get, "https://kickass.zone/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
-    end
-
-    include_examples 'return Account'
-
-    it 'does not update account information if XML comes from an unverified domain' do
-      feed_xml = <<-XML.squish
-        <?xml version="1.0" encoding="UTF-8"?>
-        <feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
-          <author>
-            <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-            <uri>http://kickass.zone/users/localhost</uri>
-            <name>localhost</name>
-            <poco:preferredUsername>localhost</poco:preferredUsername>
-            <poco:displayName>Villain!!!</poco:displayName>
-          </author>
-        </feed>
-      XML
-
-      returned_account = described_class.new.call('https://real-fake-domains.com/alice', feed_xml, :ostatus)
-      expect(returned_account.display_name).to_not eq 'Villain!!!'
-    end
-  end
-
   context 'when prefetched_body is nil' do
     context 'protocol is :activitypub' do
       before do
@@ -75,15 +42,5 @@ RSpec.describe FetchRemoteAccountService, type: :service do
 
       include_examples 'return Account'
     end
-
-    context 'protocol is :ostatus' do
-      before do
-        stub_request(:get, url).to_return(status: 200, body: xml, headers: { 'Content-Type' => 'application/atom+xml' })
-        stub_request(:get, "https://kickass.zone/.well-known/webfinger?resource=acct:localhost@kickass.zone").to_return(request_fixture('webfinger-hacker3.txt'))
-        stub_request(:get, "https://kickass.zone/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
-      end
-
-      include_examples 'return Account'
-    end
   end
 end
diff --git a/spec/services/fetch_remote_status_service_spec.rb b/spec/services/fetch_remote_status_service_spec.rb
index f9db024b9..0e63cc9eb 100644
--- a/spec/services/fetch_remote_status_service_spec.rb
+++ b/spec/services/fetch_remote_status_service_spec.rb
@@ -16,9 +16,8 @@ RSpec.describe FetchRemoteStatusService, type: :service do
   end
 
   context 'protocol is :activitypub' do
-    subject { described_class.new.call(note[:id], prefetched_body, protocol) }
+    subject { described_class.new.call(note[:id], prefetched_body) }
     let(:prefetched_body) { Oj.dump(note) }
-    let(:protocol) { :activitypub }
 
     before do
       account.update(uri: ActivityPub::TagManager.instance.uri_for(account))
@@ -32,56 +31,4 @@ RSpec.describe FetchRemoteStatusService, type: :service do
       expect(status.text).to eq 'Lorem ipsum'
     end
   end
-
-  context 'protocol is :ostatus' do
-    subject { described_class.new }
-
-    before do
-      Fabricate(:account, username: 'tracer', domain: 'real.domain', remote_url: 'https://real.domain/users/tracer')
-    end
-
-    it 'does not create status with author at different domain' do
-      status_body = <<-XML.squish
-        <?xml version="1.0"?>
-        <entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-          <id>tag:real.domain,2017-04-27:objectId=4487555:objectType=Status</id>
-          <published>2017-04-27T13:49:25Z</published>
-          <updated>2017-04-27T13:49:25Z</updated>
-          <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-          <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-          <author>
-            <id>https://real.domain/users/tracer</id>
-            <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-            <uri>https://real.domain/users/tracer</uri>
-            <name>tracer</name>
-          </author>
-          <content type="html">Overwatch rocks</content>
-        </entry>
-      XML
-
-      expect(subject.call('https://fake.domain/foo', status_body, :ostatus)).to be_nil
-    end
-
-    it 'does not create status with wrong id when id uses http format' do
-      status_body = <<-XML.squish
-        <?xml version="1.0"?>
-        <entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-          <id>https://other-real.domain/statuses/123</id>
-          <published>2017-04-27T13:49:25Z</published>
-          <updated>2017-04-27T13:49:25Z</updated>
-          <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-          <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-          <author>
-            <id>https://real.domain/users/tracer</id>
-            <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-            <uri>https://real.domain/users/tracer</uri>
-            <name>tracer</name>
-          </author>
-          <content type="html">Overwatch rocks</content>
-        </entry>
-      XML
-
-      expect(subject.call('https://real.domain/statuses/456', status_body, :ostatus)).to be_nil
-    end
-  end
 end
diff --git a/spec/services/follow_service_spec.rb b/spec/services/follow_service_spec.rb
index 3c4ec59be..86c85293e 100644
--- a/spec/services/follow_service_spec.rb
+++ b/spec/services/follow_service_spec.rb
@@ -96,74 +96,6 @@ RSpec.describe FollowService, type: :service do
     end
   end
 
-  context 'remote OStatus account' do
-    describe 'locked account' do
-      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, locked: true, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }
-
-      before do
-        stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
-        subject.call(sender, bob.acct)
-      end
-
-      it 'creates a follow request' do
-        expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil
-      end
-
-      it 'sends a follow request salmon slap' do
-        expect(a_request(:post, "http://salmon.example.com/").with { |req|
-          xml = OStatus2::Salmon.new.unpack(req.body)
-          xml.match(OStatus::TagManager::VERBS[:request_friend])
-        }).to have_been_made.once
-      end
-    end
-
-    describe 'unlocked account' do
-      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com', hub_url: 'http://hub.example.com')).account }
-
-      before do
-        stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
-        stub_request(:post, "http://hub.example.com/").to_return(status: 202)
-        subject.call(sender, bob.acct)
-      end
-
-      it 'creates a following relation' do
-        expect(sender.following?(bob)).to be true
-      end
-
-      it 'sends a follow salmon slap' do
-        expect(a_request(:post, "http://salmon.example.com/").with { |req|
-          xml = OStatus2::Salmon.new.unpack(req.body)
-          xml.match(OStatus::TagManager::VERBS[:follow])
-        }).to have_been_made.once
-      end
-
-      it 'subscribes to PuSH' do
-        expect(a_request(:post, "http://hub.example.com/")).to have_been_made.once
-      end
-    end
-
-    describe 'already followed account' do
-      let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com', hub_url: 'http://hub.example.com')).account }
-
-      before do
-        sender.follow!(bob)
-        subject.call(sender, bob.acct)
-      end
-
-      it 'keeps a following relation' do
-        expect(sender.following?(bob)).to be true
-      end
-
-      it 'does not send a follow salmon slap' do
-        expect(a_request(:post, "http://salmon.example.com/")).not_to have_been_made
-      end
-
-      it 'does not subscribe to PuSH' do
-        expect(a_request(:post, "http://hub.example.com/")).not_to have_been_made
-      end
-    end
-  end
-
   context 'remote ActivityPub account' do
     let(:bob) { Fabricate(:user, account: Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox')).account }
 
diff --git a/spec/services/process_feed_service_spec.rb b/spec/services/process_feed_service_spec.rb
deleted file mode 100644
index 9d3465f3f..000000000
--- a/spec/services/process_feed_service_spec.rb
+++ /dev/null
@@ -1,252 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe ProcessFeedService, type: :service do
-  subject { ProcessFeedService.new }
-
-  describe 'processing a feed' do
-    let(:body) { File.read(Rails.root.join('spec', 'fixtures', 'xml', 'mastodon.atom')) }
-    let(:account) { Fabricate(:account, username: 'localhost', domain: 'kickass.zone') }
-
-    before do
-      stub_request(:post, "https://pubsubhubbub.superfeedr.com/").to_return(:status => 200, :body => "", :headers => {})
-      stub_request(:head, "http://kickass.zone/media/2").to_return(:status => 404)
-      stub_request(:head, "http://kickass.zone/media/3").to_return(:status => 404)
-      stub_request(:get, "http://kickass.zone/system/accounts/avatars/000/000/001/large/eris.png").to_return(request_fixture('avatar.txt'))
-      stub_request(:get, "http://kickass.zone/system/media_attachments/files/000/000/002/original/morpheus_linux.jpg?1476059910").to_return(request_fixture('attachment1.txt'))
-      stub_request(:get, "http://kickass.zone/system/media_attachments/files/000/000/003/original/gizmo.jpg?1476060065").to_return(request_fixture('attachment2.txt'))
-    end
-
-    context 'when domain does not reject media' do
-      before do
-        subject.call(body, account)
-      end
-
-      it 'updates remote user\'s account information' do
-        account.reload
-        expect(account.display_name).to eq '::1'
-        expect(account).to have_attached_file(:avatar)
-        expect(account.avatar_file_name).not_to be_nil
-      end
-
-      it 'creates posts' do
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Status')).to_not be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')).to_not be_nil
-      end
-
-      it 'marks replies as replies' do
-        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')
-        expect(status.reply?).to be true
-      end
-
-      it 'sets account being replied to when possible' do
-        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')
-        expect(status.in_reply_to_account_id).to eq status.account_id
-      end
-
-      it 'ignores delete statuses unless they existed before' do
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=3:objectType=Status')).to be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=12:objectType=Status')).to be_nil
-      end
-
-      it 'does not create statuses for follows' do
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Follow')).to be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Follow')).to be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=4:objectType=Follow')).to be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=7:objectType=Follow')).to be_nil
-      end
-
-      it 'does not create statuses for favourites' do
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Favourite')).to be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=3:objectType=Favourite')).to be_nil
-      end
-
-      it 'creates posts with media' do
-        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=14:objectType=Status')
-
-        expect(status).to_not be_nil
-        expect(status.media_attachments.first).to have_attached_file(:file)
-        expect(status.media_attachments.first.image?).to be true
-        expect(status.media_attachments.first.file_file_name).not_to be_nil
-      end
-    end
-
-    context 'when domain is set to reject media' do
-      let!(:domain_block) { Fabricate(:domain_block, domain: 'kickass.zone', reject_media: true) }
-
-      before do
-        subject.call(body, account)
-      end
-
-      it 'updates remote user\'s account information' do
-        account.reload
-        expect(account.display_name).to eq '::1'
-      end
-
-      it 'rejects remote user\'s avatar' do
-        account.reload
-        expect(account.display_name).to eq '::1'
-        expect(account.avatar_file_name).to be_nil
-      end
-
-      it 'creates posts' do
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Status')).to_not be_nil
-        expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')).to_not be_nil
-      end
-
-      it 'creates posts with remote-only media' do
-        status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=14:objectType=Status')
-
-        expect(status).to_not be_nil
-        expect(status.media_attachments.first.file_file_name).to be_nil
-        expect(status.media_attachments.first.unknown?).to be true
-      end
-    end
-  end
-
-  it 'does not accept tampered reblogs' do
-    good_actor = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')
-
-    real_body = <<XML
-<?xml version="1.0"?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-  <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
-  <published>2017-04-27T13:49:25Z</published>
-  <updated>2017-04-27T13:49:25Z</updated>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-  <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-  <author>
-    <id>https://overwatch.com/users/tracer</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-    <uri>https://overwatch.com/users/tracer</uri>
-    <name>tracer</name>
-  </author>
-  <content type="html">Overwatch rocks</content>
-</entry>
-XML
-
-    stub_request(:get, 'https://overwatch.com/users/tracer/updates/1').to_return(status: 200, body: real_body, headers: { 'Content-Type' => 'application/atom+xml' })
-
-    bad_actor = Fabricate(:account, username: 'sombra', domain: 'talon.xyz')
-
-    body = <<XML
-<?xml version="1.0"?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-  <id>tag:talon.xyz,2017-04-27:objectId=4467137:objectType=Status</id>
-  <published>2017-04-27T13:49:25Z</published>
-  <updated>2017-04-27T13:49:25Z</updated>
-  <author>
-    <id>https://talon.xyz/users/sombra</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-    <uri>https://talon.xyz/users/sombra</uri>
-    <name>sombra</name>
-  </author>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
-  <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
-  <content type="html">Overwatch SUCKS AHAHA</content>
-  <activity:object>
-    <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-    <author>
-      <id>https://overwatch.com/users/tracer</id>
-      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-      <uri>https://overwatch.com/users/tracer</uri>
-      <name>tracer</name>
-    </author>
-    <content type="html">Overwatch SUCKS AHAHA</content>
-    <link rel="alternate" type="text/html" href="https://overwatch.com/users/tracer/updates/1" />
-  </activity:object>
-</entry>
-XML
-    created_statuses = subject.call(body, bad_actor)
-
-    expect(created_statuses.first.reblog?).to be true
-    expect(created_statuses.first.account_id).to eq bad_actor.id
-    expect(created_statuses.first.reblog.account_id).to eq good_actor.id
-    expect(created_statuses.first.reblog.text).to eq 'Overwatch rocks'
-  end
-
-  it 'ignores reblogs if it failed to retrieve reblogged statuses' do
-    stub_request(:get, 'https://overwatch.com/users/tracer/updates/1').to_return(status: 404)
-
-    actor = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')
-
-    body = <<XML
-<?xml version="1.0"?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-  <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
-  <published>2017-04-27T13:49:25Z</published>
-  <updated>2017-04-27T13:49:25Z</updated>
-  <author>
-    <id>https://overwatch.com/users/tracer</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-    <uri>https://overwatch.com/users/tracer</uri>
-    <name>tracer</name>
-  </author>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
-  <activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
-  <content type="html">Overwatch rocks</content>
-  <activity:object>
-    <id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-    <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-    <author>
-      <id>https://overwatch.com/users/tracer</id>
-      <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-      <uri>https://overwatch.com/users/tracer</uri>
-      <name>tracer</name>
-    </author>
-    <content type="html">Overwatch rocks</content>
-    <link rel="alternate" type="text/html" href="https://overwatch.com/users/tracer/updates/1" />
-  </activity:object>
-XML
-
-    created_statuses = subject.call(body, actor)
-
-    expect(created_statuses).to eq []
-  end
-
-  it 'ignores statuses with an out-of-order delete' do
-    sender = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')
-
-    delete_body = <<XML
-<?xml version="1.0"?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-  <id>tag:overwatch.com,2017-04-27:objectId=4487555:objectType=Status</id>
-  <published>2017-04-27T13:49:25Z</published>
-  <updated>2017-04-27T13:49:25Z</updated>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-  <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>
-  <author>
-    <id>https://overwatch.com/users/tracer</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-    <uri>https://overwatch.com/users/tracer</uri>
-    <name>tracer</name>
-  </author>
-</entry>
-XML
-
-    status_body = <<XML
-<?xml version="1.0"?>
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
-  <id>tag:overwatch.com,2017-04-27:objectId=4487555:objectType=Status</id>
-  <published>2017-04-27T13:49:25Z</published>
-  <updated>2017-04-27T13:49:25Z</updated>
-  <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
-  <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-  <author>
-    <id>https://overwatch.com/users/tracer</id>
-    <activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
-    <uri>https://overwatch.com/users/tracer</uri>
-    <name>tracer</name>
-  </author>
-  <content type="html">Overwatch rocks</content>
-</entry>
-XML
-
-    subject.call(delete_body, sender)
-    created_statuses = subject.call(status_body, sender)
-
-    expect(created_statuses).to be_empty
-  end
-end
diff --git a/spec/services/process_interaction_service_spec.rb b/spec/services/process_interaction_service_spec.rb
deleted file mode 100644
index b858c19d0..000000000
--- a/spec/services/process_interaction_service_spec.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe ProcessInteractionService, type: :service do
-  let(:receiver) { Fabricate(:user, email: 'alice@example.com', account: Fabricate(:account, username: 'alice')).account }
-  let(:sender)   { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
-  let(:remote_sender) { Fabricate(:account, username: 'carol', domain: 'localdomain.com', uri: 'https://webdomain.com/users/carol') }
-
-  subject { ProcessInteractionService.new }
-
-  describe 'status delete slap' do
-    let(:remote_status) { Fabricate(:status, account: remote_sender) }
-    let(:envelope) { OStatus2::Salmon.new.pack(payload, sender.keypair) }
-    let(:payload) {
-      <<~XML
-        <entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-          <author>
-            <email>carol@localdomain.com</email>
-            <name>carol</name>
-            <uri>https://webdomain.com/users/carol</uri>
-          </author>
-
-          <id>#{remote_status.id}</id>
-          <activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>
-        </entry>
-      XML
-    }
-
-    before do
-      receiver.update(locked: true)
-      remote_sender.update(private_key: sender.private_key, public_key: remote_sender.public_key)
-    end
-
-    it 'deletes a record' do
-      expect(RemovalWorker).to receive(:perform_async).with(remote_status.id)
-      subject.call(envelope, receiver)
-    end
-  end
-
-  describe 'follow request slap' do
-    before do
-      receiver.update(locked: true)
-
-      payload = <<XML
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-  <author>
-    <name>bob</name>
-    <uri>https://cb6e6126.ngrok.io/users/bob</uri>
-  </author>
-
-  <id>someIdHere</id>
-  <activity:verb>http://activitystrea.ms/schema/1.0/request-friend</activity:verb>
-</entry>
-XML
-
-      envelope = OStatus2::Salmon.new.pack(payload, sender.keypair)
-      subject.call(envelope, receiver)
-    end
-
-    it 'creates a record' do
-      expect(FollowRequest.find_by(account: sender, target_account: receiver)).to_not be_nil
-    end
-  end
-
-  describe 'follow request slap from known remote user identified by email' do
-    before do
-      receiver.update(locked: true)
-      # Copy already-generated key
-      remote_sender.update(private_key: sender.private_key, public_key: remote_sender.public_key)
-
-      payload = <<XML
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-  <author>
-    <email>carol@localdomain.com</email>
-    <name>carol</name>
-    <uri>https://webdomain.com/users/carol</uri>
-  </author>
-
-  <id>someIdHere</id>
-  <activity:verb>http://activitystrea.ms/schema/1.0/request-friend</activity:verb>
-</entry>
-XML
-
-      envelope = OStatus2::Salmon.new.pack(payload, remote_sender.keypair)
-      subject.call(envelope, receiver)
-    end
-
-    it 'creates a record' do
-      expect(FollowRequest.find_by(account: remote_sender, target_account: receiver)).to_not be_nil
-    end
-  end
-
-  describe 'follow request authorization slap' do
-    before do
-      receiver.update(locked: true)
-      FollowRequest.create(account: sender, target_account: receiver)
-
-      payload = <<XML
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-  <author>
-    <name>alice</name>
-    <uri>https://cb6e6126.ngrok.io/users/alice</uri>
-  </author>
-
-  <id>someIdHere</id>
-  <activity:verb>http://activitystrea.ms/schema/1.0/authorize</activity:verb>
-</entry>
-XML
-
-      envelope = OStatus2::Salmon.new.pack(payload, receiver.keypair)
-      subject.call(envelope, sender)
-    end
-
-    it 'creates a follow relationship' do
-      expect(Follow.find_by(account: sender, target_account: receiver)).to_not be_nil
-    end
-
-    it 'removes the follow request' do
-      expect(FollowRequest.find_by(account: sender, target_account: receiver)).to be_nil
-    end
-  end
-
-  describe 'follow request rejection slap' do
-    before do
-      receiver.update(locked: true)
-      FollowRequest.create(account: sender, target_account: receiver)
-
-      payload = <<XML
-<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
-  <author>
-    <name>alice</name>
-    <uri>https://cb6e6126.ngrok.io/users/alice</uri>
-  </author>
-
-  <id>someIdHere</id>
-  <activity:verb>http://activitystrea.ms/schema/1.0/reject</activity:verb>
-</entry>
-XML
-
-      envelope = OStatus2::Salmon.new.pack(payload, receiver.keypair)
-      subject.call(envelope, sender)
-    end
-
-    it 'does not create a follow relationship' do
-      expect(Follow.find_by(account: sender, target_account: receiver)).to be_nil
-    end
-
-    it 'removes the follow request' do
-      expect(FollowRequest.find_by(account: sender, target_account: receiver)).to be_nil
-    end
-  end
-end
diff --git a/spec/services/process_mentions_service_spec.rb b/spec/services/process_mentions_service_spec.rb
index 8a6bb44ac..2192a8fa2 100644
--- a/spec/services/process_mentions_service_spec.rb
+++ b/spec/services/process_mentions_service_spec.rb
@@ -5,45 +5,6 @@ RSpec.describe ProcessMentionsService, type: :service do
   let(:visibility) { :public }
   let(:status)     { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct}", visibility: visibility) }
 
-  context 'OStatus with public toot' do
-    let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') }
-
-    subject { ProcessMentionsService.new }
-
-    before do
-      stub_request(:post, remote_user.salmon_url)
-      subject.call(status)
-    end
-
-    it 'creates a mention' do
-      expect(remote_user.mentions.where(status: status).count).to eq 1
-    end
-
-    it 'posts to remote user\'s Salmon end point' do
-      expect(a_request(:post, remote_user.salmon_url)).to have_been_made.once
-    end
-  end
-
-  context 'OStatus with private toot' do
-    let(:visibility)  { :private }
-    let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') }
-
-    subject { ProcessMentionsService.new }
-
-    before do
-      stub_request(:post, remote_user.salmon_url)
-      subject.call(status)
-    end
-
-    it 'does not create a mention' do
-      expect(remote_user.mentions.where(status: status).count).to eq 0
-    end
-
-    it 'does not post to remote user\'s Salmon end point' do
-      expect(a_request(:post, remote_user.salmon_url)).to_not have_been_made
-    end
-  end
-
   context 'ActivityPub' do
     let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
 
diff --git a/spec/services/reblog_service_spec.rb b/spec/services/reblog_service_spec.rb
index 9d84c41d5..e2077f282 100644
--- a/spec/services/reblog_service_spec.rb
+++ b/spec/services/reblog_service_spec.rb
@@ -32,26 +32,6 @@ RSpec.describe ReblogService, type: :service do
     end
   end
 
-  context 'OStatus' do
-    let(:bob)    { Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com') }
-    let(:status) { Fabricate(:status, account: bob, uri: 'tag:example.com;something:something') }
-
-    subject { ReblogService.new }
-
-    before do
-      stub_request(:post, 'http://salmon.example.com')
-      subject.call(alice, status)
-    end
-
-    it 'creates a reblog' do
-      expect(status.reblogs.count).to eq 1
-    end
-
-    it 'sends a Salmon slap for a remote reblog' do
-      expect(a_request(:post, 'http://salmon.example.com')).to have_been_made
-    end
-  end
-
   context 'ActivityPub' do
     let(:bob)    { Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
     let(:status) { Fabricate(:status, account: bob) }
diff --git a/spec/services/reject_follow_service_spec.rb b/spec/services/reject_follow_service_spec.rb
index e5ac37ed9..732cb07f7 100644
--- a/spec/services/reject_follow_service_spec.rb
+++ b/spec/services/reject_follow_service_spec.rb
@@ -22,31 +22,6 @@ RSpec.describe RejectFollowService, type: :service do
     end
   end
 
-  describe 'remote OStatus' do
-    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }
-
-    before do
-      FollowRequest.create(account: bob, target_account: sender)
-      stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
-      subject.call(bob, sender)
-    end
-
-    it 'removes follow request' do
-      expect(bob.requested?(sender)).to be false
-    end
-
-    it 'does not create follow relation' do
-      expect(bob.following?(sender)).to be false
-    end
-
-    it 'sends a follow request rejection salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:reject])
-      }).to have_been_made.once
-    end
-  end
-
   describe 'remote ActivityPub' do
     let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox')).account }
 
diff --git a/spec/services/remove_status_service_spec.rb b/spec/services/remove_status_service_spec.rb
index 7bba83a60..edfefaabc 100644
--- a/spec/services/remove_status_service_spec.rb
+++ b/spec/services/remove_status_service_spec.rb
@@ -4,18 +4,14 @@ RSpec.describe RemoveStatusService, type: :service do
   subject { RemoveStatusService.new }
 
   let!(:alice)  { Fabricate(:account) }
-  let!(:bob)    { Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://example.com/salmon') }
   let!(:jeff)   { Fabricate(:account) }
   let!(:hank)   { Fabricate(:account, username: 'hank', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
   let!(:bill)   { Fabricate(:account, username: 'bill', protocol: :activitypub, domain: 'example2.com', inbox_url: 'http://example2.com/inbox') }
 
   before do
-    stub_request(:post, 'http://example.com/push').to_return(status: 200, body: '', headers: {})
-    stub_request(:post, 'http://example.com/salmon').to_return(status: 200, body: '', headers: {})
     stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
     stub_request(:post, 'http://example2.com/inbox').to_return(status: 200)
 
-    Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)
     jeff.follow!(alice)
     hank.follow!(alice)
 
@@ -32,23 +28,10 @@ RSpec.describe RemoveStatusService, type: :service do
     expect(HomeFeed.new(jeff).get(10)).to_not include(@status.id)
   end
 
-  it 'sends PuSH update to PuSH subscribers' do
-    expect(a_request(:post, 'http://example.com/push').with { |req|
-      req.body.match(OStatus::TagManager::VERBS[:delete])
-    }).to have_been_made
-  end
-
   it 'sends delete activity to followers' do
     expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.twice
   end
 
-  it 'sends Salmon slap to previously mentioned users' do
-    expect(a_request(:post, "http://example.com/salmon").with { |req|
-      xml = OStatus2::Salmon.new.unpack(req.body)
-      xml.match(OStatus::TagManager::VERBS[:delete])
-    }).to have_been_made.once
-  end
-
   it 'sends delete activity to rebloggers' do
     expect(a_request(:post, 'http://example2.com/inbox')).to have_been_made
   end
diff --git a/spec/services/resolve_account_service_spec.rb b/spec/services/resolve_account_service_spec.rb
index 27a85af7c..105ff6943 100644
--- a/spec/services/resolve_account_service_spec.rb
+++ b/spec/services/resolve_account_service_spec.rb
@@ -38,39 +38,6 @@ RSpec.describe ResolveAccountService, type: :service do
     expect(subject.call('hacker2@redirected.com')).to be_nil
   end
 
-  context 'with an OStatus account' do
-    it 'returns an already existing remote account' do
-      old_account      = Fabricate(:account, username: 'gargron', domain: 'quitter.no')
-      returned_account = subject.call('gargron@quitter.no')
-
-      expect(old_account.id).to eq returned_account.id
-    end
-
-    it 'returns a new remote account' do
-      account = subject.call('gargron@quitter.no')
-
-      expect(account.username).to eq 'gargron'
-      expect(account.domain).to eq 'quitter.no'
-      expect(account.remote_url).to eq 'https://quitter.no/api/statuses/user_timeline/7477.atom'
-    end
-
-    it 'follows a legitimate account redirection' do
-      account = subject.call('gargron@redirected.com')
-
-      expect(account.username).to eq 'gargron'
-      expect(account.domain).to eq 'quitter.no'
-      expect(account.remote_url).to eq 'https://quitter.no/api/statuses/user_timeline/7477.atom'
-    end
-
-    it 'returns a new remote account' do
-      account = subject.call('foo@localdomain.com')
-
-      expect(account.username).to eq 'foo'
-      expect(account.domain).to eq 'localdomain.com'
-      expect(account.remote_url).to eq 'https://webdomain.com/users/foo.atom'
-    end
-  end
-
   context 'with an ActivityPub account' do
     before do
       stub_request(:get, "https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com").to_return(request_fixture('activitypub-webfinger.txt'))
@@ -79,24 +46,6 @@ RSpec.describe ResolveAccountService, type: :service do
       stub_request(:get, %r{https://ap.example.com/users/foo/\w+}).to_return(status: 404)
     end
 
-    it 'fallback to OStatus if actor json could not be fetched' do
-      stub_request(:get, "https://ap.example.com/users/foo").to_return(status: 404)
-
-      account = subject.call('foo@ap.example.com')
-
-      expect(account.ostatus?).to eq true
-      expect(account.remote_url).to eq 'https://ap.example.com/users/foo.atom'
-    end
-
-    it 'fallback to OStatus if actor json did not have inbox_url' do
-      stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor-noinbox.txt'))
-
-      account = subject.call('foo@ap.example.com')
-
-      expect(account.ostatus?).to eq true
-      expect(account.remote_url).to eq 'https://ap.example.com/users/foo.atom'
-    end
-
     it 'returns new remote account' do
       account = subject.call('foo@ap.example.com')
 
diff --git a/spec/services/send_interaction_service_spec.rb b/spec/services/send_interaction_service_spec.rb
deleted file mode 100644
index 710d8184c..000000000
--- a/spec/services/send_interaction_service_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe SendInteractionService, type: :service do
-  subject { SendInteractionService.new }
-
-  it 'sends an XML envelope to the Salmon end point of remote user'
-end
diff --git a/spec/services/unblock_service_spec.rb b/spec/services/unblock_service_spec.rb
index 5835b912b..c43ab24b0 100644
--- a/spec/services/unblock_service_spec.rb
+++ b/spec/services/unblock_service_spec.rb
@@ -18,27 +18,6 @@ RSpec.describe UnblockService, type: :service do
     end
   end
 
-  describe 'remote OStatus' do
-    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }
-
-    before do
-      sender.block!(bob)
-      stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
-      subject.call(sender, bob)
-    end
-
-    it 'destroys the blocking relation' do
-      expect(sender.blocking?(bob)).to be false
-    end
-
-    it 'sends an unblock salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:unblock])
-      }).to have_been_made.once
-    end
-  end
-
   describe 'remote ActivityPub' do
     let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }
 
diff --git a/spec/services/unfollow_service_spec.rb b/spec/services/unfollow_service_spec.rb
index 8a2881ab1..7f0b575e4 100644
--- a/spec/services/unfollow_service_spec.rb
+++ b/spec/services/unfollow_service_spec.rb
@@ -18,27 +18,6 @@ RSpec.describe UnfollowService, type: :service do
     end
   end
 
-  describe 'remote OStatus' do
-    let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }
-
-    before do
-      sender.follow!(bob)
-      stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
-      subject.call(sender, bob)
-    end
-
-    it 'destroys the following relation' do
-      expect(sender.following?(bob)).to be false
-    end
-
-    it 'sends an unfollow salmon slap' do
-      expect(a_request(:post, "http://salmon.example.com/").with { |req|
-        xml = OStatus2::Salmon.new.unpack(req.body)
-        xml.match(OStatus::TagManager::VERBS[:unfollow])
-      }).to have_been_made.once
-    end
-  end
-
   describe 'remote ActivityPub' do
     let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox')).account }
 
diff --git a/spec/services/update_remote_profile_service_spec.rb b/spec/services/update_remote_profile_service_spec.rb
deleted file mode 100644
index f3ea70b80..000000000
--- a/spec/services/update_remote_profile_service_spec.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe UpdateRemoteProfileService, type: :service do
-  let(:xml) { File.read(Rails.root.join('spec', 'fixtures', 'push', 'feed.atom')) }
-
-  subject { UpdateRemoteProfileService.new }
-
-  before do
-    stub_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png').to_return(request_fixture('avatar.txt'))
-  end
-
-  context 'with updated details' do
-    let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com') }
-
-    before do
-      subject.call(xml, remote_account)
-    end
-
-    it 'downloads new avatar' do
-      expect(a_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png')).to have_been_made
-    end
-
-    it 'sets the avatar remote url' do
-      expect(remote_account.reload.avatar_remote_url).to eq 'https://quitter.no/avatar/7477-300-20160211190340.png'
-    end
-
-    it 'sets display name' do
-      expect(remote_account.reload.display_name).to eq 'DIGITAL CAT'
-    end
-
-    it 'sets note' do
-      expect(remote_account.reload.note).to eq 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes'
-    end
-  end
-
-  context 'with unchanged details' do
-    let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com', display_name: 'DIGITAL CAT', note: 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes', avatar_remote_url: 'https://quitter.no/avatar/7477-300-20160211190340.png') }
-
-    before do
-      subject.call(xml, remote_account)
-    end
-
-    it 'does not re-download avatar' do
-      expect(a_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png')).to have_been_made.once
-    end
-
-    it 'sets the avatar remote url' do
-      expect(remote_account.reload.avatar_remote_url).to eq 'https://quitter.no/avatar/7477-300-20160211190340.png'
-    end
-
-    it 'sets display name' do
-      expect(remote_account.reload.display_name).to eq 'DIGITAL CAT'
-    end
-
-    it 'sets note' do
-      expect(remote_account.reload.note).to eq 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes'
-    end
-  end
-
-  context 'with updated details from a domain set to reject media' do
-    let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com') }
-    let!(:domain_block) { Fabricate(:domain_block, domain: 'example.com', reject_media: true) }
-
-    before do
-      subject.call(xml, remote_account)
-    end
-
-    it 'does not the avatar remote url' do
-      expect(remote_account.reload.avatar_remote_url).to be_nil
-    end
-
-    it 'sets display name' do
-      expect(remote_account.reload.display_name).to eq 'DIGITAL CAT'
-    end
-
-    it 'sets note' do
-      expect(remote_account.reload.note).to eq 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes'
-    end
-
-    it 'does not set store the avatar' do
-      expect(remote_account.reload.avatar_file_name).to be_nil
-    end
-  end
-end
diff --git a/spec/workers/pubsubhubbub/confirmation_worker_spec.rb b/spec/workers/pubsubhubbub/confirmation_worker_spec.rb
deleted file mode 100644
index 1eecdd2b5..000000000
--- a/spec/workers/pubsubhubbub/confirmation_worker_spec.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-describe Pubsubhubbub::ConfirmationWorker do
-  include RoutingHelper
-
-  subject { described_class.new }
-
-  let!(:alice) { Fabricate(:account, username: 'alice') }
-  let!(:subscription) { Fabricate(:subscription, account: alice, callback_url: 'http://example.com/api', confirmed: false, expires_at: 3.days.from_now, secret: nil) }
-
-  describe 'perform' do
-    describe 'with subscribe mode' do
-      it 'confirms and updates subscription when challenge matches' do
-        stub_random_value
-        stub_request(:get, url_for_mode('subscribe'))
-          .with(headers: http_headers)
-          .to_return(status: 200, body: challenge_value, headers: {})
-
-        seconds = 10.days.seconds.to_i
-        subject.perform(subscription.id, 'subscribe', 'asdf', seconds)
-
-        subscription.reload
-        expect(subscription.secret).to eq 'asdf'
-        expect(subscription.confirmed).to eq true
-        expect(subscription.expires_at).to be_within(5).of(10.days.from_now)
-      end
-
-      it 'does not update subscription when challenge does not match' do
-        stub_random_value
-        stub_request(:get, url_for_mode('subscribe'))
-          .with(headers: http_headers)
-          .to_return(status: 200, body: 'wrong value', headers: {})
-
-        seconds = 10.days.seconds.to_i
-        subject.perform(subscription.id, 'subscribe', 'asdf', seconds)
-
-        subscription.reload
-        expect(subscription.secret).to be_blank
-        expect(subscription.confirmed).to eq false
-        expect(subscription.expires_at).to be_within(5).of(3.days.from_now)
-      end
-    end
-
-    describe 'with unsubscribe mode' do
-      it 'confirms and destroys subscription when challenge matches' do
-        stub_random_value
-        stub_request(:get, url_for_mode('unsubscribe'))
-          .with(headers: http_headers)
-          .to_return(status: 200, body: challenge_value, headers: {})
-
-        seconds = 10.days.seconds.to_i
-        subject.perform(subscription.id, 'unsubscribe', 'asdf', seconds)
-
-        expect { subscription.reload }.to raise_error(ActiveRecord::RecordNotFound)
-      end
-
-      it 'does not destroy subscription when challenge does not match' do
-        stub_random_value
-        stub_request(:get, url_for_mode('unsubscribe'))
-          .with(headers: http_headers)
-          .to_return(status: 200, body: 'wrong value', headers: {})
-
-        seconds = 10.days.seconds.to_i
-        subject.perform(subscription.id, 'unsubscribe', 'asdf', seconds)
-
-        expect { subscription.reload }.not_to raise_error
-      end
-    end
-  end
-
-  def url_for_mode(mode)
-    "http://example.com/api?hub.challenge=#{challenge_value}&hub.lease_seconds=863999&hub.mode=#{mode}&hub.topic=https://#{Rails.configuration.x.local_domain}/users/alice.atom"
-  end
-
-  def stub_random_value
-    allow(SecureRandom).to receive(:hex).and_return(challenge_value)
-  end
-
-  def challenge_value
-    '1a2s3d4f'
-  end
-
-  def http_headers
-    { 'Connection' => 'close', 'Host' => 'example.com' }
-  end
-end
diff --git a/spec/workers/pubsubhubbub/delivery_worker_spec.rb b/spec/workers/pubsubhubbub/delivery_worker_spec.rb
deleted file mode 100644
index c0e0d5186..000000000
--- a/spec/workers/pubsubhubbub/delivery_worker_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-# frozen_string_literal: true
-
-require 'rails_helper'
-
-describe Pubsubhubbub::DeliveryWorker do
-  include RoutingHelper
-  subject { described_class.new }
-
-  let(:payload) { 'test' }
-
-  describe 'perform' do
-    it 'raises when subscription does not exist' do
-      expect { subject.perform 123, payload }.to raise_error(ActiveRecord::RecordNotFound)
-    end
-
-    it 'does not attempt to deliver when domain blocked' do
-      _domain_block = Fabricate(:domain_block, domain: 'example.com', severity: :suspend)
-      subscription = Fabricate(:subscription, callback_url: 'https://example.com/api', last_successful_delivery_at: 2.days.ago)
-
-      subject.perform(subscription.id, payload)
-
-      expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(2.days.ago)
-    end
-
-    it 'raises when request fails' do
-      subscription = Fabricate(:subscription)
-
-      stub_request_to_respond_with(subscription, 500)
-      expect { subject.perform(subscription.id, payload) }.to raise_error Mastodon::UnexpectedResponseError
-    end
-
-    it 'updates subscriptions when delivery succeeds' do
-      subscription = Fabricate(:subscription)
-
-      stub_request_to_respond_with(subscription, 200)
-      subject.perform(subscription.id, payload)
-
-      expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(Time.now.utc)
-    end
-
-    it 'updates subscription without a secret when delivery succeeds' do
-      subscription = Fabricate(:subscription, secret: nil)
-
-      stub_request_to_respond_with(subscription, 200)
-      subject.perform(subscription.id, payload)
-
-      expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(Time.now.utc)
-    end
-
-    def stub_request_to_respond_with(subscription, code)
-      stub_request(:post, 'http://example.com/callback')
-        .with(body: payload, headers: expected_headers(subscription))
-        .to_return(status: code, body: '', headers: {})
-    end
-
-    def expected_headers(subscription)
-      {
-        'Connection' => 'close',
-        'Content-Type' => 'application/atom+xml',
-        'Host' => 'example.com',
-        'Link' => "<https://#{Rails.configuration.x.local_domain}/api/push>; rel=\"hub\", <https://#{Rails.configuration.x.local_domain}/users/#{subscription.account.username}.atom>; rel=\"self\"",
-      }.tap do |basic|
-        known_digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), subscription.secret.to_s, payload)
-        basic.merge('X-Hub-Signature' => "sha1=#{known_digest}") if subscription.secret?
-      end
-    end
-  end
-end
diff --git a/spec/workers/pubsubhubbub/distribution_worker_spec.rb b/spec/workers/pubsubhubbub/distribution_worker_spec.rb
deleted file mode 100644
index 584485079..000000000
--- a/spec/workers/pubsubhubbub/distribution_worker_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require 'rails_helper'
-
-describe Pubsubhubbub::DistributionWorker do
-  subject { Pubsubhubbub::DistributionWorker.new }
-
-  let!(:alice) { Fabricate(:account, username: 'alice') }
-  let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example2.com') }
-  let!(:anonymous_subscription) { Fabricate(:subscription, account: alice, callback_url: 'http://example1.com', confirmed: true, lease_seconds: 3600) }
-  let!(:subscription_with_follower) { Fabricate(:subscription, account: alice, callback_url: 'http://example2.com', confirmed: true, lease_seconds: 3600) }
-
-  before do
-    bob.follow!(alice)
-  end
-
-  describe 'with public status' do
-    let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :public) }
-
-    it 'delivers payload to all subscriptions' do
-      allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)
-      subject.perform(status.stream_entry.id)
-      expect(Pubsubhubbub::DeliveryWorker).to have_received(:push_bulk).with([anonymous_subscription.id, subscription_with_follower.id])
-    end
-  end
-
-  context 'when OStatus privacy is not used' do
-    describe 'with private status' do
-      let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :private) }
-
-      it 'does not deliver anything' do
-        allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)
-        subject.perform(status.stream_entry.id)
-        expect(Pubsubhubbub::DeliveryWorker).to_not have_received(:push_bulk)
-      end
-    end
-
-    describe 'with direct status' do
-      let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :direct) }
-
-      it 'does not deliver payload' do
-        allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)
-        subject.perform(status.stream_entry.id)
-        expect(Pubsubhubbub::DeliveryWorker).to_not have_received(:push_bulk)
-      end
-    end
-  end
-end
diff --git a/spec/workers/scheduler/subscriptions_scheduler_spec.rb b/spec/workers/scheduler/subscriptions_scheduler_spec.rb
deleted file mode 100644
index a7d1046de..000000000
--- a/spec/workers/scheduler/subscriptions_scheduler_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require 'rails_helper'
-
-describe Scheduler::SubscriptionsScheduler do
-  subject { Scheduler::SubscriptionsScheduler.new }
-
-  let!(:expiring_account1) { Fabricate(:account, subscription_expires_at: 20.minutes.from_now, domain: 'example.com', followers_count: 1, hub_url: 'http://hub.example.com') }
-  let!(:expiring_account2) { Fabricate(:account, subscription_expires_at: 4.hours.from_now, domain: 'example.org', followers_count: 1, hub_url: 'http://hub.example.org') }
-
-  before do
-    stub_request(:post, 'http://hub.example.com/').to_return(status: 202)
-    stub_request(:post, 'http://hub.example.org/').to_return(status: 202)
-  end
-
-  it 're-subscribes for all expiring accounts' do
-    subject.perform
-    expect(a_request(:post, 'http://hub.example.com/')).to have_been_made.once
-    expect(a_request(:post, 'http://hub.example.org/')).to have_been_made.once
-  end
-end