You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
3.7 KiB

  1. # frozen_string_literal: true
  2. class SuspendAccountService < BaseService
  3. include Payloadable
  4. # Carry out the suspension of a recently-suspended account
  5. # @param [Account] account Account to suspend
  6. def call(account)
  7. return unless account.suspended?
  8. @account = account
  9. reject_remote_follows!
  10. distribute_update_actor!
  11. unmerge_from_home_timelines!
  12. unmerge_from_list_timelines!
  13. privatize_media_attachments!
  14. end
  15. private
  16. def reject_remote_follows!
  17. return if @account.local? || !@account.activitypub?
  18. # When suspending a remote account, the account obviously doesn't
  19. # actually become suspended on its origin server, i.e. unlike a
  20. # locally suspended account it continues to have access to its home
  21. # feed and other content. To prevent it from being able to continue
  22. # to access toots it would receive because it follows local accounts,
  23. # we have to force it to unfollow them. Unfortunately, there is no
  24. # counterpart to this operation, i.e. you can't then force a remote
  25. # account to re-follow you, so this part is not reversible.
  26. Follow.where(account: @account).find_in_batches do |follows|
  27. ActivityPub::DeliveryWorker.push_bulk(follows) do |follow|
  28. [Oj.dump(serialize_payload(follow, ActivityPub::RejectFollowSerializer)), follow.target_account_id, @account.inbox_url]
  29. end
  30. follows.each(&:destroy)
  31. end
  32. end
  33. def distribute_update_actor!
  34. return unless @account.local?
  35. account_reach_finder = AccountReachFinder.new(@account)
  36. ActivityPub::DeliveryWorker.push_bulk(account_reach_finder.inboxes, limit: 1_000) do |inbox_url|
  37. [signed_activity_json, @account.id, inbox_url]
  38. end
  39. end
  40. def unmerge_from_home_timelines!
  41. @account.followers_for_local_distribution.find_each do |follower|
  42. FeedManager.instance.unmerge_from_home(@account, follower)
  43. end
  44. end
  45. def unmerge_from_list_timelines!
  46. @account.lists_for_local_distribution.find_each do |list|
  47. FeedManager.instance.unmerge_from_list(@account, list)
  48. end
  49. end
  50. def privatize_media_attachments!
  51. attachment_names = MediaAttachment.attachment_definitions.keys
  52. @account.media_attachments.find_each do |media_attachment|
  53. attachment_names.each do |attachment_name|
  54. attachment = media_attachment.public_send(attachment_name)
  55. styles = [:original] | attachment.styles.keys
  56. next if attachment.blank?
  57. styles.each do |style|
  58. case Paperclip::Attachment.default_options[:storage]
  59. when :s3
  60. # Prevent useless S3 calls if ACLs are disabled
  61. next if ENV['S3_PERMISSION'] == ''
  62. begin
  63. attachment.s3_object(style).acl.put(acl: 'private')
  64. rescue Aws::S3::Errors::NoSuchKey
  65. Rails.logger.warn "Tried to change acl on non-existent key #{attachment.s3_object(style).key}"
  66. rescue Aws::S3::Errors::NotImplemented => e
  67. Rails.logger.error "Error trying to change ACL on #{attachment.s3_object(style).key}: #{e.message}"
  68. end
  69. when :fog
  70. # Not supported
  71. when :filesystem
  72. begin
  73. FileUtils.chmod(0o600 & ~File.umask, attachment.path(style)) unless attachment.path(style).nil?
  74. rescue Errno::ENOENT
  75. Rails.logger.warn "Tried to change permission on non-existent file #{attachment.path(style)}"
  76. end
  77. end
  78. CacheBusterWorker.perform_async(attachment.path(style)) if Rails.configuration.x.cache_buster_enabled
  79. end
  80. end
  81. end
  82. end
  83. def signed_activity_json
  84. @signed_activity_json ||= Oj.dump(serialize_payload(@account, ActivityPub::UpdateSerializer, signer: @account))
  85. end
  86. end