mail-jdec 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
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