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 +4 -4
- data/CHANGELOG.md +10 -0
- data/lib/mail/jdec/body_patch.rb +19 -0
- data/lib/mail/jdec/decoder.rb +10 -0
- data/lib/mail/jdec/elements/content_disposition_element_patch.rb +23 -7
- data/lib/mail/jdec/elements/content_type_element_patch.rb +20 -2
- data/lib/mail/jdec/fields/address_field_patch.rb +27 -0
- data/lib/mail/jdec/fields/date_field_patch.rb +54 -0
- data/lib/mail/jdec/fields/parameter_hash_patch.rb +59 -0
- data/lib/mail/jdec/ruby_1_9_patch.rb +15 -0
- data/lib/mail/jdec/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 880f1f6ecdd0e34f0844fe398d29bfcb13587c5a93aef0b2bcd42e1a7dbb6319
|
4
|
+
data.tar.gz: 9a135d5433d8cb1af49178d9e0a80a2884a1955d59f5391c0beac9417d343715
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/mail/jdec/decoder.rb
CHANGED
@@ -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
|
-
|
9
|
-
|
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
|
-
#
|
7
|
-
string = string.gsub(
|
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
|
data/lib/mail/jdec/version.rb
CHANGED
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.
|
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-
|
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
|