From d56c47033c32d6d32a864e5c16a3b2fd959b08da Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 14 Apr 2023 14:17:48 +0000 Subject: Add latest changes from gitlab-org/gitlab@15-10-stable-ee --- Gemfile | 4 ++ config/initializers/mail_starttls_patch.rb | 87 +++++++++++++++++++++++++++ spec/initializers/mail_starttls_patch_spec.rb | 86 ++++++++++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 config/initializers/mail_starttls_patch.rb create mode 100644 spec/initializers/mail_starttls_patch_spec.rb diff --git a/Gemfile b/Gemfile index 15995b07e1f..a8063691b7e 100644 --- a/Gemfile +++ b/Gemfile @@ -546,6 +546,10 @@ gem 'lru_redux' # Locked as long as quoted-printable encoding issues are not resolved # Monkey-patched in `config/initializers/mail_encoding_patch.rb` # See https://gitlab.com/gitlab-org/gitlab/issues/197386 +# +# `config/initializers/mail_starttls_patch.rb` has also been patched to +# fix STARTTLS handling until https://github.com/mikel/mail/pull/1536 is +# released. gem 'mail', '= 2.8.1' gem 'mail-smtp_pool', '~> 0.1.0', path: 'vendor/gems/mail-smtp_pool', require: false diff --git a/config/initializers/mail_starttls_patch.rb b/config/initializers/mail_starttls_patch.rb new file mode 100644 index 00000000000..c4fe102edfb --- /dev/null +++ b/config/initializers/mail_starttls_patch.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require 'mail/network/delivery_methods/smtp' + +# Monkey patch mail 2.8.1 to make it possible to disable STARTTLS. +# without having to change existing settings. +# This brings in changes from https://github.com/mikel/mail/pull/1536, +# which has not been released yet. +module Mail + class SMTP + def initialize(values) + self.settings = DEFAULTS + settings[:enable_starttls_auto] = nil + settings.merge!(values) + end + + private + + # `key` is said to be provided when `settings` has a non-nil value for `key`. + def setting_provided?(key) + !settings[key].nil? + end + + # Yields one of `:always`, `:auto` or `false` based on `enable_starttls` and `enable_starttls_auto` flags. + # Yields `false` when `smtp_tls?`. + def smtp_starttls + return false if smtp_tls? + + if setting_provided?(:enable_starttls) && settings[:enable_starttls] + # enable_starttls: provided and truthy + case settings[:enable_starttls] + when :auto then :auto + when :always then :always + else + :always + end + elsif setting_provided?(:enable_starttls_auto) + # enable_starttls: not provided or false + settings[:enable_starttls_auto] ? :auto : false + else + # enable_starttls_auto: not provided + # enable_starttls: when provided then false + # use :auto when neither enable_starttls* provided + setting_provided?(:enable_starttls) ? false : :auto + end + end + + def smtp_tls? + (setting_provided?(:tls) && settings[:tls]) || (setting_provided?(:ssl) && settings[:ssl]) + end + + def start_smtp_session(&block) + build_smtp_session.start(settings[:domain], settings[:user_name], settings[:password], + settings[:authentication], &block) + end + + def build_smtp_session + if smtp_tls? && (settings[:enable_starttls] || settings[:enable_starttls_auto]) + # rubocop:disable Layout/LineLength + raise ArgumentError, + ":enable_starttls and :tls are mutually exclusive. Set :tls if you're on an SMTPS connection. Set :enable_starttls if you're on an SMTP connection and using STARTTLS for secure TLS upgrade." + # rubocop:enable Layout/LineLength + end + + Net::SMTP.new(settings[:address], settings[:port]).tap do |smtp| + if smtp_tls? + smtp.disable_starttls + smtp.enable_tls(ssl_context) + else + smtp.disable_tls + + case smtp_starttls + when :always + smtp.enable_starttls(ssl_context) + when :auto + smtp.enable_starttls_auto(ssl_context) + else + smtp.disable_starttls + end + end + + smtp.open_timeout = settings[:open_timeout] if settings[:open_timeout] + smtp.read_timeout = settings[:read_timeout] if settings[:read_timeout] + end + end + end +end diff --git a/spec/initializers/mail_starttls_patch_spec.rb b/spec/initializers/mail_starttls_patch_spec.rb new file mode 100644 index 00000000000..126ffb98f0e --- /dev/null +++ b/spec/initializers/mail_starttls_patch_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +# rubocop:disable RSpec/VariableDefinition, RSpec/VariableName + +require 'spec_helper' +require 'mail' +require_relative '../../config/initializers/mail_starttls_patch' + +RSpec.describe 'Mail STARTTLS patch', feature_category: :integrations do + using RSpec::Parameterized::TableSyntax + + let(:message) do + Mail.new do + from 'sender@example.com' + to 'receiver@example.com' + subject 'test mesage' + end + end + + # Taken from https://github.com/mikel/mail/pull/1536#issue-1490438378 + where(:ssl, :tls, :enable_starttls, :enable_starttls_auto, :smtp_tls, :smtp_starttls_mode) do + true | nil | nil | nil | true | false + nil | false | nil | nil | false | :auto + nil | false | nil | true | false | :auto + false | false | true | false | false | :always + false | nil | false | false | false | false + false | false | false | nil | false | false + false | nil | :always | nil | false | :always + false | nil | :auto | nil | false | :auto + end + + with_them do + let(:values) do + { + ssl: ssl, + tls: tls, + enable_starttls: enable_starttls, + enable_starttls_auto: enable_starttls_auto + } + end + + let(:mail) { Mail::SMTP.new(values) } + let(:smtp) { double } + + it 'sets TLS and STARTTLS settings properly' do + expect(smtp).to receive(:open_timeout=) + expect(smtp).to receive(:read_timeout=) + expect(smtp).to receive(:start) + + if smtp_tls + expect(smtp).to receive(:enable_tls) + expect(smtp).to receive(:disable_starttls) + else + expect(smtp).to receive(:disable_tls) + + case smtp_starttls_mode + when :always + expect(smtp).to receive(:enable_starttls) + when :auto + expect(smtp).to receive(:enable_starttls_auto) + when false + expect(smtp).to receive(:disable_starttls) + end + end + + allow(Net::SMTP).to receive(:new).and_return(smtp) + mail.deliver!(message) + end + end + + context 'when enable_starttls and tls are enabled' do + let(:values) do + { + tls: true, + enable_starttls: true + } + end + + let(:mail) { Mail::SMTP.new(values) } + + it 'raises an argument exception' do + expect { mail.deliver!(message) }.to raise_error(ArgumentError) + end + end +end +# rubocop:enable RSpec/VariableDefinition, RSpec/VariableName -- cgit v1.2.1