mail-jdec 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40591766001e935ee0d7788949ffeb1bc1169f15648e12b2393c1e493d73fbb5
4
- data.tar.gz: b2a30e1f237534e3f4ad48580d9696c7e51865230c0391282e83bcce2481b644
3
+ metadata.gz: 880f1f6ecdd0e34f0844fe398d29bfcb13587c5a93aef0b2bcd42e1a7dbb6319
4
+ data.tar.gz: 9a135d5433d8cb1af49178d9e0a80a2884a1955d59f5391c0beac9417d343715
5
5
  SHA512:
6
- metadata.gz: f20fb45790b61b679be860b6460a1db9d4ae4a04485a58de95fd3f17a6790be351d5ba37a7095b55556032950f585135dd31194c66ce492134e037386c0ca697
7
- data.tar.gz: dc3a1c3a3a5c77b4fa56f27ef20521bdf0559d1a58cceb8f425b1949a9a9aa523b75488a6dd772f0e11f39cd0cc131a5476b11df054ce9d5b5beb6bcddf0aaad
6
+ metadata.gz: 654dde35ada8044faf9cd06addb0876c27604a32cc7463055615a7684e6021e574a40686c24660979ec71ade8b7c8cffa316fffa1cadb8b54be95b319fbdcdce
7
+ data.tar.gz: ee99673c7b744c5a880e4e1a752d4afebc5784a6850f1e2dfbc31bdc3e88b7d082d4e985cb51bbdb38c23c12116e73d4c4f7a128730647811e25b3e105f944f4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.0.4
4
+
5
+ * Sanitize some wrong parameters for content type and content disposition.
6
+ * Sanitize unescaped characters for RFC2231 filename.
7
+ * Strip null bytes from decoded string.
8
+ * Decode unicode-1-1-utf-7.
9
+ * Fallback parser errors for date and addresses.
10
+ * Fallback unknown encoding errors for body.
11
+ * Sort filename parameters by counter number.
12
+
3
13
  ## 1.0.3
4
14
 
5
15
  * Fix decoding of quoted printable with space.
@@ -0,0 +1,19 @@
1
+ module Mail
2
+ module Jdec
3
+ module BodyPatch
4
+ def decoded
5
+ super
6
+ rescue Mail::UnknownEncodingType => e
7
+ if Jdec.enabled?
8
+ Jdec::Decoder.force_utf8(raw_source)
9
+ else
10
+ raise e
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ unless Mail::Body.included_modules.include?(Mail::Jdec::BodyPatch)
18
+ Mail::Body.prepend Mail::Jdec::BodyPatch
19
+ end
@@ -17,6 +17,16 @@ module Mail
17
17
  def force_utf8(str)
18
18
  str.dup.force_encoding('utf-8').encode('utf-8', invalid: :replace, undef: :replace)
19
19
  end
20
+
21
+ def decode_utf7(str)
22
+ str.gsub(/\+([^-]+)?-/n) do
23
+ if $1
24
+ ($1.tr(",", "/") + "===").unpack("m")[0].encode(Encoding::UTF_8, Encoding::UTF_16BE)
25
+ else
26
+ '+'
27
+ end
28
+ end
29
+ end
20
30
  end
21
31
  end
22
32
 
@@ -2,21 +2,37 @@ module Mail
2
2
  module Jdec
3
3
  module ContentDispositionElementPatch
4
4
  def initialize(string)
