discourse/app/services/email_settings_exception_ha...

117 lines
3.4 KiB
Ruby

# frozen_string_literal: true
require "net/imap"
require "net/smtp"
require "net/pop"
class EmailSettingsExceptionHandler
EXPECTED_EXCEPTIONS = [
Net::POPAuthenticationError,
Net::IMAP::NoResponseError,
Net::IMAP::Error,
Net::SMTPAuthenticationError,
Net::SMTPServerBusy,
Net::SMTPSyntaxError,
Net::SMTPFatalError,
Net::SMTPUnknownError,
Net::OpenTimeout,
Net::ReadTimeout,
SocketError,
Errno::ECONNREFUSED,
]
class GenericProvider
def initialize(exception)
@exception = exception
end
def message
case @exception
when Net::POPAuthenticationError
net_pop_authentication_error
when Net::IMAP::NoResponseError
net_imap_no_response_error
when Net::IMAP::Error
net_imap_unhandled_error
when Net::SMTPAuthenticationError
net_smtp_authentication_error
when Net::SMTPServerBusy
net_smtp_server_busy
when Net::SMTPSyntaxError, Net::SMTPFatalError, Net::SMTPUnknownError
net_smtp_unhandled_error
when SocketError, Errno::ECONNREFUSED
socket_connection_error
when Net::OpenTimeout, Net::ReadTimeout
net_timeout_error
else
unhandled_error
end
end
private
def net_pop_authentication_error
I18n.t("email_settings.pop3_authentication_error")
end
def net_imap_no_response_error
# Most of IMAP's errors are lumped under the NoResponseError, including invalid
# credentials errors, because it is raised when a "NO" response is
# raised from the IMAP server https://datatracker.ietf.org/doc/html/rfc3501#section-7.1.2
#
# Generally, it should be fairly safe to just return the error message as is.
if @exception.message.match(/Invalid credentials/)
I18n.t("email_settings.imap_authentication_error")
else
I18n.t(
"email_settings.imap_no_response_error",
message: @exception.message.gsub(" (Failure)", ""),
)
end
end
def net_imap_unhandled_error
I18n.t("email_settings.imap_unhandled_error", message: @exception.message)
end
def net_smtp_authentication_error
# Generally SMTP authentication errors are due to invalid credentials,
# and most common mail servers provide more detailed error messages,
# so it should be safe to return the error message as is.
#
# Example: Office 365 returns:
#
# 535 5.7.139 Authentication unsuccessful, user is locked by your organization's security defaults policy. Contact your administrator.
#
# Example: Gmail returns:
#
# Application-specific password required. Learn more at https://support.google.com/accounts/answer/185833
I18n.t("email_settings.smtp_authentication_error", message: @exception.message)
end
def net_smtp_server_busy
I18n.t("email_settings.smtp_server_busy_error")
end
def net_smtp_unhandled_error
I18n.t("email_settings.smtp_unhandled_error", message: @exception.message)
end
def socket_connection_error
I18n.t("email_settings.connection_error")
end
def net_timeout_error
I18n.t("email_settings.timeout_error")
end
def unhandled_error
I18n.t("email_settings.unhandled_error", message: @exception.message)
end
end
def self.friendly_exception_message(exception, host)
EmailSettingsExceptionHandler::GenericProvider.new(exception).message
end
end