From 96202c9b7aefe80605c8700228fee52d3d009ae9 Mon Sep 17 00:00:00 2001 From: Rosa Gutierrez Date: Mon, 20 Dec 2021 10:46:22 +0100 Subject: [PATCH] Handle too long dates passed to DateTime.parse This raises an ArgumentError with a different message from the invalid date message since Ruby 3.0.3 when the string passed is too long, as a mitigation for CVE-2021-41817. https://www.ruby-lang.org/en/news/2021/11/15/date-parsing-method-regexp-dos-cve-2021-41817/ In this case we should just return nil, like when the date itself is invalid. --- lib/mail/fields/common_date_field.rb | 44 ++++++++++++++++------------ spec/mail/fields/date_field_spec.rb | 6 ++++ 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/lib/mail/fields/common_date_field.rb b/lib/mail/fields/common_date_field.rb index 05259aa85..83178e535 100644 --- a/lib/mail/fields/common_date_field.rb +++ b/lib/mail/fields/common_date_field.rb @@ -4,26 +4,32 @@ module Mail class CommonDateField < NamedStructuredField #:nodoc: - def self.singular? - true - end + class << self + def singular? + true + end - def self.normalize_datetime(string) - if Utilities.blank?(string) - datetime = ::DateTime.now - else - stripped = string.to_s.gsub(/\(.*?\)/, '').squeeze(' ') - begin - datetime = ::DateTime.parse(stripped) - rescue ArgumentError => e - raise unless 'invalid date' == e.message + def normalize_datetime(string) + if Utilities.blank?(string) + datetime = ::DateTime.now + else + stripped = string.to_s.gsub(/\(.*?\)/, '').squeeze(' ') + with_invalid_date_time_error_handling do + datetime = ::DateTime.parse(stripped) + end + end + + if datetime + datetime.strftime('%a, %d %b %Y %H:%M:%S %z') + else + string end end - if datetime - datetime.strftime('%a, %d %b %Y %H:%M:%S %z') - else - string + def with_invalid_date_time_error_handling(&block) + yield + rescue ArgumentError => e + raise unless e.message =~ /\A(invalid date|string length \(\d+\) exceeds the limit \d+)\z/ end end @@ -33,9 +39,9 @@ def initialize(value = nil, charset = nil) # Returns a date time object of the parsed date def date_time - ::DateTime.parse("#{element.date_string} #{element.time_string}") - rescue ArgumentError => e - raise e unless e.message == 'invalid date' + self.class.with_invalid_date_time_error_handling do + ::DateTime.parse("#{element.date_string} #{element.time_string}") + end end def default diff --git a/spec/mail/fields/date_field_spec.rb b/spec/mail/fields/date_field_spec.rb index bdb9e916b..5d3618fb5 100644 --- a/spec/mail/fields/date_field_spec.rb +++ b/spec/mail/fields/date_field_spec.rb @@ -66,5 +66,11 @@ field = Mail::DateField.new("12 Aug 2009 30:00:02 GMT") expect(field.date_time).to be_nil end + + it "should handle too long invalid date" do + # field = Mail::DateField.new("12 Aug 2009 30:00:02 GMT") + field = Mail::DateField.new("Wed, 23 Jan 2019 30:51:32 -0500") + expect(field.date_time).to be_nil + end end end