From 22da434f10b46306505ccf9796d90ba7177fddee Mon Sep 17 00:00:00 2001 From: nick evans Date: Tue, 18 Feb 2025 18:39:03 -0500 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=92=A5=F0=9F=94=A5=20Remove=20depreca?= =?UTF-8?q?ted=20UIDPlusData=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/net/imap.rb | 6 +- lib/net/imap/response_data.rb | 5 +- lib/net/imap/response_parser.rb | 19 +----- lib/net/imap/uidplus_data.rb | 65 +----------------- test/net/imap/test_response_parser.rb | 94 --------------------------- test/net/imap/test_uidplus_data.rb | 42 ------------ 6 files changed, 9 insertions(+), 222 deletions(-) diff --git a/lib/net/imap.rb b/lib/net/imap.rb index 4ac9d7a89..dce03b63f 100644 --- a/lib/net/imap.rb +++ b/lib/net/imap.rb @@ -2020,7 +2020,7 @@ def status(mailbox, attr) # # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is # supported and the destination supports persistent UIDs, the server's - # response should include an +APPENDUID+ response code with UIDPlusData. + # response should include an +APPENDUID+ response code with AppendUIDData. # This will report the UIDVALIDITY of the destination mailbox and the # assigned UID of the appended message. # @@ -2777,7 +2777,7 @@ def uid_store(set, attr, flags, unchangedsince: nil) # # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is # supported, the server's response should include a +COPYUID+ response code - # with UIDPlusData. This will report the UIDVALIDITY of the destination + # with CopyUIDData. This will report the UIDVALIDITY of the destination # mailbox, the UID set of the source messages, and the assigned UID set of # the moved messages. # @@ -2818,7 +2818,7 @@ def uid_copy(set, mailbox) # # If +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315.html]] is # supported, the server's response should include a +COPYUID+ response code - # with UIDPlusData. This will report the UIDVALIDITY of the destination + # with CopyUIDData. This will report the UIDVALIDITY of the destination # mailbox, the UID set of the source messages, and the assigned UID set of # the moved messages. # diff --git a/lib/net/imap/response_data.rb b/lib/net/imap/response_data.rb index 875f7f2f6..950205b3c 100644 --- a/lib/net/imap/response_data.rb +++ b/lib/net/imap/response_data.rb @@ -6,7 +6,6 @@ class IMAP < Protocol autoload :FetchData, "#{__dir__}/fetch_data" autoload :UIDFetchData, "#{__dir__}/fetch_data" autoload :SearchResult, "#{__dir__}/search_result" - autoload :UIDPlusData, "#{__dir__}/uidplus_data" autoload :AppendUIDData, "#{__dir__}/uidplus_data" autoload :CopyUIDData, "#{__dir__}/uidplus_data" autoload :VanishedData, "#{__dir__}/vanished_data" @@ -260,8 +259,8 @@ class ResponseText < Struct.new(:code, :text) # # === +UIDPLUS+ extension # See {[RFC4315 ยง3]}[https://www.rfc-editor.org/rfc/rfc4315#section-3]. - # * +APPENDUID+, #data is UIDPlusData. See IMAP#append. - # * +COPYUID+, #data is UIDPlusData. See IMAP#copy. + # * +APPENDUID+, #data is AppendUIDData. See IMAP#append. + # * +COPYUID+, #data is CopyUIDData. See IMAP#copy. # * +UIDNOTSTICKY+, #data is +nil+. See IMAP#select. # # === +SEARCHRES+ extension diff --git a/lib/net/imap/response_parser.rb b/lib/net/imap/response_parser.rb index 03e54b202..098e77e77 100644 --- a/lib/net/imap/response_parser.rb +++ b/lib/net/imap/response_parser.rb @@ -2017,23 +2017,8 @@ def resp_code_copy__data CopyUID(validity, src_uids, dst_uids) end - def AppendUID(...) DeprecatedUIDPlus(...) || AppendUIDData.new(...) end - def CopyUID(...) DeprecatedUIDPlus(...) || CopyUIDData.new(...) end - - # TODO: remove this code in the v0.6.0 release - def DeprecatedUIDPlus(validity, src_uids = nil, dst_uids) - return unless config.parser_use_deprecated_uidplus_data - compact_uid_sets = [src_uids, dst_uids].compact - count = compact_uid_sets.map { _1.count_with_duplicates }.max - max = config.parser_max_deprecated_uidplus_data_size - if count <= max - src_uids &&= src_uids.each_ordered_number.to_a - dst_uids = dst_uids.each_ordered_number.to_a - UIDPlusData.new(validity, src_uids, dst_uids) - elsif config.parser_use_deprecated_uidplus_data != :up_to_max_size - parse_error("uid-set is too large: %d > %d", count, max) - end - end + def AppendUID(...) AppendUIDData.new(...) end + def CopyUID(...) CopyUIDData.new(...) end ADDRESS_REGEXP = /\G \( (?: NIL | #{Patterns::QUOTED_rev2} ) # 1: NAME diff --git a/lib/net/imap/uidplus_data.rb b/lib/net/imap/uidplus_data.rb index 0e5936366..14eb70a7c 100644 --- a/lib/net/imap/uidplus_data.rb +++ b/lib/net/imap/uidplus_data.rb @@ -3,69 +3,8 @@ module Net class IMAP < Protocol - # *NOTE:* UIDPlusData is deprecated and will be removed in the +0.6.0+ - # release. To use AppendUIDData and CopyUIDData before +0.6.0+, set - # Config#parser_use_deprecated_uidplus_data to +false+. - # - # UIDPlusData represents the ResponseCode#data that accompanies the - # +APPENDUID+ and +COPYUID+ {response codes}[rdoc-ref:ResponseCode]. - # - # A server that supports +UIDPLUS+ should send UIDPlusData in response to - # the append[rdoc-ref:Net::IMAP#append], copy[rdoc-ref:Net::IMAP#copy], - # move[rdoc-ref:Net::IMAP#move], {uid copy}[rdoc-ref:Net::IMAP#uid_copy], - # and {uid move}[rdoc-ref:Net::IMAP#uid_move] commands---unless the - # destination mailbox reports +UIDNOTSTICKY+. - # - # Note that append[rdoc-ref:Net::IMAP#append], copy[rdoc-ref:Net::IMAP#copy] - # and {uid_copy}[rdoc-ref:Net::IMAP#uid_copy] return UIDPlusData in their - # TaggedResponse. But move[rdoc-ref:Net::IMAP#copy] and - # {uid_move}[rdoc-ref:Net::IMAP#uid_move] _should_ send UIDPlusData in an - # UntaggedResponse response before sending their TaggedResponse. However - # some servers do send UIDPlusData in the TaggedResponse for +MOVE+ - # commands---this complies with the older +UIDPLUS+ specification but is - # discouraged by the +MOVE+ extension and disallowed by +IMAP4rev2+. - # - # == Required capability - # Requires either +UIDPLUS+ [RFC4315[https://www.rfc-editor.org/rfc/rfc4315]] - # or +IMAP4rev2+ capability. - # - class UIDPlusData < Struct.new(:uidvalidity, :source_uids, :assigned_uids) - ## - # method: uidvalidity - # :call-seq: uidvalidity -> nonzero uint32 - # - # The UIDVALIDITY of the destination mailbox. - - ## - # method: source_uids - # :call-seq: source_uids -> nil or an array of nonzero uint32 - # - # The UIDs of the copied or moved messages. - # - # Note:: Returns +nil+ for Net::IMAP#append. - - ## - # method: assigned_uids - # :call-seq: assigned_uids -> an array of nonzero uint32 - # - # The newly assigned UIDs of the copied, moved, or appended messages. - # - # Note:: This always returns an array, even when it contains only one UID. - - ## - # :call-seq: uid_mapping -> nil or a hash - # - # Returns a hash mapping each source UID to the newly assigned destination - # UID. - # - # Note:: Returns +nil+ for Net::IMAP#append. - def uid_mapping - source_uids&.zip(assigned_uids)&.to_h - end - end - # >>> - # *NOTE:* AppendUIDData will replace UIDPlusData for +APPENDUID+ in the + # *NOTE:* AppendUIDData replaced UIDPlusData for +APPENDUID+ in the # +0.6.0+ release. To use AppendUIDData before +0.6.0+, set # Config#parser_use_deprecated_uidplus_data to +false+. # @@ -109,7 +48,7 @@ def size end # >>> - # *NOTE:* CopyUIDData will replace UIDPlusData for +COPYUID+ in the + # *NOTE:* CopyUIDData replaced UIDPlusData for +COPYUID+ in the # +0.6.0+ release. To use CopyUIDData before +0.6.0+, set # Config#parser_use_deprecated_uidplus_data to +false+. # diff --git a/test/net/imap/test_response_parser.rb b/test/net/imap/test_response_parser.rb index f6a4b756e..cb35e4196 100644 --- a/test/net/imap/test_response_parser.rb +++ b/test/net/imap/test_response_parser.rb @@ -201,51 +201,6 @@ def test_fetch_binary_and_binary_size end end - test "APPENDUID with parser_use_deprecated_uidplus_data = true" do - parser = Net::IMAP::ResponseParser.new(config: { - parser_use_deprecated_uidplus_data: true, - parser_max_deprecated_uidplus_data_size: 10_000, - }) - assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do - parser.parse( - "A004 OK [APPENDUID 1 10000:20000,1] Done\r\n" - ) - end - response = parser.parse("A004 OK [APPENDUID 1 100:200] Done\r\n") - uidplus = response.data.code.data - assert_equal 101, uidplus.assigned_uids.size - parser.config.parser_max_deprecated_uidplus_data_size = 100 - assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do - parser.parse( - "A004 OK [APPENDUID 1 100:200] Done\r\n" - ) - end - response = parser.parse("A004 OK [APPENDUID 1 101:200] Done\r\n") - uidplus = response.data.code.data - assert_instance_of Net::IMAP::UIDPlusData, uidplus - assert_equal 100, uidplus.assigned_uids.size - end - - test "APPENDUID with parser_use_deprecated_uidplus_data = :up_to_max_size" do - parser = Net::IMAP::ResponseParser.new(config: { - parser_use_deprecated_uidplus_data: :up_to_max_size, - parser_max_deprecated_uidplus_data_size: 100 - }) - response = parser.parse("A004 OK [APPENDUID 1 101:200] Done\r\n") - assert_instance_of Net::IMAP::UIDPlusData, response.data.code.data - response = parser.parse("A004 OK [APPENDUID 1 100:200] Done\r\n") - assert_instance_of Net::IMAP::AppendUIDData, response.data.code.data - end - - test "APPENDUID with parser_use_deprecated_uidplus_data = false" do - parser = Net::IMAP::ResponseParser.new(config: { - parser_use_deprecated_uidplus_data: false, - parser_max_deprecated_uidplus_data_size: 10_000_000, - }) - response = parser.parse("A004 OK [APPENDUID 1 10] Done\r\n") - assert_instance_of Net::IMAP::AppendUIDData, response.data.code.data - end - test "COPYUID with backwards ranges" do parser = Net::IMAP::ResponseParser.new response = parser.parse( @@ -276,53 +231,4 @@ def test_fetch_binary_and_binary_size end end - test "COPYUID with parser_use_deprecated_uidplus_data = true" do - parser = Net::IMAP::ResponseParser.new(config: { - parser_use_deprecated_uidplus_data: true, - parser_max_deprecated_uidplus_data_size: 10_000, - }) - assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do - parser.parse( - "A004 OK [copyUID 1 10000:20000,1 1:10001] Done\r\n" - ) - end - response = parser.parse("A004 OK [copyUID 1 100:200 1:101] Done\r\n") - uidplus = response.data.code.data - assert_equal 101, uidplus.assigned_uids.size - assert_equal 101, uidplus.source_uids.size - parser.config.parser_max_deprecated_uidplus_data_size = 100 - assert_raise_with_message Net::IMAP::ResponseParseError, /uid-set is too large/ do - parser.parse( - "A004 OK [copyUID 1 100:200 1:101] Done\r\n" - ) - end - response = parser.parse("A004 OK [copyUID 1 101:200 1:100] Done\r\n") - uidplus = response.data.code.data - assert_instance_of Net::IMAP::UIDPlusData, uidplus - assert_equal 100, uidplus.assigned_uids.size - assert_equal 100, uidplus.source_uids.size - end - - test "COPYUID with parser_use_deprecated_uidplus_data = :up_to_max_size" do - parser = Net::IMAP::ResponseParser.new(config: { - parser_use_deprecated_uidplus_data: :up_to_max_size, - parser_max_deprecated_uidplus_data_size: 100 - }) - response = parser.parse("A004 OK [COPYUID 1 101:200 1:100] Done\r\n") - copyuid = response.data.code.data - assert_instance_of Net::IMAP::UIDPlusData, copyuid - response = parser.parse("A004 OK [COPYUID 1 100:200 1:101] Done\r\n") - copyuid = response.data.code.data - assert_instance_of Net::IMAP::CopyUIDData, copyuid - end - - test "COPYUID with parser_use_deprecated_uidplus_data = false" do - parser = Net::IMAP::ResponseParser.new(config: { - parser_use_deprecated_uidplus_data: false, - parser_max_deprecated_uidplus_data_size: 10_000_000, - }) - response = parser.parse("A004 OK [COPYUID 1 101 1] Done\r\n") - assert_instance_of Net::IMAP::CopyUIDData, response.data.code.data - end - end diff --git a/test/net/imap/test_uidplus_data.rb b/test/net/imap/test_uidplus_data.rb index e26609557..a87df9eef 100644 --- a/test/net/imap/test_uidplus_data.rb +++ b/test/net/imap/test_uidplus_data.rb @@ -3,48 +3,6 @@ require "net/imap" require "test/unit" -class TestUIDPlusData < Net::IMAP::TestCase - - test "#uid_mapping with sorted source_uids" do - uidplus = Net::IMAP::UIDPlusData.new( - 1, [19, 20, *(495..500)], [*(92..97), 100, 101], - ) - assert_equal( - { - 19 => 92, - 20 => 93, - 495 => 94, - 496 => 95, - 497 => 96, - 498 => 97, - 499 => 100, - 500 => 101, - }, - uidplus.uid_mapping - ) - end - - test "#uid_mapping for with source_uids in unsorted order" do - uidplus = Net::IMAP::UIDPlusData.new( - 1, [*(495..500), 19, 20], [*(92..97), 100, 101], - ) - assert_equal( - { - 495 => 92, - 496 => 93, - 497 => 94, - 498 => 95, - 499 => 96, - 500 => 97, - 19 => 100, - 20 => 101, - }, - uidplus.uid_mapping - ) - end - -end - class TestAppendUIDData < Net::IMAP::TestCase # alias for convenience AppendUIDData = Net::IMAP::AppendUIDData From a864e0d4084787945cb285e16988050928dd123c Mon Sep 17 00:00:00 2001 From: nick evans Date: Mon, 10 Nov 2025 16:34:11 -0500 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9A=20Document=20deprecated=20conf?= =?UTF-8?q?ig=20options=20for=20UIDPlusData?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/net/imap/config.rb | 57 ++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/lib/net/imap/config.rb b/lib/net/imap/config.rb index 8e2f230d4..86b8c4065 100644 --- a/lib/net/imap/config.rb +++ b/lib/net/imap/config.rb @@ -347,38 +347,31 @@ def self.[](config) # # Alias for responses_without_block - # Whether ResponseParser should use the deprecated UIDPlusData or + # **NOTE:** +UIDPlusData+ has been removed since +v0.6.0+, and this + # config option is completely ignored. The config option is kept + # only for compatibility and will be removed by +v0.7.0+. + # + # Whether ResponseParser would use the deprecated UIDPlusData or # CopyUIDData for +COPYUID+ response codes, and UIDPlusData or # AppendUIDData for +APPENDUID+ response codes. # - # UIDPlusData stores its data in arrays of numbers, which is vulnerable to - # a memory exhaustion denial of service attack from an untrusted or - # compromised server. Set this option to +false+ to completely block this - # vulnerability. Otherwise, parser_max_deprecated_uidplus_data_size - # mitigates this vulnerability. - # - # AppendUIDData and CopyUIDData are _mostly_ backward-compatible with - # UIDPlusData. Most applications should be able to upgrade with little - # or no changes. - # - # (Parser support for +UIDPLUS+ added in +v0.3.2+.) + # Parser support for +UIDPLUS+ added in +v0.3.2+. # - # (Config option added in +v0.4.19+ and +v0.5.6+.) + # Config option added in +v0.4.19+ and +v0.5.6+. # - # UIDPlusData will be removed in +v0.6+ and this config setting will - # be ignored. + # UIDPlusData was removed in +v0.6.0+. # - # ==== Valid options + # ==== Options # # [+true+ (original default)] - # ResponseParser only uses UIDPlusData. + # IGNORED since v0.6+. + # Prints a warning when UIDPLUS data is parsed. # # [+:up_to_max_size+ (default since +v0.5.6+)] - # ResponseParser uses UIDPlusData when the +uid-set+ size is below - # parser_max_deprecated_uidplus_data_size. Above that size, - # ResponseParser uses AppendUIDData or CopyUIDData. + # IGNORED since v0.6+. + # Prints a warning when UIDPLUS data is parsed. # - # [+false+ (planned default for +v0.6+)] + # [+false+ (only valid option since +v0.6.0+)] # ResponseParser _only_ uses AppendUIDData and CopyUIDData. attr_accessor :parser_use_deprecated_uidplus_data, type: Enum[ true, :up_to_max_size, false @@ -388,22 +381,22 @@ def self.[](config) 0.6r => false, } - # The maximum +uid-set+ size that ResponseParser will parse into - # deprecated UIDPlusData. This limit only applies when - # parser_use_deprecated_uidplus_data is not +false+. + # **NOTE:** +UIDPlusData+ has been removed since +v0.6.0+, and this + # config option is ignored. The config option is kept only for + # compatibility and will be removed by +v0.7.0+. # - # (Parser support for +UIDPLUS+ added in +v0.3.2+.) + # The maximum +uid-set+ size that ResponseParser would parse into + # deprecated UIDPlusData. This limit would only apply when + # parser_use_deprecated_uidplus_data was not +false+. # - # Support for limiting UIDPlusData to a maximum size was added in - # +v0.3.8+, +v0.4.19+, and +v0.5.6+. + # Parser support for +UIDPLUS+ added in +v0.3.2+. # - # UIDPlusData will be removed in +v0.6+. + # Support for limiting UIDPlusData to a maximum size was added in + # +v0.3.8+, +v0.4.19+, and +v0.5.6+. # - # ==== Versioned Defaults + # UIDPlusData was removed in +v0.6.0+. # - # Because this limit guards against a remote server causing catastrophic - # memory exhaustion, the versioned default (used by #load_defaults) also - # applies to versions without the feature. + # ==== Versioned Defaults # # * +0.3+ and prior: 10,000 # * +0.4+: 1,000