Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🗑️ Add deprecation warnings to .new and #starttls #119

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 89 additions & 4 deletions lib/net/imap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -802,8 +802,21 @@ def idle_response_timeout; config.idle_response_timeout end
# Returns +false+ for a plaintext connection.
attr_reader :ssl_ctx_params

# Creates a new Net::IMAP object and connects it to the specified
# +host+.
# Creates a new Net::IMAP object and connects it to the specified +host+.
#
# ==== Default port and SSL
#
# When both both +port+ and +ssl+ are unspecified or +nil+,
# +ssl+ is determined by {config.default_ssl}[rdoc-ref:Config#default_ssl]
# and +port+ is based on that implicit value for +ssl+.
#
# When only one of the two is specified:
# * When +ssl+ is truthy, +port+ defaults to +993+.
# * When +ssl+ is +false+, +port+ defaults to +143+.
# * When +port+ is +993+, +ssl+ defaults to +true+.
# * When +port+ is +143+, +ssl+ defaults to +false+.
# * When +port+ is nonstandard, the default for +ssl+ is determined
# by {config.default_ssl}[rdoc-ref:Config#default_ssl].
#
# ==== Options
#
Expand Down Expand Up @@ -831,7 +844,9 @@ def idle_response_timeout; config.idle_response_timeout end
# SSL session verification mode. Valid modes include
# +OpenSSL::SSL::VERIFY_PEER+ and +OpenSSL::SSL::VERIFY_NONE+.
#
# See {OpenSSL::SSL::SSLContext}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html] for other valid SSL context params.
# See
# {OpenSSL::SSL::SSLContext}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html]
# for other valid SSL context params.
#
# See DeprecatedClientOptions.new for deprecated SSL arguments.
#
Expand Down Expand Up @@ -912,7 +927,7 @@ def initialize(host, port: nil, ssl: nil,
# Config options
@host = host
@config = Config.new(config, **config_options)
@port = port || (ssl ? SSL_PORT : PORT)
ssl, @port = default_ssl_and_port(ssl, port)
@ssl_ctx_params, @ssl_ctx = build_ssl_ctx(ssl)

# Basic Client State
Expand Down Expand Up @@ -2887,6 +2902,76 @@ def remove_response_handler(handler)
PORT = 143 # :nodoc:
SSL_PORT = 993 # :nodoc:

def default_ssl_and_port(tls, port)
case [tls && true, classify_port(port)]
in true, nil then return tls, SSL_PORT
in false, nil then return tls, PORT
in nil, :tls then return true, port
in nil, :plain then return false, port
in nil, nil then return use_default_ssl
in true, :tls | :other then return tls, port
in false, :plain | :other then return tls, port
in true, :plain then return warn_mismatched_port tls, port
in false, :tls then return warn_mismatched_port tls, port
in nil, :other then return warn_nonstandard_port port
end
# TODO: move this wherever is appropriate
tls &&= tls.respond_to?(:to_hash) ? tls.to_hash : {}
end

# classify_port(port) -> :tls | :plain | :other | nil
def classify_port(port)
case port
in (SSL_PORT | /\Aimaps\z/i) then :tls
in (PORT | /\Aimap\z/i) then :plain
in (Integer | String) then :other
in nil then nil
end
end

def warn_mismatched_port(tls, port)
if tls
warn "Using TLS on plaintext IMAP port"
else
warn "Using plaintext on TLS IMAP port"
end
[tls, port]
end

def warn_nonstandard_port(port)
tls = !!config.default_ssl
if config.warn_nonstandard_port_without_ssl
warn "Using #{tls ? "TLS" : "plaintext"} on port #{port}. " \
"Set ssl explicitly for non-standard IMAP ports."
end
# TODO: print default_ssl warning
[tls, port]
end

TLS_DEFAULT_WARNING =
"Net::IMAP.config.default_ssl will default to true in the future. " \
"To silence this warning, " \
"set Net::IMAP.config.default_ssl = (true | false)' or " \
"use 'Net::IMAP.new(host, ssl: (true | false))'."
private_constant :TLS_DEFAULT_WARNING

def use_default_ssl
case config.default_ssl
when true then [true, SSL_PORT]
when false then [false, PORT]
when :warn
warn TLS_DEFAULT_WARNING unless port
port ||= SSL_PORT
warn "Using TLS on port #{port}."
[true, port]
when nil
warn TLS_DEFAULT_WARNING unless port
port ||= PORT
warn "Using plain-text on port #{port}."
[false, port]
end
end

def start_imap_connection
@greeting = get_server_greeting
@capabilities = capabilities_from_resp_code @greeting
Expand Down
58 changes: 57 additions & 1 deletion lib/net/imap/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,51 @@ def self.[](config)
# The default value is +5+ seconds.
attr_accessor :idle_response_timeout, type: Integer

# The default value for the +ssl+ option of Net::IMAP.new, when +port+ is
# unspecified or non-standard and +ssl+ is unspecified. default_ssl is
# ignored when Net::IMAP.new is called with any value for +ssl+ besides
# +nil+,
#
# *Note*: A future release of Net::IMAP will set the default to +true+, as
# per RFC7525[https://tools.ietf.org/html/rfc7525],
# RFC7817[https://tools.ietf.org/html/rfc7817], and
# RFC8314[https://tools.ietf.org/html/rfc8314].
#
# <em>(The default_ssl config attribute was added in +v0.5.?+.)</em>
#
# ==== Valid options
#
# [+false+ <em>(original behavior)</em>]
# Plaintext by default, with no warnings.
# [+nil+ <em>(planned default for +v0.6+)</em>]
# Plaintext by default, and prints a warning.
#
# <em>This option will be removed in +v0.7+, when +:warn+ becomes the
# default.</em>
# [+:warn+ <em>(planned default for +v0.7+)</em>]
# A warning will be printed, and behave as if the default were +true+.
# [+true+ <em>(planned future default)</em>]
# Use TLS by default, with the default SSL context params set by calling
# {OpenSSL::SSL::SSLContext#set_params}[https://docs.ruby-lang.org/en/master/OpenSSL/SSL/SSLContext.html#method-i-set_params]
# with no params.
attr_accessor :default_ssl, type: [false, nil, :warn, true]

# Whether to warn for using default_ssl when the port is non-standard.
#
# Although default_ssl is used for non-standard ports, this warning is
# different replaces the warning when default_ssl is +nil+ or +:warn+.
# When this option is false but default_ssl is +nil+ or +:warn+, that
# warning will be printed instead.
#
# ==== Valid options
#
# [+false+ <em>(original behavior)</em>]
# Don't print a special warning for nonstandard ports without explicit
# +ssl+.
# [+true+ <em>(eventual future default)</em>]
# Print a special warning for nonstandard ports without explicit +ssl+.
attr_accessor :warn_nonstandard_port_without_ssl, type: :boolean

# Whether to use the +SASL-IR+ extension when the server and \SASL
# mechanism both support it. Can be overridden by the +sasl_ir+ keyword
# parameter to Net::IMAP#authenticate.
Expand Down Expand Up @@ -362,6 +407,8 @@ def defaults_hash
debug: false,
open_timeout: 30,
idle_response_timeout: 5,
default_ssl: false,
warn_nonstandard_port_without_ssl: false,
sasl_ir: true,
enforce_logindisabled: true,
responses_without_block: :warn,
Expand Down Expand Up @@ -390,9 +437,18 @@ def defaults_hash

version_defaults[0.6] = Config[0.5].dup.update(
responses_without_block: :frozen_dup,
default_ssl: nil,
).freeze
version_defaults[:next] = Config[0.6]
version_defaults[:future] = Config[:next]

version_defaults[0.7] = Config[0.6].dup.update(
default_ssl: :warn,
).freeze

version_defaults[:future] = Config[0.7].dup.update(
default_ssl: true,
warn_nonstandard_port_without_ssl: true,
).freeze

version_defaults.freeze
end
Expand Down