require_relative 'mastodon/accounts_cli'
require_relative 'mastodon/feeds_cli'
require_relative 'mastodon/settings_cli'
+require_relative 'mastodon/domains_cli'
module Mastodon
class CLI < Thor
desc 'settings SUBCOMMAND ...ARGS', 'Manage dynamic settings'
subcommand 'settings', Mastodon::SettingsCLI
+
+ desc 'domains SUBCOMMAND ...ARGS', 'Manage account domains'
+ subcommand 'domains', Mastodon::DomainsCLI
end
end
# frozen_string_literal: true
-require 'rubygems/package'
+require 'set'
require_relative '../../config/boot'
require_relative '../../config/environment'
require_relative 'cli_helper'
def self.exit_on_failure?
true
end
+
option :all, type: :boolean
desc 'rotate [USERNAME]', 'Generate and broadcast new keys'
long_desc <<-LONG_DESC
Accounts that have had confirmed activity within the last week
are excluded from the checks.
- If 10 or more accounts from the same domain cannot be queried
- due to a connection error (such as missing DNS records) then
- the domain is considered dead, and all other accounts from it
- are deleted without further querying.
+ Domains that are unreachable are not checked.
With the --dry-run option, no deletes will actually be carried
out.
LONG_DESC
def cull
- domain_thresholds = Hash.new { |hash, key| hash[key] = 0 }
- skip_threshold = 7.days.ago
- culled = 0
- dead_servers = []
- dry_run = options[:dry_run] ? ' (DRY RUN)' : ''
+ skip_threshold = 7.days.ago
+ culled = 0
+ skip_domains = Set.new
+ dry_run = options[:dry_run] ? ' (DRY RUN)' : ''
Account.remote.where(protocol: :activitypub).partitioned.find_each do |account|
next if account.updated_at >= skip_threshold || (account.last_webfingered_at.present? && account.last_webfingered_at >= skip_threshold)
- unless dead_servers.include?(account.domain)
+ unless skip_domains.include?(account.domain)
begin
code = Request.new(:head, account.uri).perform(&:code)
rescue HTTP::ConnectionError
- domain_thresholds[account.domain] += 1
-
- if domain_thresholds[account.domain] >= 10
- dead_servers << account.domain
- end
+ skip_domains << account.domain
rescue StandardError
next
end
end
end
- # Remove dead servers
- unless dead_servers.empty? || options[:dry_run]
- dead_servers.each do |domain|
- Account.where(domain: domain).find_each do |account|
- SuspendAccountService.new.call(account)
- account.destroy
- culled += 1
- say('.', :green, false)
- end
- end
- end
-
say
- say("Removed #{culled} accounts (#{dead_servers.size} dead servers)#{dry_run}", :green)
+ say("Removed #{culled} accounts. #{skip_domains.size} servers skipped#{dry_run}", skip_domains.empty? ? :green : :yellow)
- unless dead_servers.empty?
- say('R.I.P.:', :yellow)
- dead_servers.each { |domain| say(' ' + domain) }
+ unless skip_domains.empty?
+ say('The following servers were not available during the check:', :yellow)
+ skip_domains.each { |domain| say(' ' + domain) }
end
end
--- /dev/null
+# frozen_string_literal: true
+
+require_relative '../../config/boot'
+require_relative '../../config/environment'
+require_relative 'cli_helper'
+
+module Mastodon
+ class DomainsCLI < Thor
+ def self.exit_on_failure?
+ true
+ end
+
+ option :dry_run, type: :boolean
+ desc 'purge DOMAIN', 'Remove accounts from a DOMAIN without a trace'
+ long_desc <<-LONG_DESC
+ Remove all accounts from a given DOMAIN without leaving behind any
+ records. Unlike a suspension, if the DOMAIN still exists in the wild,
+ it means the accounts could return if they are resolved again.
+ LONG_DESC
+ def purge(domain)
+ removed = 0
+ dry_run = options[:dry_run] ? ' (DRY RUN)' : ''
+
+ Account.where(domain: domain).find_each do |account|
+ unless options[:dry_run]
+ SuspendAccountService.new.call(account)
+ account.destroy
+ end
+
+ removed += 1
+ say('.', :green, false)
+ end
+
+ DomainBlock.where(domain: domain).destroy_all
+
+ say
+ say("Removed #{removed} accounts#{dry_run}", :green)
+ end
+ end
+end
def self.exit_on_failure?
true
end
+
option :all, type: :boolean, default: false
option :background, type: :boolean, default: false
option :dry_run, type: :boolean, default: false
account = Account.find_local(username)
if account.nil?
- say("Account #{username} is not found", :red)
+ say('No such account', :red)
exit(1)
end