suspend_account_service.rb 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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. follows = Follow.where(account: @account).to_a
  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. def distribute_update_actor!
  33. return unless @account.local?
  34. account_reach_finder = AccountReachFinder.new(@account)
  35. ActivityPub::DeliveryWorker.push_bulk(account_reach_finder.inboxes) do |inbox_url|
  36. [signed_activity_json, @account.id, inbox_url]
  37. end
  38. end
  39. def unmerge_from_home_timelines!
  40. @account.followers_for_local_distribution.find_each do |follower|
  41. FeedManager.instance.unmerge_from_home(@account, follower)
  42. end
  43. end
  44. def unmerge_from_list_timelines!
  45. @account.lists_for_local_distribution.find_each do |list|
  46. FeedManager.instance.unmerge_from_list(@account, list)
  47. end
  48. end
  49. def privatize_media_attachments!
  50. attachment_names = MediaAttachment.attachment_definitions.keys
  51. @account.media_attachments.find_each do |media_attachment|
  52. attachment_names.each do |attachment_name|
  53. attachment = media_attachment.public_send(attachment_name)
  54. styles = [:original] | attachment.styles.keys
  55. next if attachment.blank?
  56. styles.each do |style|
  57. case Paperclip::Attachment.default_options[:storage]
  58. when :s3
  59. # Prevent useless S3 calls if ACLs are disabled
  60. next if ENV['S3_PERMISSION'] == ''
  61. begin
  62. attachment.s3_object(style).acl.put(acl: 'private')
  63. rescue Aws::S3::Errors::NoSuchKey
  64. Rails.logger.warn "Tried to change acl on non-existent key #{attachment.s3_object(style).key}"
  65. rescue Aws::S3::Errors::NotImplemented => e
  66. Rails.logger.error "Error trying to change ACL on #{attachment.s3_object(style).key}: #{e.message}"
  67. end
  68. when :fog
  69. # Not supported
  70. when :filesystem
  71. begin
  72. FileUtils.chmod(0o600 & ~File.umask, attachment.path(style)) unless attachment.path(style).nil?
  73. rescue Errno::ENOENT
  74. Rails.logger.warn "Tried to change permission on non-existent file #{attachment.path(style)}"
  75. end
  76. end
  77. CacheBusterWorker.perform_async(attachment.path(style)) if Rails.configuration.x.cache_buster_enabled
  78. end
  79. end
  80. end
  81. end
  82. def signed_activity_json
  83. @signed_activity_json ||= Oj.dump(serialize_payload(@account, ActivityPub::UpdateSerializer, signer: @account))
  84. end
  85. end