118 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
# frozen_string_literal: true
 | 
						|
 | 
						|
require 'concurrent'
 | 
						|
require_relative 'base'
 | 
						|
 | 
						|
module Mastodon::CLI
 | 
						|
  class EmailDomainBlocks < Base
 | 
						|
    desc 'list', 'List blocked e-mail domains'
 | 
						|
    def list
 | 
						|
      EmailDomainBlock.where(parent_id: nil).find_each do |entry|
 | 
						|
        say(entry.domain.to_s, :white)
 | 
						|
 | 
						|
        EmailDomainBlock.where(parent_id: entry.id).find_each do |child|
 | 
						|
          say("  #{child.domain}", :cyan)
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    option :with_dns_records, type: :boolean
 | 
						|
    desc 'add DOMAIN...', 'Block e-mail domain(s)'
 | 
						|
    long_desc <<-LONG_DESC
 | 
						|
      Blocking an e-mail domain prevents users from signing up
 | 
						|
      with e-mail addresses from that domain. You can provide one or
 | 
						|
      multiple domains to the command.
 | 
						|
 | 
						|
      When the --with-dns-records option is given, an attempt to resolve the
 | 
						|
      given domains' MX records will be made and the results will also be blocked.
 | 
						|
      This can be helpful if you are blocking an e-mail server that has many
 | 
						|
      different domains pointing to it as it allows you to essentially block
 | 
						|
      it at the root.
 | 
						|
    LONG_DESC
 | 
						|
    def add(*domains)
 | 
						|
      fail_with_message 'No domain(s) given' if domains.empty?
 | 
						|
 | 
						|
      skipped = 0
 | 
						|
      processed = 0
 | 
						|
 | 
						|
      domains.each do |domain|
 | 
						|
        if EmailDomainBlock.exists?(domain: domain)
 | 
						|
          say("#{domain} is already blocked.", :yellow)
 | 
						|
          skipped += 1
 | 
						|
          next
 | 
						|
        end
 | 
						|
 | 
						|
        other_domains = []
 | 
						|
        if options[:with_dns_records]
 | 
						|
          Resolv::DNS.open do |dns|
 | 
						|
            dns.timeouts = 5
 | 
						|
            other_domains = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a
 | 
						|
          end
 | 
						|
        end
 | 
						|
 | 
						|
        email_domain_block = EmailDomainBlock.new(domain: domain, other_domains: other_domains)
 | 
						|
        email_domain_block.save!
 | 
						|
        processed += 1
 | 
						|
 | 
						|
        (email_domain_block.other_domains || []).uniq.each do |hostname|
 | 
						|
          another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: email_domain_block)
 | 
						|
 | 
						|
          if EmailDomainBlock.exists?(domain: hostname)
 | 
						|
            say("#{hostname} is already blocked.", :yellow)
 | 
						|
            skipped += 1
 | 
						|
            next
 | 
						|
          end
 | 
						|
 | 
						|
          another_email_domain_block.save!
 | 
						|
          processed += 1
 | 
						|
        end
 | 
						|
      end
 | 
						|
 | 
						|
      say("Added #{processed}, skipped #{skipped}", color(processed, 0))
 | 
						|
    end
 | 
						|
 | 
						|
    desc 'remove DOMAIN...', 'Remove e-mail domain blocks'
 | 
						|
    def remove(*domains)
 | 
						|
      fail_with_message 'No domain(s) given' if domains.empty?
 | 
						|
 | 
						|
      skipped = 0
 | 
						|
      processed = 0
 | 
						|
      failed = 0
 | 
						|
 | 
						|
      domains.each do |domain|
 | 
						|
        entry = EmailDomainBlock.find_by(domain: domain)
 | 
						|
 | 
						|
        if entry.nil?
 | 
						|
          say("#{domain} is not yet blocked.", :yellow)
 | 
						|
          skipped += 1
 | 
						|
          next
 | 
						|
        end
 | 
						|
 | 
						|
        children_count = EmailDomainBlock.where(parent_id: entry.id).count
 | 
						|
        result = entry.destroy
 | 
						|
 | 
						|
        if result
 | 
						|
          processed += children_count + 1
 | 
						|
        else
 | 
						|
          say("#{domain} could not be unblocked.", :red)
 | 
						|
          failed += 1
 | 
						|
        end
 | 
						|
      end
 | 
						|
 | 
						|
      say("Removed #{processed}, skipped #{skipped}, failed #{failed}", color(processed, failed))
 | 
						|
    end
 | 
						|
 | 
						|
    private
 | 
						|
 | 
						|
    def color(processed, failed)
 | 
						|
      if !processed.zero? && failed.zero?
 | 
						|
        :green
 | 
						|
      elsif failed.zero?
 | 
						|
        :yellow
 | 
						|
      else
 | 
						|
        :red
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 |