mirror of
https://github.com/nodemailer/wildduck.git
synced 2024-09-20 07:16:05 +08:00
fix(mime-parsing): ensure that text content for multipart nodes always ends with a newline. Fixes #571
This commit is contained in:
parent
e553523df3
commit
6f4994d3a0
|
@ -58,4 +58,5 @@ module.exports = function (grunt) {
|
||||||
// Tasks
|
// Tasks
|
||||||
grunt.registerTask('default', ['eslint', 'shell:server', 'wait:server', 'mochaTest', 'shell:server:kill']);
|
grunt.registerTask('default', ['eslint', 'shell:server', 'wait:server', 'mochaTest', 'shell:server:kill']);
|
||||||
grunt.registerTask('testonly', ['shell:server', 'wait:server', 'mochaTest', 'shell:server:kill']);
|
grunt.registerTask('testonly', ['shell:server', 'wait:server', 'mochaTest', 'shell:server:kill']);
|
||||||
|
grunt.registerTask('proto', ['mochaTest:imap']);
|
||||||
};
|
};
|
||||||
|
|
|
@ -125,6 +125,23 @@ class MIMEParser {
|
||||||
node.message = parse(node.body.join(''));
|
node.message = parse(node.body.join(''));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node.body && node.body.length && node.multipart) {
|
||||||
|
// find last character from an array of strings
|
||||||
|
let lastChar;
|
||||||
|
let lastIndex = 0;
|
||||||
|
for (let i = node.body.length - 1; i >= 0; i--) {
|
||||||
|
if (typeof node.body[i] === 'string' && node.body[i].length) {
|
||||||
|
lastChar = node.body[i].at(-1);
|
||||||
|
lastIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastChar && lastChar !== '\n') {
|
||||||
|
// ensure that non-multipart body text always ends with a newline
|
||||||
|
node.body[lastIndex] += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node.lineCount = node.body.length ? node.body.length - 1 : 0;
|
node.lineCount = node.body.length ? node.body.length - 1 : 0;
|
||||||
node.body = Buffer.from(
|
node.body = Buffer.from(
|
||||||
node.body
|
node.body
|
||||||
|
|
22
imap-core/test/fixtures/no_empty_line_between_text_boundary.eml
vendored
Normal file
22
imap-core/test/fixtures/no_empty_line_between_text_boundary.eml
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Content-Type: multipart/mixed; boundary="------------cWFvDSey27tFG0hVYLqp9hs9"
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <beep-boop@example-1.com>
|
||||||
|
To: foo-1@example-1.com
|
||||||
|
From: foo-1@example-1.com
|
||||||
|
Subject: test
|
||||||
|
|
||||||
|
This is a multi-part message in MIME format.
|
||||||
|
--------------cWFvDSey27tFG0hVYLqp9hs9
|
||||||
|
Content-Type: text/plain; charset=UTF-8; format=flowed
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
test
|
||||||
|
|
||||||
|
--------------cWFvDSey27tFG0hVYLqp9hs9
|
||||||
|
Content-Type: text/plain; charset=UTF-8; name="example.txt"
|
||||||
|
Content-Disposition: attachment; filename="example.txt"
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
ZXhhbXBsZQo=
|
||||||
|
|
||||||
|
--------------cWFvDSey27tFG0hVYLqp9hs9--
|
22
imap-core/test/fixtures/no_empty_line_between_text_boundary.eml.2
vendored
Normal file
22
imap-core/test/fixtures/no_empty_line_between_text_boundary.eml.2
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Content-Type: multipart/mixed; boundary="------------cWFvDSey27tFG0hVYLqp9hs9"
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <beep-boop@example-1.com>
|
||||||
|
To: foo-1@example-1.com
|
||||||
|
From: foo-1@example-1.com
|
||||||
|
Subject: test
|
||||||
|
|
||||||
|
This is a multi-part message in MIME format.
|
||||||
|
--------------cWFvDSey27tFG0hVYLqp9hs9
|
||||||
|
Content-Type: text/plain; charset=UTF-8; format=flowed
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
test
|
||||||
|
|
||||||
|
--------------cWFvDSey27tFG0hVYLqp9hs9
|
||||||
|
Content-Type: text/plain; charset=UTF-8; name="example.txt"
|
||||||
|
Content-Disposition: attachment; filename="example.txt"
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
ZXhhbXBsZQo=
|
||||||
|
|
||||||
|
--------------cWFvDSey27tFG0hVYLqp9hs9--
|
|
@ -3,11 +3,20 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const MIMEParser = require('../lib/indexer/parse-mime-tree').MIMEParser;
|
const MIMEParser = require('../lib/indexer/parse-mime-tree').MIMEParser;
|
||||||
|
const Indexer = require('../lib/indexer/indexer');
|
||||||
|
const indexer = new Indexer();
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
const chai = require('chai');
|
const chai = require('chai');
|
||||||
const expect = chai.expect;
|
const expect = chai.expect;
|
||||||
chai.config.includeStack = true;
|
chai.config.includeStack = true;
|
||||||
|
|
||||||
|
const fixtures = {
|
||||||
|
no_empty_line_between_text_boundary: {
|
||||||
|
eml: fs.readFileSync(__dirname + '/fixtures/no_empty_line_between_text_boundary.eml')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
describe('#parseValueParams', function () {
|
describe('#parseValueParams', function () {
|
||||||
it('should return continuation value as mime-word', function () {
|
it('should return continuation value as mime-word', function () {
|
||||||
let parser = new MIMEParser();
|
let parser = new MIMEParser();
|
||||||
|
@ -44,4 +53,23 @@ describe('#parseValueParams', function () {
|
||||||
hasParams: true
|
hasParams: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should parse a file with no empty line between text and boundary', function (done) {
|
||||||
|
// parse a file and then make sure that boundary is correct
|
||||||
|
|
||||||
|
let source = Buffer.concat([fixtures.no_empty_line_between_text_boundary.eml]);
|
||||||
|
|
||||||
|
let parser = new MIMEParser(source);
|
||||||
|
|
||||||
|
parser.parse();
|
||||||
|
parser.finalizeTree();
|
||||||
|
|
||||||
|
let parsed = parser.tree.childNodes[0];
|
||||||
|
|
||||||
|
indexer.bodyQuery(parsed, '', (err, data) => {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
expect(data.toString().indexOf('This is a multi-part message in MIME format.\r\n--------------cWFvDSey27tFG0hVYLqp9hs9')).to.gt(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "mongo --eval 'db.dropDatabase()' wildduck-test && redis-cli -n 13 flushdb && npm run runtest",
|
"test": "mongo --eval 'db.dropDatabase()' wildduck-test && redis-cli -n 13 flushdb && npm run runtest",
|
||||||
|
"test:proto": "NODE_ENV=test grunt proto",
|
||||||
"printconf": "NODE_CONFIG_ONLY=true npm start",
|
"printconf": "NODE_CONFIG_ONLY=true npm start",
|
||||||
"runtest": "NODE_ENV=test grunt",
|
"runtest": "NODE_ENV=test grunt",
|
||||||
"runci": "npm run printconf && npm run runtest",
|
"runci": "npm run printconf && npm run runtest",
|
||||||
|
|
Loading…
Reference in a new issue