5
+ if Jdec.enabled?
6
+ # Remove extra trailing semicolon
7
+ string = string.gsub(/;+$/, '')
8
+ # Handles filename=test
9
+ string = string.gsub(/filename\s*=\s*([^"]+?)\s*(;|$)/im) { %Q|filename="#{$1}"#{$2}| }
10
+ # Handles filename=""test""
11
+ string = string.gsub(/filename\s*=\s*"+([^"]+?)"+\s*(;|$)/im) { %Q|filename="#{$1}"#{$2}| }
12
+ # Escape tspecial chars in RFC2231 filename
13
+ string = string.gsub(/filename\*(\d*)(\*?)\s*=\s*(\S+?)'(\S*)'(\S+)(;|$)/i) { %Q|filename*#{$1}#{$2}=#{$3}'#{$4}'#{Escaper.escape($5)}#{$6}| }
14
+ string = string.gsub(/filename\*(\d*)(\*?)\s*=\s*(\S+)(;|$)/i) { %Q|filename*#{$1}#{$2}=#{Escaper.escape($3)}#{$4}| }
15
+ end
16
+
5
17
  super
6
18
  rescue Mail::Field::ParseError => e
7
19
  if Jdec.enabled?
8
- value = Jdec::Decoder.force_utf8(string)
9
- if (matched = value.match(/^\s*attachment\s*;\s*(.+)/im))
10
- @disposition_type = 'attachment'
11
- @parameters = [{ filename: matched[1].gsub(/(\r\n|\r|\n)\s/, '') }]
12
- else
13
- raise e
14
- end
20
+ @disposition_type = 'attachment'
21
+ @parameters = ['filename' => Jdec::Decoder.force_utf8(string)]
15
22
  else
16
23
  raise e
17
24
  end
18
25
  end
19
26
  end
27
+
28
+ module Escaper
29
+ def self.escape(str)
30
+ require 'cgi'
31
+ str.gsub(/[#{Regexp.escape(%Q|()<>@,;:\\"/[]?=|)}]/) do |c|
32
+ CGI.escape(c)
33
+ end
34
+ end
35
+ end
20
36
  end
21
37
  end
22
38
 
@@ -3,11 +3,29 @@ module Mail
3
3
  module ContentTypeElementPatch
4
4
  def initialize(string)
5
5
  if Jdec.enabled?
6
- # Handles ; name=
7
- string = string.gsub(/^\s*;?\s*name=(.+)$/im) { "application/octet-stream; name=#{$1}" }
6
+ # Remove extra trailing semicolon
7
+ string = string.gsub(/;+$/, '')
8
+ # Remove unnecessary space
9
+ string = string.gsub(/;\s*charset\s+=\s+/i, '; charset=')
10
+ # Handles name=test
11
+ string = string.gsub(/name\s*=\s*([^"]+?)\s*(;|$)/im) { %Q|name="#{$1}"#{$2}| }
12
+ # Handles name=""test""
13
+ string = string.gsub(/name\s*=\s*"+([^"]+?)"+\s*(;|$)/im) { %Q|name="#{$1}"#{$2}| }
14
+ # Handles text; name=test
15
+ string = string.gsub(/^\s*([^\/]+)\s*;\s*name\s*=\s*(.+)$/im) { "#{$1}/unknown; name=#{$2}" }
16
+ # Handles ; name=test
17
+ string = string.gsub(/^\s*;?\s*name\s*=\s*(.+)$/im) { "application/octet-stream; name=#{$1}" }
8
18
  end
9
19
 
10
20
  super
21
+ rescue Mail::Field::ParseError => e
22
+ if Jdec.enabled?
23
+ @main_type = 'application'
24
+ @sub_type = 'octet-stream'
25
+ @parameters = ['name' => Jdec::Decoder.force_utf8(string)]
26
+ else
27
+ raise e
28
+ end
11
29
  end
12
30
  end
13
31
  end
@@ -0,0 +1,27 @@
1
+ module Mail
2
+ module Jdec
3
+ module AddressFieldPatch
4
+ def parse(val = value)
5
+ super
6
+ rescue Mail::Field::ParseError => e
7
+ if Jdec.enabled?
8
+ @errors = [name, val, e]
9
+ @address_list = AddressList.new('')
10
+ else
11
+ raise e
12
+ end
13
+ end
14
+
15
+ def errors
16
+ @errors
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ klasses = ObjectSpace.each_object(Class).select { |klass| klass < Mail::CommonAddress }
23
+ klasses.each do |klass|
24
+ unless klass.included_modules.include?(Mail::Jdec::AddressFieldPatch)
25
+ klass.prepend Mail::Jdec::AddressFieldPatch
26
+ end
27
+ end
@@ -0,0 +1,54 @@
1
+ module Mail
2
+ module Jdec
3
+ module DateFieldPatch
4
+ def date_time
5
+ super
6
+ rescue ArgumentError, Mail::Field::ParseError => e
7
+ if Jdec.enabled?
8
+ begin
9
+ require 'time'
10
+ Time.parse(value).to_datetime
11
+ rescue ArgumentError => e
12
+ nil
13
+ end
14
+ else
15
+ raise e
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ module Mail
23
+ class DateField < StructuredField
24
+ def initialize(value = nil, charset = nil)
25
+ super(CAPITALIZED_FIELD, self.class.normalize_datetime(value), charset)
26
+ end
27
+
28
+ def self.normalize_datetime(string)
29
+ if Utilities.blank?(string)
30
+ datetime = ::DateTime.now
31
+ else
32
+ stripped = string.to_s.gsub(/\(.*?\)/, '').squeeze(' ')
33
+ begin
34
+ datetime = ::DateTime.parse(stripped)
35
+ rescue ArgumentError => e
36
+ raise unless 'invalid date' == e.message
37
+ end
38
+ end
39
+
40
+ if datetime
41
+ datetime.strftime('%a, %d %b %Y %H:%M:%S %z')
42
+ else
43
+ string
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ klasses = ObjectSpace.each_object(Class).select { |klass| klass < Mail::CommonDate }
50
+ klasses.each do |klass|
51
+ unless klass.included_modules.include?(Mail::Jdec::DateFieldPatch)
52
+ klass.prepend Mail::Jdec::DateFieldPatch
53
+ end
54
+ end
@@ -0,0 +1,59 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ module Mail
4
+
5
+ # ParameterHash is an intelligent Hash that allows you to add
6
+ # parameter values including the MIME extension paramaters that
7
+ # have the name*0="blah", name*1="bleh" keys, and will just return
8
+ # a single key called name="blahbleh" and do any required un-encoding
9
+ # to make that happen
10
+ # Parameters are defined in RFC2045, split keys are in RFC2231
11
+
12
+ class ParameterHash < IndifferentHash
13
+
14
+ include Mail::Utilities
15
+
16
+ def [](key_name)
17
+ key_pattern = Regexp.escape(key_name.to_s)
18
+ pairs = []
19
+ exact = nil
20
+ each do |k,v|
21
+ if k =~ /^#{key_pattern}(\*|$)/i
22
+ if $1 == ASTERISK
23
+ pairs << [k, v]
24
+ else
25
+ exact = k
26
+ end
27
+ end
28
+ end
29
+ if pairs.empty? # Just dealing with a single value pair
30
+ super(exact || key_name)
31
+ else # Dealing with a multiple value pair or a single encoded value pair
32
+ string = pairs.sort_by { |a| a.first.to_s =~ /^([^*]+)\*(\d+)/ ? [$1, $2.to_i] : [a.first.to_s, 0] }.map { |v| v.last }.join('')
33
+ if mt = string.match(/([\w\-]+)?'(\w\w)?'(.*)/)
34
+ string = mt[3]
35
+ encoding = mt[1]
36
+ else
37
+ encoding = nil
38
+ end
39
+ Mail::Encodings.param_decode(string, encoding)
40
+ end
41
+ end
42
+
43
+ def encoded
44
+ map.sort_by { |a| a.first.to_s =~ /^([^*]+)\*(\d+)/ ? [$1, $2.to_i] : [a.first.to_s, 0] }.map! do |key_name, value|
45
+ unless value.ascii_only?
46
+ value = Mail::Encodings.param_encode(value)
47
+ key_name = "#{key_name}*"
48
+ end
49
+ %Q{#{key_name}=#{quote_token(value)}}
50
+ end.join(";\r\n\s")
51
+ end
52
+
53
+ def decoded
54
+ map.sort_by { |a| a.first.to_s =~ /^([^*]+)\*(\d+)/ ? [$1, $2.to_i] : [a.first.to_s, 0] }.map! do |key_name, value|
55
+ %Q{#{key_name}=#{quote_token(value)}}
56
+ end.join("; ")
57
+ end
58
+ end
59
+ end
@@ -11,6 +11,21 @@ module Mail
11
11
  end
12
12
  super
13
13
  end
14
+
15
+ def transcode_charset(str, from_encoding, to_encoding = Encoding::UTF_8)
16
+ if Jdec.enabled?
17
+ case from_encoding.to_s.downcase
18
+ when 'unicode-1-1-utf-7'
19
+ str = Decoder.decode_utf7(str).encode(to_encoding, undef: :replace, invalid: :replace)
20
+ else
21
+ str = super
22
+ end
23
+ str.strip! if to_encoding.to_s.downcase == 'utf-8'
24
+ str
25
+ else
26
+ super
27
+ end
28
+ end
14
29
  end
15
30
  end
16
31
  end
@@ -1,5 +1,5 @@
1
1
  module Mail
2
2
  module Jdec
3
- VERSION = '1.0.3'
3
+ VERSION = '1.0.4'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mail-jdec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yoshikazu Kaneta
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-02-06 00:00:00.000000000 Z
11
+ date: 2019-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mail
@@ -99,11 +99,15 @@ files:
99
99
  - bin/setup
100
100
  - gemfiles/mail27.gemfile
101
101
  - lib/mail/jdec.rb
102
+ - lib/mail/jdec/body_patch.rb
102
103
  - lib/mail/jdec/decoder.rb
103
104
  - lib/mail/jdec/detector.rb
104
105
  - lib/mail/jdec/elements/content_disposition_element_patch.rb
105
106
  - lib/mail/jdec/elements/content_type_element_patch.rb
106
107
  - lib/mail/jdec/encodings_patch.rb
108
+ - lib/mail/jdec/fields/address_field_patch.rb
109
+ - lib/mail/jdec/fields/date_field_patch.rb
110
+ - lib/mail/jdec/fields/parameter_hash_patch.rb
107
111
  - lib/mail/jdec/fields/references_field_patch.rb
108
112
  - lib/mail/jdec/fields/structured_field_patch.rb
109
113
  - lib/mail/jdec/fields/unstructured_field_patch.rb