cli.rb 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. # frozen_string_literal: true
  2. require 'thor'
  3. require_relative 'mastodon/media_cli'
  4. require_relative 'mastodon/emoji_cli'
  5. require_relative 'mastodon/accounts_cli'
  6. require_relative 'mastodon/feeds_cli'
  7. require_relative 'mastodon/search_cli'
  8. require_relative 'mastodon/settings_cli'
  9. require_relative 'mastodon/statuses_cli'
  10. require_relative 'mastodon/domains_cli'
  11. require_relative 'mastodon/preview_cards_cli'
  12. require_relative 'mastodon/cache_cli'
  13. require_relative 'mastodon/upgrade_cli'
  14. require_relative 'mastodon/email_domain_blocks_cli'
  15. require_relative 'mastodon/ip_blocks_cli'
  16. require_relative 'mastodon/maintenance_cli'
  17. require_relative 'mastodon/version'
  18. module Mastodon
  19. class CLI < Thor
  20. def self.exit_on_failure?
  21. true
  22. end
  23. desc 'media SUBCOMMAND ...ARGS', 'Manage media files'
  24. subcommand 'media', Mastodon::MediaCLI
  25. desc 'emoji SUBCOMMAND ...ARGS', 'Manage custom emoji'
  26. subcommand 'emoji', Mastodon::EmojiCLI
  27. desc 'accounts SUBCOMMAND ...ARGS', 'Manage accounts'
  28. subcommand 'accounts', Mastodon::AccountsCLI
  29. desc 'feeds SUBCOMMAND ...ARGS', 'Manage feeds'
  30. subcommand 'feeds', Mastodon::FeedsCLI
  31. desc 'search SUBCOMMAND ...ARGS', 'Manage the search engine'
  32. subcommand 'search', Mastodon::SearchCLI
  33. desc 'settings SUBCOMMAND ...ARGS', 'Manage dynamic settings'
  34. subcommand 'settings', Mastodon::SettingsCLI
  35. desc 'statuses SUBCOMMAND ...ARGS', 'Manage statuses'
  36. subcommand 'statuses', Mastodon::StatusesCLI
  37. desc 'domains SUBCOMMAND ...ARGS', 'Manage account domains'
  38. subcommand 'domains', Mastodon::DomainsCLI
  39. desc 'preview_cards SUBCOMMAND ...ARGS', 'Manage preview cards'
  40. subcommand 'preview_cards', Mastodon::PreviewCardsCLI
  41. desc 'cache SUBCOMMAND ...ARGS', 'Manage cache'
  42. subcommand 'cache', Mastodon::CacheCLI
  43. desc 'upgrade SUBCOMMAND ...ARGS', 'Various version upgrade utilities'
  44. subcommand 'upgrade', Mastodon::UpgradeCLI
  45. desc 'email_domain_blocks SUBCOMMAND ...ARGS', 'Manage e-mail domain blocks'
  46. subcommand 'email_domain_blocks', Mastodon::EmailDomainBlocksCLI
  47. desc 'ip_blocks SUBCOMMAND ...ARGS', 'Manage IP blocks'
  48. subcommand 'ip_blocks', Mastodon::IpBlocksCLI
  49. desc 'maintenance SUBCOMMAND ...ARGS', 'Various maintenance utilities'
  50. subcommand 'maintenance', Mastodon::MaintenanceCLI
  51. option :dry_run, type: :boolean
  52. desc 'self-destruct', 'Erase the server from the federation'
  53. long_desc <<~LONG_DESC
  54. Erase the server from the federation by broadcasting account delete
  55. activities to all known other servers. This allows a "clean exit" from
  56. running a Mastodon server, as it leaves next to no cache behind on
  57. other servers.
  58. This command is always interactive and requires confirmation twice.
  59. No local data is actually deleted, because emptying the
  60. database or removing files is much faster through other, external
  61. means, such as e.g. deleting the entire VPS. However, because other
  62. servers will delete data about local users, but no local data will be
  63. updated (such as e.g. followers), there will be a state mismatch
  64. that will lead to glitches and issues if you then continue to run and use
  65. the server.
  66. So either you know exactly what you are doing, or you are starting
  67. from a blank slate afterwards by manually clearing out all the local
  68. data!
  69. LONG_DESC
  70. def self_destruct
  71. require 'tty-prompt'
  72. prompt = TTY::Prompt.new
  73. exit(1) unless prompt.ask('Type in the domain of the server to confirm:', required: true) == Rails.configuration.x.local_domain
  74. unless options[:dry_run]
  75. prompt.warn('This operation WILL NOT be reversible. It can also take a long time.')
  76. prompt.warn('While the data won\'t be erased locally, the server will be in a BROKEN STATE afterwards.')
  77. prompt.warn('A running Sidekiq process is required. Do not shut it down until queues clear.')
  78. exit(1) if prompt.no?('Are you sure you want to proceed?')
  79. end
  80. inboxes = Account.inboxes
  81. processed = 0
  82. dry_run = options[:dry_run] ? ' (DRY RUN)' : ''
  83. Setting.registrations_mode = 'none' unless options[:dry_run]
  84. if inboxes.empty?
  85. Account.local.without_suspended.in_batches.update_all(suspended_at: Time.now.utc, suspension_origin: :local) unless options[:dry_run]
  86. prompt.ok('It seems like your server has not federated with anything')
  87. prompt.ok('You can shut it down and delete it any time')
  88. return
  89. end
  90. prompt.warn('Do NOT interrupt this process...')
  91. delete_account = ->(account) do
  92. payload = ActiveModelSerializers::SerializableResource.new(
  93. account,
  94. serializer: ActivityPub::DeleteActorSerializer,
  95. adapter: ActivityPub::Adapter
  96. ).as_json
  97. json = Oj.dump(ActivityPub::LinkedDataSignature.new(payload).sign!(account))
  98. unless options[:dry_run]
  99. ActivityPub::DeliveryWorker.push_bulk(inboxes) do |inbox_url|
  100. [json, account.id, inbox_url]
  101. end
  102. account.suspend!(block_email: false)
  103. end
  104. processed += 1
  105. end
  106. Account.local.without_suspended.find_each { |account| delete_account.call(account) }
  107. Account.local.suspended.joins(:deletion_request).find_each { |account| delete_account.call(account) }
  108. prompt.ok("Queued #{inboxes.size * processed} items into Sidekiq for #{processed} accounts#{dry_run}")
  109. prompt.ok('Wait until Sidekiq processes all items, then you can shut everything down and delete the data')
  110. rescue TTY::Reader::InputInterrupt
  111. exit(1)
  112. end
  113. map %w(--version -v) => :version
  114. desc 'version', 'Show version'
  115. def version
  116. say(Mastodon::Version.to_s)
  117. end
  118. end
  119. end