libmime 2.0.3 → 2.1.3

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.
package/.eslintrc.js CHANGED
@@ -45,7 +45,8 @@ module.exports = {
45
45
  'no-bitwise': 2,
46
46
  'no-lonely-if': 2,
47
47
  'no-mixed-spaces-and-tabs': 2,
48
- 'no-console': 2
48
+ 'no-console': 2,
49
+ 'no-control-regex': 0
49
50
  },
50
51
  env: {
51
52
  es6: false,
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## v2.1.3 2016-12-08
4
+
5
+ * Revert dot as a special symbol
6
+
7
+ ## v2.1.2 2016-11-21
8
+
9
+ * Quote special symbols as defined in RFC (surajwy)
10
+
11
+ ## v2.1.1 2016-11-15
12
+
13
+ * Fixed issue with special symbols in attachment filenames
14
+
15
+ ## v2.1.0 2016-07-24
16
+
17
+ * Changed handling of base64 encoded mime words where multiple words are joined together if possible. This fixes issues with multi byte characters getting split into different mime words (against the RFC but occurs)
18
+
3
19
  ## v2.0.3 2016-02-29
4
20
 
5
21
  * Fixed an issue with rfc2231 filenames
package/lib/charset.js CHANGED
@@ -72,7 +72,7 @@ var charset = module.exports = {
72
72
  return 'UTF-' + match[1];
73
73
  }
74
74
 
75
- if ((match = charset.match(/^win[\-_]?(\d+)$/i))) {
75
+ if ((match = charset.match(/^win(?:dows)?[\-_]?(\d+)$/i))) {
76
76
  return 'WINDOWS-' + match[1];
77
77
  }
78
78
 
package/lib/libmime.js CHANGED
@@ -184,7 +184,15 @@ var libmime = module.exports = {
184
184
  fromCharset = match[1].split('*').shift();
185
185
 
186
186
  encoding = (match[2] || 'Q').toString().toUpperCase();
187
- str = (match[3] || '').replace(/_/g, ' ').replace(/ $/, '=20');
187
+ str = (match[3] || '');
188
+
189
+ if (encoding === 'Q') {
190
+ // remove spaces between = and hex char, this might indicate invalidly applied line splitting
191
+ str = str.replace(/=\s+([0-9a-fA-F])/, '=$1');
192
+ }
193
+
194
+ // convert all underscores to spaces
195
+ str = str.replace(/_/g, ' ').replace(/ $/, '=20');
188
196
 
189
197
  if (encoding === 'B') {
190
198
  return libcharset.decode(libbase64.decode(str), fromCharset);
@@ -229,14 +237,40 @@ var libmime = module.exports = {
229
237
  * @return {String} Decoded unicode string
230
238
  */
231
239
  decodeWords: function (str) {
232
- str = (str || '').toString();
233
- str = str.
240
+ return (str || '').toString().
241
+
242
+ // find base64 words that can be joined
243
+ replace(/(=\?([^?]+)\?[Bb]\?[^?]+[^^=]\?=)\s*(?==\?([^?]+)\?[Bb]\?[^?]+\?=)/g,
244
+ function (match, left, chLeft, chRight) {
245
+ // only mark b64 chunks to be joined if charsets match
246
+ if (libcharset.normalizeCharset(chLeft || '').toLowerCase().trim() === libcharset.normalizeCharset(chRight || '').toLowerCase().trim()) {
247
+ // set a joiner marker
248
+ return left + '__\x00JOIN\x00__';
249
+ }
250
+ return match;
251
+ }).
252
+
253
+ // find QP words that can be joined
254
+ replace(/(=\?([^?]+)\?[Qq]\?[^?]+\?=)\s*(?==\?([^?]+)\?[Qq]\?[^?]+\?=)/g,
255
+ function (match, left, chLeft, chRight) {
256
+ // only mark QP chunks to be joined if charsets match
257
+ if (libcharset.normalizeCharset(chLeft || '').toLowerCase().trim() === libcharset.normalizeCharset(chRight || '').toLowerCase().trim()) {
258
+ // set a joiner marker
259
+ return left + '__\x00JOIN\x00__';
260
+ }
261
+ return match;
262
+ }).
263
+
264
+ // join base64 encoded words
265
+ replace(/(\?=)?__\x00JOIN\x00__(=\?([^?]+)\?[QqBb]\?)?/g, '').
266
+
267
+ // remove spaces between mime encoded words
234
268
  replace(/(=\?[^?]+\?[QqBb]\?[^?]+\?=)\s+(?==\?[^?]+\?[QqBb]\?[^?]+\?=)/g, '$1').
269
+
270
+ // decode words
235
271
  replace(/\=\?([\w_\-\*]+)\?([QqBb])\?[^\?]+\?\=/g, function (mimeWord) {
236
272
  return libmime.decodeWord(mimeWord);
237
273
  });
238
-
239
- return str;
240
274
  },
241
275
 
242
276
  /**
@@ -293,7 +327,8 @@ var libmime = module.exports = {
293
327
 
294
328
  /**
295
329
  * Joins parsed header value together as 'value; param1=value1; param2=value2'
296
- *
330
+ * PS: We are following RFC 822 for the list of special characters that we need to keep in quotes.
331
+ * Refer: https://www.w3.org/Protocols/rfc1341/4_Content-Type.html
297
332
  * @param {Object} structured Parsed header value
298
333
  * @return {String} joined header value
299
334
  */
@@ -305,13 +340,13 @@ var libmime = module.exports = {
305
340
  var value = structured.params[param];
306
341
  if (!libmime.isPlainText(value) || value.length >= 75) {
307
342
  libmime.buildHeaderParam(param, value, 50).forEach(function (encodedParam) {
308
- if (!/[\s"\\;\/=]|^[\-']|'$/.test(encodedParam.value) || encodedParam.key.substr(-1) === '*') {
343
+ if (!/[\s"\\;:\/=\(\),<>@\[\]\?]|^[\-']|'$/.test(encodedParam.value) || encodedParam.key.substr(-1) === '*') {
309
344
  paramsArray.push(encodedParam.key + '=' + encodedParam.value);
310
345
  } else {
311
346
  paramsArray.push(encodedParam.key + '=' + JSON.stringify(encodedParam.value));
312
347
  }
313
348
  });
314
- } else if (/[\s'"\\;\/=]|^\-/.test(value)) {
349
+ } else if (/[\s'"\\;:\/=\(\),<>@\[\]\?]|^\-/.test(value)) {
315
350
  paramsArray.push(param + '=' + JSON.stringify(value));
316
351
  } else {
317
352
  paramsArray.push(param + '=' + value);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "libmime",
3
3
  "description": "Encode and decode quoted printable and base64 strings",
4
- "version": "2.0.3",
4
+ "version": "2.1.3",
5
5
  "main": "lib/libmime",
6
6
  "homepage": "https://github.com/andris9/libmime",
7
7
  "repository": {
@@ -16,19 +16,19 @@
16
16
  ],
17
17
  "author": "Andris Reinman <andris@kreata.ee>",
18
18
  "scripts": {
19
- "test": "grunt"
19
+ "test": "grunt mochaTest"
20
20
  },
21
21
  "dependencies": {
22
- "iconv-lite": "0.4.13",
22
+ "iconv-lite": "0.4.15",
23
23
  "libbase64": "0.1.0",
24
24
  "libqp": "1.1.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "chai": "^3.5.0",
28
- "grunt": "^0.4.5",
29
- "grunt-cli": "^0.1.13",
30
- "grunt-eslint": "^18.0.0",
31
- "grunt-mocha-test": "^0.12.7",
32
- "mocha": "^2.4.5"
28
+ "grunt": "^1.0.1",
29
+ "grunt-cli": "^1.2.0",
30
+ "grunt-eslint": "^19.0.0",
31
+ "grunt-mocha-test": "^0.13.2",
32
+ "mocha": "^3.2.0"
33
33
  }
34
34
  }