From 305d22955fd9a679ff4dc72b8ccb631a80558980 Mon Sep 17 00:00:00 2001 From: nick evans Date: Sat, 14 Oct 2023 16:01:29 -0400 Subject: [PATCH 1/2] Forward keyword args and block from #authenticate --- lib/net/smtp.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb index cca06e6..44ebfb5 100644 --- a/lib/net/smtp.rb +++ b/lib/net/smtp.rb @@ -869,10 +869,10 @@ def open_message_stream(from_addr, *to_addrs, &block) # :yield: stream # All arguments-other than +authtype+-are forwarded to the authenticator. # Different authenticators may interpret the +user+ and +secret+ # arguments differently. - def authenticate(user, secret, authtype = DEFAULT_AUTH_TYPE) - check_auth_args authtype, user, secret + def authenticate(user, secret, authtype = DEFAULT_AUTH_TYPE, **kwargs, &block) + check_auth_args authtype, user, secret, **kwargs authenticator = Authenticator.auth_class(authtype).new(self) - authenticator.auth(user, secret) + authenticator.auth(user, secret, **kwargs, &block) end private From 2dd30e58e37cdf0a71acf41c3f3cf10e358090fd Mon Sep 17 00:00:00 2001 From: nick evans Date: Tue, 7 Nov 2023 18:10:29 -0500 Subject: [PATCH 2/2] Add `auth` keyword arg to `start` methods This adds a new `auth` keyword param to `Net::SMTP.start` and `#start` that can be used to pass any arbitrary keyword parameters to `#authenticate`. The pre-existing `username`, `secret`, etc keyword params will retain their existing behavior as positional arguments to `#authenticate`. --- lib/net/smtp.rb | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb index 44ebfb5..dbed2c4 100644 --- a/lib/net/smtp.rb +++ b/lib/net/smtp.rb @@ -459,6 +459,7 @@ def debug_output=(arg) # # :call-seq: + # start(address, port = nil, helo: 'localhost', auth: nil, tls: false, starttls: :auto, tls_verify: true, tls_hostname: nil, ssl_context_params: nil) { |smtp| ... } # start(address, port = nil, helo: 'localhost', user: nil, secret: nil, authtype: nil, tls: false, starttls: :auto, tls_verify: true, tls_hostname: nil, ssl_context_params: nil) { |smtp| ... } # start(address, port = nil, helo = 'localhost', user = nil, secret = nil, authtype = nil) { |smtp| ... } # @@ -521,6 +522,8 @@ def debug_output=(arg) # These will be sent to #authenticate as positional arguments-the exact # semantics are dependent on the +authtype+. # + # +auth+ is an optional hash of keyword arguments for #authenticate. + # # See the discussion of Net::SMTP@SMTP+Authentication in the overview notes. # # === Errors @@ -538,6 +541,7 @@ def debug_output=(arg) # def SMTP.start(address, port = nil, *args, helo: nil, user: nil, secret: nil, password: nil, authtype: nil, + auth: nil, tls: false, starttls: :auto, tls_verify: true, tls_hostname: nil, ssl_context_params: nil, &block) @@ -546,7 +550,8 @@ def SMTP.start(address, port = nil, *args, helo: nil, user ||= args[1] secret ||= password || args[2] authtype ||= args[3] - new(address, port, tls: tls, starttls: starttls, tls_verify: tls_verify, tls_hostname: tls_hostname, ssl_context_params: ssl_context_params).start(helo: helo, user: user, secret: secret, authtype: authtype, &block) + new(address, port, tls: tls, starttls: starttls, tls_verify: tls_verify, tls_hostname: tls_hostname, ssl_context_params: ssl_context_params) + .start(helo: helo, user: user, secret: secret, authtype: authtype, auth: auth, &block) end # +true+ if the \SMTP session has been started. @@ -558,6 +563,7 @@ def started? # :call-seq: # start(helo: 'localhost', user: nil, secret: nil, authtype: nil) { |smtp| ... } # start(helo = 'localhost', user = nil, secret = nil, authtype = nil) { |smtp| ... } + # start(helo = 'localhost', auth: {type: nil, **auth_kwargs}) { |smtp| ... } # # Opens a TCP connection and starts the SMTP session. # @@ -578,6 +584,8 @@ def started? # These will be sent to #authenticate as positional arguments-the exact # semantics are dependent on the +authtype+. # + # +auth+ is an optional hash of keyword arguments for #authenticate. + # # See the discussion of Net::SMTP@SMTP+Authentication in the overview notes. # # See also: Net::SMTP.start @@ -619,12 +627,15 @@ def started? # * Net::ReadTimeout # * IOError # - def start(*args, helo: nil, user: nil, secret: nil, password: nil, authtype: nil) + def start(*args, helo: nil, + user: nil, secret: nil, password: nil, + authtype: nil, auth: nil) raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0..4)" if args.size > 4 helo ||= args[0] || 'localhost' user ||= args[1] secret ||= password || args[2] authtype ||= args[3] + auth ||= {} if defined?(OpenSSL::VERSION) ssl_context_params = @ssl_context_params || {} unless ssl_context_params.has_key?(:verify_mode) @@ -639,13 +650,13 @@ def start(*args, helo: nil, user: nil, secret: nil, password: nil, authtype: nil end if block_given? begin - do_start helo, user, secret, authtype + do_start helo, user, secret, authtype, **auth return yield(self) ensure do_finish end else - do_start helo, user, secret, authtype + do_start helo, user, secret, authtype, **auth return self end end @@ -663,10 +674,10 @@ def tcp_socket(address, port) TCPSocket.open address, port end - def do_start(helo_domain, user, secret, authtype) + def do_start(helo_domain, user, secret, authtype, **auth) raise IOError, 'SMTP session already started' if @started - if user || secret || authtype - check_auth_args authtype, user, secret + if user || secret || authtype || auth.any? + check_auth_args(authtype, user, secret, **auth) end s = Timeout.timeout(@open_timeout, Net::OpenTimeout) do tcp_socket(@address, @port) @@ -684,7 +695,11 @@ def do_start(helo_domain, user, secret, authtype) # helo response may be different after STARTTLS do_helo helo_domain end - authenticate user, secret, (authtype || DEFAULT_AUTH_TYPE) if user + if user or secret + authenticate(user, secret, authtype, **auth) + elsif authtype or auth.any? + authenticate(authtype, **auth) + end @started = true ensure unless @started