cli.rb 4.6 KB

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