mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2026-02-04 08:18:34 +00:00
feat(GODT-3113): Only force UTF-8 charset for HTML part when needed.
This commit is contained in:
@ -197,9 +197,6 @@ func convertForeignEncodings(p *parser.Parser) error {
|
|||||||
|
|
||||||
return p.NewWalker().
|
return p.NewWalker().
|
||||||
RegisterContentTypeHandler("text/html", func(p *parser.Part) error {
|
RegisterContentTypeHandler("text/html", func(p *parser.Part) error {
|
||||||
if p.IsAttachment() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := p.ConvertToUTF8(); err != nil {
|
if err := p.ConvertToUTF8(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,6 +41,8 @@ type Part struct {
|
|||||||
children Parts
|
children Parts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const utf8Charset = "UTF-8"
|
||||||
|
|
||||||
func (p *Part) ContentType() (string, map[string]string, error) {
|
func (p *Part) ContentType() (string, map[string]string, error) {
|
||||||
t, params, err := p.Header.ContentType()
|
t, params, err := p.Header.ContentType()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -116,7 +118,7 @@ func (p *Part) ConvertToUTF8() error {
|
|||||||
params = make(map[string]string)
|
params = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
params["charset"] = "UTF-8"
|
params["charset"] = utf8Charset
|
||||||
|
|
||||||
p.Header.SetContentType(t, params)
|
p.Header.SetContentType(t, params)
|
||||||
|
|
||||||
@ -129,6 +131,8 @@ func (p *Part) ConvertMetaCharset() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Override charset to UTF-8 in meta headers only if needed.
|
||||||
|
var metaModified = false
|
||||||
goquery.NewDocumentFromNode(doc).Find("meta").Each(func(n int, sel *goquery.Selection) {
|
goquery.NewDocumentFromNode(doc).Find("meta").Each(func(n int, sel *goquery.Selection) {
|
||||||
if val, ok := sel.Attr("content"); ok {
|
if val, ok := sel.Attr("content"); ok {
|
||||||
t, params, err := pmmime.ParseMediaType(val)
|
t, params, err := pmmime.ParseMediaType(val)
|
||||||
@ -136,24 +140,31 @@ func (p *Part) ConvertMetaCharset() error {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
params["charset"] = "UTF-8"
|
if charset, ok := params["charset"]; ok && charset != utf8Charset {
|
||||||
|
params["charset"] = utf8Charset
|
||||||
|
}
|
||||||
|
|
||||||
sel.SetAttr("content", mime.FormatMediaType(t, params))
|
sel.SetAttr("content", mime.FormatMediaType(t, params))
|
||||||
|
metaModified = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := sel.Attr("charset"); ok {
|
if charset, ok := sel.Attr("charset"); ok && charset != utf8Charset {
|
||||||
sel.SetAttr("charset", "UTF-8")
|
sel.SetAttr("charset", utf8Charset)
|
||||||
|
metaModified = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
// Override the body part only if modification was applied
|
||||||
|
// as html.render will sanitise the html headers.
|
||||||
|
if metaModified {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
if err := html.Render(buf, doc); err != nil {
|
if err := html.Render(buf, doc); err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Body = buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Body = buf.Bytes()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -431,7 +431,7 @@ func TestParseTextHTML(t *testing.T) {
|
|||||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||||
assert.Equal(t, `"Receiver" <receiver@pm.me>`, m.ToList[0].String())
|
assert.Equal(t, `"Receiver" <receiver@pm.me>`, m.ToList[0].String())
|
||||||
|
|
||||||
assert.Equal(t, "<html><head></head><body>This is body of <b>HTML mail</b> without attachment</body></html>", string(m.RichBody))
|
assert.Equal(t, "<html><body>This is body of <b>HTML mail</b> without attachment</body></html>", string(m.RichBody))
|
||||||
assert.Equal(t, "This is body of *HTML mail* without attachment", string(m.PlainBody))
|
assert.Equal(t, "This is body of *HTML mail* without attachment", string(m.PlainBody))
|
||||||
|
|
||||||
assert.Len(t, m.Attachments, 0)
|
assert.Len(t, m.Attachments, 0)
|
||||||
@ -446,7 +446,7 @@ func TestParseTextHTMLAlready7Bit(t *testing.T) {
|
|||||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||||
assert.Equal(t, `"Receiver" <receiver@pm.me>`, m.ToList[0].String())
|
assert.Equal(t, `"Receiver" <receiver@pm.me>`, m.ToList[0].String())
|
||||||
|
|
||||||
assert.Equal(t, "<html><head></head><body>This is body of <b>HTML mail</b> without attachment</body></html>", string(m.RichBody))
|
assert.Equal(t, "<html><body>This is body of <b>HTML mail</b> without attachment</body></html>", string(m.RichBody))
|
||||||
assert.Equal(t, "This is body of *HTML mail* without attachment", string(m.PlainBody))
|
assert.Equal(t, "This is body of *HTML mail* without attachment", string(m.PlainBody))
|
||||||
|
|
||||||
assert.Len(t, m.Attachments, 0)
|
assert.Len(t, m.Attachments, 0)
|
||||||
@ -461,7 +461,7 @@ func TestParseTextHTMLWithOctetAttachment(t *testing.T) {
|
|||||||
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
assert.Equal(t, `"Sender" <sender@pm.me>`, m.Sender.String())
|
||||||
assert.Equal(t, `"Receiver" <receiver@pm.me>`, m.ToList[0].String())
|
assert.Equal(t, `"Receiver" <receiver@pm.me>`, m.ToList[0].String())
|
||||||
|
|
||||||
assert.Equal(t, "<html><head></head><body>This is body of <b>HTML mail</b> with attachment</body></html>", string(m.RichBody))
|
assert.Equal(t, "<html><body>This is body of <b>HTML mail</b> with attachment</body></html>", string(m.RichBody))
|
||||||
assert.Equal(t, "This is body of *HTML mail* with attachment", string(m.PlainBody))
|
assert.Equal(t, "This is body of *HTML mail* with attachment", string(m.PlainBody))
|
||||||
|
|
||||||
require.Len(t, m.Attachments, 1)
|
require.Len(t, m.Attachments, 1)
|
||||||
@ -478,7 +478,7 @@ func TestParseTextHTMLWithPlainAttachment(t *testing.T) {
|
|||||||
assert.Equal(t, `"Receiver" <receiver@pm.me>`, m.ToList[0].String())
|
assert.Equal(t, `"Receiver" <receiver@pm.me>`, m.ToList[0].String())
|
||||||
|
|
||||||
// BAD: plainBody should not be empty!
|
// BAD: plainBody should not be empty!
|
||||||
assert.Equal(t, "<html><head></head><body>This is body of <b>HTML mail</b> with attachment</body></html>", string(m.RichBody))
|
assert.Equal(t, "<html><body>This is body of <b>HTML mail</b> with attachment</body></html>", string(m.RichBody))
|
||||||
assert.Equal(t, "This is body of *HTML mail* with attachment", string(m.PlainBody))
|
assert.Equal(t, "This is body of *HTML mail* with attachment", string(m.PlainBody))
|
||||||
|
|
||||||
require.Len(t, m.Attachments, 1)
|
require.Len(t, m.Attachments, 1)
|
||||||
@ -496,7 +496,7 @@ func TestParseTextHTMLWithImageInline(t *testing.T) {
|
|||||||
|
|
||||||
require.Len(t, m.Attachments, 1)
|
require.Len(t, m.Attachments, 1)
|
||||||
|
|
||||||
assert.Equal(t, fmt.Sprintf(`<html><head></head><body>This is body of <b>HTML mail</b> with attachment</body></html><html><body><img src="cid:%v"/></body></html>`, m.Attachments[0].ContentID), string(m.RichBody))
|
assert.Equal(t, fmt.Sprintf(`<html><body>This is body of <b>HTML mail</b> with attachment</body></html><html><body><img src="cid:%v"/></body></html>`, m.Attachments[0].ContentID), string(m.RichBody))
|
||||||
assert.Equal(t, "This is body of *HTML mail* with attachment", string(m.PlainBody))
|
assert.Equal(t, "This is body of *HTML mail* with attachment", string(m.PlainBody))
|
||||||
|
|
||||||
// The inline image is an 8x8 mic-dropping gopher.
|
// The inline image is an 8x8 mic-dropping gopher.
|
||||||
@ -627,7 +627,7 @@ func TestParseWithTrailingEndOfMailIndicator(t *testing.T) {
|
|||||||
assert.Equal(t, `"Sender" <sender@sender.com>`, m.Sender.String())
|
assert.Equal(t, `"Sender" <sender@sender.com>`, m.Sender.String())
|
||||||
assert.Equal(t, `"Receiver" <receiver@receiver.com>`, m.ToList[0].String())
|
assert.Equal(t, `"Receiver" <receiver@receiver.com>`, m.ToList[0].String())
|
||||||
|
|
||||||
assert.Equal(t, "<!DOCTYPE html><html><head></head><body>boo!</body></html>", string(m.RichBody))
|
assert.Equal(t, "<!DOCTYPE HTML>\n<html><body>boo!</body></html>", string(m.RichBody))
|
||||||
assert.Equal(t, "boo!", string(m.PlainBody))
|
assert.Equal(t, "boo!", string(m.PlainBody))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -241,6 +241,7 @@ Feature: SMTP sending of HTMl messages to Internal recipient
|
|||||||
{
|
{
|
||||||
"content-type": "application/pgp-keys",
|
"content-type": "application/pgp-keys",
|
||||||
"content-disposition": "attachment",
|
"content-disposition": "attachment",
|
||||||
|
|
||||||
"transfer-encoding": "base64"
|
"transfer-encoding": "base64"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -763,7 +764,7 @@ Feature: SMTP sending of HTMl messages to Internal recipient
|
|||||||
"content-disposition": "attachment",
|
"content-disposition": "attachment",
|
||||||
"content-disposition-filename": "index.html",
|
"content-disposition-filename": "index.html",
|
||||||
"transfer-encoding": "base64",
|
"transfer-encoding": "base64",
|
||||||
"body-is": "PCFET0NUWVBFIGh0bWw+PGh0bWw+PGhlYWQ+Cjx0aXRsZT5QYWdlIFRpdGxlPC90aXRsZT4KPC9o\r\nZWFkPgo8Ym9keT4KCjxoMT5NeSBGaXJzdCBIZWFkaW5nPC9oMT4KPHA+TXkgZmlyc3QgcGFyYWdy\r\nYXBoLjwvcD4KCgogPC9ib2R5PjwvaHRtbD4="
|
"body-is": "IDwhRE9DVFlQRSBodG1sPg0KPGh0bWw+DQo8aGVhZD4NCjx0aXRsZT5QYWdlIFRpdGxlPC90aXRs\r\nZT4NCjwvaGVhZD4NCjxib2R5Pg0KDQo8aDE+TXkgRmlyc3QgSGVhZGluZzwvaDE+DQo8cD5NeSBm\r\naXJzdCBwYXJhZ3JhcGguPC9wPg0KDQo8L2JvZHk+DQo8L2h0bWw+IA=="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"content-type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
"content-type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
@ -1070,7 +1071,6 @@ Feature: SMTP sending of HTMl messages to Internal recipient
|
|||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
Scenario: Replying to a message after enabling attach public key
|
Scenario: Replying to a message after enabling attach public key
|
||||||
When SMTP client "1" sends the following message from "[user:user]@[domain]" to "[user:to]@[domain]":
|
When SMTP client "1" sends the following message from "[user:user]@[domain]" to "[user:to]@[domain]":
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -1242,7 +1242,7 @@ Feature: SMTP sending of PLAIN messages to Internal recipient
|
|||||||
"content-disposition": "attachment",
|
"content-disposition": "attachment",
|
||||||
"content-disposition-filename": "index.html",
|
"content-disposition-filename": "index.html",
|
||||||
"transfer-encoding": "base64",
|
"transfer-encoding": "base64",
|
||||||
"body-is": "PCFET0NUWVBFIGh0bWw+PGh0bWw+PGhlYWQ+Cjx0aXRsZT5QYWdlIFRpdGxlPC90aXRsZT4KPC9o\r\nZWFkPgo8Ym9keT4KCjxoMT5NeSBGaXJzdCBIZWFkaW5nPC9oMT4KPHA+TXkgZmlyc3QgcGFyYWdy\r\nYXBoLjwvcD4KCgogPC9ib2R5PjwvaHRtbD4="
|
"body-is": "IDwhRE9DVFlQRSBodG1sPg0KPGh0bWw+DQo8aGVhZD4NCjx0aXRsZT5QYWdlIFRpdGxlPC90aXRs\r\nZT4NCjwvaGVhZD4NCjxib2R5Pg0KDQo8aDE+TXkgRmlyc3QgSGVhZGluZzwvaDE+DQo8cD5NeSBm\r\naXJzdCBwYXJhZ3JhcGguPC9wPg0KDQo8L2JvZHk+DQo8L2h0bWw+IA=="
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"content-type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
"content-type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
|||||||
Reference in New Issue
Block a user