email_domain_blocks_cli.rb 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. # frozen_string_literal: true
  2. require 'concurrent'
  3. require_relative '../../config/boot'
  4. require_relative '../../config/environment'
  5. require_relative 'cli_helper'
  6. module Mastodon
  7. class EmailDomainBlocksCLI < Thor
  8. include CLIHelper
  9. def self.exit_on_failure?
  10. true
  11. end
  12. desc 'list', 'List blocked e-mail domains'
  13. def list
  14. EmailDomainBlock.where(parent_id: nil).order(id: 'DESC').find_each do |entry|
  15. say(entry.domain.to_s, :white)
  16. EmailDomainBlock.where(parent_id: entry.id).order(id: 'DESC').find_each do |child|
  17. say(" #{child.domain}", :cyan)
  18. end
  19. end
  20. end
  21. option :with_dns_records, type: :boolean
  22. desc 'add DOMAIN...', 'Block e-mail domain(s)'
  23. long_desc <<-LONG_DESC
  24. Blocking an e-mail domain prevents users from signing up
  25. with e-mail addresses from that domain. You can provide one or
  26. multiple domains to the command.
  27. When the --with-dns-records option is given, an attempt to resolve the
  28. given domains' MX records will be made and the results will also be blocked.
  29. This can be helpful if you are blocking an e-mail server that has many
  30. different domains pointing to it as it allows you to essentially block
  31. it at the root.
  32. LONG_DESC
  33. def add(*domains)
  34. if domains.empty?
  35. say('No domain(s) given', :red)
  36. exit(1)
  37. end
  38. skipped = 0
  39. processed = 0
  40. domains.each do |domain|
  41. if EmailDomainBlock.where(domain: domain).exists?
  42. say("#{domain} is already blocked.", :yellow)
  43. skipped += 1
  44. next
  45. end
  46. other_domains = []
  47. if options[:with_dns_records]
  48. Resolv::DNS.open do |dns|
  49. dns.timeouts = 5
  50. other_domains = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a
  51. end
  52. end
  53. email_domain_block = EmailDomainBlock.new(domain: domain, other_domains: other_domains)
  54. email_domain_block.save!
  55. processed += 1
  56. (email_domain_block.other_domains || []).uniq.each do |hostname|
  57. another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: email_domain_block)
  58. if EmailDomainBlock.where(domain: hostname).exists?
  59. say("#{hostname} is already blocked.", :yellow)
  60. skipped += 1
  61. next
  62. end
  63. another_email_domain_block.save!
  64. processed += 1
  65. end
  66. end
  67. say("Added #{processed}, skipped #{skipped}", color(processed, 0))
  68. end
  69. desc 'remove DOMAIN...', 'Remove e-mail domain blocks'
  70. def remove(*domains)
  71. if domains.empty?
  72. say('No domain(s) given', :red)
  73. exit(1)
  74. end
  75. skipped = 0
  76. processed = 0
  77. failed = 0
  78. domains.each do |domain|
  79. entry = EmailDomainBlock.find_by(domain: domain)
  80. if entry.nil?
  81. say("#{domain} is not yet blocked.", :yellow)
  82. skipped += 1
  83. next
  84. end
  85. children_count = EmailDomainBlock.where(parent_id: entry.id).count
  86. result = entry.destroy
  87. if result
  88. processed += children_count + 1
  89. else
  90. say("#{domain} could not be unblocked.", :red)
  91. failed += 1
  92. end
  93. end
  94. say("Removed #{processed}, skipped #{skipped}, failed #{failed}", color(processed, failed))
  95. end
  96. private
  97. def color(processed, failed)
  98. if !processed.zero? && failed.zero?
  99. :green
  100. elsif failed.zero?
  101. :yellow
  102. else
  103. :red
  104. end
  105. end
  106. end
  107. end