Files
danbooru/app/logical/email_validator.rb
evazion b7bd6c8fdd users: require email verification for signups from proxies.
Require users who signup using proxies to verify their email addresses
before they can perform any edits. For verification purposes, the email
must be a nondisposable address from a whitelist of trusted email
providers.
2020-03-24 17:25:35 -05:00

121 lines
3.6 KiB
Ruby

require 'resolv'
module EmailValidator
module_function
IGNORE_DOTS = %w[gmail.com]
IGNORE_PLUS_ADDRESSING = %w[gmail.com hotmail.com outlook.com live.com]
IGNORE_MINUS_ADDRESSING = %w[yahoo.com]
CANONICAL_DOMAINS = {
"googlemail.com" => "gmail.com",
"hotmail.co.uk" => "outlook.com",
"hotmail.co.jp" => "outlook.com",
"hotmail.co.th" => "outlook.com",
"hotmail.com" => "outlook.com",
"hotmail.ca" => "outlook.com",
"hotmail.de" => "outlook.com",
"hotmail.es" => "outlook.com",
"hotmail.fr" => "outlook.com",
"hotmail.it" => "outlook.com",
"live.com.au" => "outlook.com",
"live.com.ar" => "outlook.com",
"live.com.mx" => "outlook.com",
"live.co.uk" => "outlook.com",
"live.com" => "outlook.com",
"live.ca" => "outlook.com",
"live.cl" => "outlook.com",
"live.cn" => "outlook.com",
"live.de" => "outlook.com",
"live.fr" => "outlook.com",
"live.it" => "outlook.com",
"live.jp" => "outlook.com",
"live.nl" => "outlook.com",
"live.se" => "outlook.com",
"msn.com" => "outlook.com",
"yahoo.com.au" => "yahoo.com",
"yahoo.com.ar" => "yahoo.com",
"yahoo.com.br" => "yahoo.com",
"yahoo.com.cn" => "yahoo.com",
"yahoo.com.hk" => "yahoo.com",
"yahoo.com.mx" => "yahoo.com",
"yahoo.com.ph" => "yahoo.com",
"yahoo.com.sg" => "yahoo.com",
"yahoo.com.tw" => "yahoo.com",
"yahoo.com.vn" => "yahoo.com",
"yahoo.co.id" => "yahoo.com",
"yahoo.co.kr" => "yahoo.com",
"yahoo.co.jp" => "yahoo.com",
"yahoo.co.uk" => "yahoo.com",
"yahoo.ca" => "yahoo.com",
"yahoo.cn" => "yahoo.com",
"yahoo.de" => "yahoo.com",
"yahoo.es" => "yahoo.com",
"yahoo.fr" => "yahoo.com",
"yahoo.it" => "yahoo.com",
"ymail.com" => "yahoo.com",
"126.com" => "163.com",
"aim.com" => "aol.com",
"gmx.com" => "gmx.net",
"gmx.at" => "gmx.net",
"gmx.ch" => "gmx.net",
"gmx.de" => "gmx.net",
"gmx.fr" => "gmx.net",
"gmx.us" => "gmx.net",
}
def normalize(address)
return nil unless address.count("@") == 1
name, domain = address.downcase.split("@")
domain = CANONICAL_DOMAINS.fetch(domain, domain)
name = name.delete(".") if domain.in?(IGNORE_DOTS)
name = name.gsub(/\+.*\z/, "") if domain.in?(IGNORE_PLUS_ADDRESSING)
name = name.gsub(/-.*\z/, "") if domain.in?(IGNORE_MINUS_ADDRESSING)
"#{name}@#{domain}"
end
def nondisposable?(address)
domain = Mail::Address.new(address).domain
domain.in?(Danbooru.config.email_domain_verification_list)
end
def undeliverable?(to_address, from_address: Danbooru.config.contact_email, timeout: 3)
mail_server = mx_domain(to_address, timeout: timeout)
mail_server.nil? || rcpt_to_failed?(to_address, from_address, mail_server, timeout: timeout)
rescue
false
end
def rcpt_to_failed?(to_address, from_address, mail_server, timeout: nil)
return false unless smtp_enabled?
from_domain = Mail::Address.new(from_address).domain
smtp = Net::SMTP.new(mail_server)
smtp.read_timeout = timeout
smtp.open_timeout = timeout
smtp.start(from_domain) do |conn|
conn.mailfrom(from_address)
# Net::SMTPFatalError is raised if RCPT TO returns a 5xx error.
response = conn.rcptto(to_address) rescue $!
return response.is_a?(Net::SMTPFatalError)
end
end
def mx_domain(to_address, timeout: nil)
domain = Mail::Address.new(to_address).domain
dns = Resolv::DNS.new
dns.timeouts = timeout
response = dns.getresource(domain, Resolv::DNS::Resource::IN::MX)
response.exchange.to_s
rescue Resolv::ResolvError
nil
end
end