@mavogel/awscdk-rootmail 0.1.24 → 0.1.25

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.
Files changed (96) hide show
  1. package/.jsii +3 -3
  2. package/lib/rootmail.js +1 -1
  3. package/lib/ses-receive.js +1 -1
  4. package/node_modules/@zone-eu/mailsplit/README.md +1 -1
  5. package/node_modules/@zone-eu/mailsplit/lib/headers.js +10 -4
  6. package/node_modules/@zone-eu/mailsplit/lib/message-splitter.js +5 -4
  7. package/node_modules/@zone-eu/mailsplit/lib/mime-node.d.ts +4 -1
  8. package/node_modules/@zone-eu/mailsplit/lib/mime-node.js +23 -2
  9. package/node_modules/@zone-eu/mailsplit/lib/types.d.ts +3 -1
  10. package/node_modules/@zone-eu/mailsplit/package.json +4 -4
  11. package/node_modules/libbase64/CHANGELOG.md +20 -0
  12. package/node_modules/libbase64/README.md +40 -13
  13. package/node_modules/libbase64/dist/cjs/libbase64.d.ts +80 -0
  14. package/node_modules/libbase64/dist/cjs/libbase64.js +310 -0
  15. package/node_modules/libbase64/dist/cjs/package.json +3 -0
  16. package/node_modules/libbase64/dist/esm/libbase64.d.ts +80 -0
  17. package/node_modules/libbase64/{lib → dist/esm}/libbase64.js +74 -117
  18. package/node_modules/libbase64/dist/esm/package.json +3 -0
  19. package/node_modules/libbase64/package.json +59 -13
  20. package/node_modules/libmime/CHANGELOG.md +31 -0
  21. package/node_modules/libmime/README.md +55 -26
  22. package/node_modules/libmime/SECURITY.md +152 -0
  23. package/node_modules/libmime/dist/cjs/charset.d.ts +43 -0
  24. package/node_modules/libmime/dist/cjs/charset.js +135 -0
  25. package/node_modules/libmime/dist/cjs/charsets.d.ts +2 -0
  26. package/node_modules/libmime/dist/cjs/charsets.js +213 -0
  27. package/node_modules/libmime/dist/cjs/get-charset-name.d.ts +1 -0
  28. package/node_modules/libmime/dist/cjs/get-charset-name.js +224 -0
  29. package/node_modules/libmime/dist/cjs/libmime.d.ts +218 -0
  30. package/node_modules/libmime/dist/cjs/libmime.js +1013 -0
  31. package/node_modules/libmime/dist/cjs/mimetypes.d.ts +7 -0
  32. package/node_modules/libmime/dist/cjs/mimetypes.js +2072 -0
  33. package/node_modules/libmime/dist/cjs/package.json +3 -0
  34. package/node_modules/libmime/dist/cjs/types.d.ts +59 -0
  35. package/node_modules/libmime/dist/cjs/types.js +4 -0
  36. package/node_modules/libmime/dist/esm/charset.d.ts +43 -0
  37. package/node_modules/libmime/dist/esm/charset.js +125 -0
  38. package/node_modules/libmime/dist/esm/charsets.d.ts +2 -0
  39. package/node_modules/libmime/{lib → dist/esm}/charsets.js +3 -5
  40. package/node_modules/libmime/dist/esm/get-charset-name.d.ts +1 -0
  41. package/node_modules/libmime/{lib → dist/esm}/get-charset-name.js +1 -8
  42. package/node_modules/libmime/dist/esm/libmime.d.ts +219 -0
  43. package/node_modules/libmime/{lib → dist/esm}/libmime.js +256 -329
  44. package/node_modules/libmime/dist/esm/mimetypes.d.ts +7 -0
  45. package/node_modules/libmime/dist/esm/mimetypes.js +2068 -0
  46. package/node_modules/libmime/dist/esm/package.json +3 -0
  47. package/node_modules/libmime/dist/esm/types.d.ts +59 -0
  48. package/node_modules/libmime/dist/esm/types.js +3 -0
  49. package/node_modules/libmime/package.json +58 -15
  50. package/node_modules/libqp/CHANGELOG.md +18 -0
  51. package/node_modules/libqp/README.md +50 -19
  52. package/node_modules/libqp/dist/cjs/libqp.d.ts +74 -0
  53. package/node_modules/libqp/dist/cjs/libqp.js +378 -0
  54. package/node_modules/libqp/dist/cjs/package.json +3 -0
  55. package/node_modules/libqp/dist/esm/libqp.d.ts +74 -0
  56. package/node_modules/libqp/dist/esm/libqp.js +369 -0
  57. package/node_modules/libqp/dist/esm/package.json +3 -0
  58. package/node_modules/libqp/lib/libqp.js +4 -383
  59. package/node_modules/libqp/lib/package.json +3 -0
  60. package/node_modules/libqp/package.json +62 -6
  61. package/node_modules/mailparser/.release-please-manifest.json +1 -1
  62. package/node_modules/mailparser/CHANGELOG.md +42 -0
  63. package/node_modules/mailparser/package.json +5 -5
  64. package/node_modules/nodemailer/CHANGELOG.md +44 -0
  65. package/node_modules/nodemailer/dist/cjs/addressparser/index.js +695 -267
  66. package/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +4 -1
  67. package/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +8 -2
  68. package/node_modules/nodemailer/dist/cjs/mime-node/index.js +48 -16
  69. package/node_modules/nodemailer/dist/cjs/package-info.d.ts +1 -1
  70. package/node_modules/nodemailer/dist/cjs/package-info.js +1 -1
  71. package/node_modules/nodemailer/dist/cjs/shared/url.js +22 -5
  72. package/node_modules/nodemailer/dist/esm/addressparser/index.js +695 -267
  73. package/node_modules/nodemailer/dist/esm/mailer/mail-message.js +4 -1
  74. package/node_modules/nodemailer/dist/esm/mime-funcs/index.js +8 -2
  75. package/node_modules/nodemailer/dist/esm/mime-node/index.js +48 -16
  76. package/node_modules/nodemailer/dist/esm/package-info.d.ts +1 -1
  77. package/node_modules/nodemailer/dist/esm/package-info.js +1 -1
  78. package/node_modules/nodemailer/dist/esm/shared/url.js +22 -5
  79. package/node_modules/nodemailer/package.json +1 -1
  80. package/package.json +2 -2
  81. package/node_modules/libbase64/.eslintrc +0 -11
  82. package/node_modules/libbase64/.github/FUNDING.yml +0 -4
  83. package/node_modules/libbase64/.github/VULNERABILITY_REPORT.yml +0 -75
  84. package/node_modules/libbase64/.github/workflows/release.yaml +0 -39
  85. package/node_modules/libbase64/.github/workflows/test.yml +0 -21
  86. package/node_modules/libbase64/.ncurc.js +0 -13
  87. package/node_modules/libbase64/.prettierrc.js +0 -8
  88. package/node_modules/libmime/lib/charset.js +0 -131
  89. package/node_modules/libmime/lib/mimetypes.js +0 -2049
  90. package/node_modules/libqp/.eslintrc +0 -15
  91. package/node_modules/libqp/.github/FUNDING.yml +0 -4
  92. package/node_modules/libqp/.github/VULNERABILITY_REPORT.yml +0 -75
  93. package/node_modules/libqp/.github/workflows/release.yaml +0 -39
  94. package/node_modules/libqp/.github/workflows/test.yml +0 -21
  95. package/node_modules/libqp/.prettierrc.js +0 -8
  96. package/node_modules/libqp/test/libqp-test.js +0 -366
@@ -145,7 +145,10 @@ export default class MailMessage {
145
145
  const values = [data.html, data.text, data.watchHtml, data.amp, data.raw, data.icalEvent];
146
146
  for (const key of ['attachments', 'alternatives']) {
147
147
  if (Array.isArray(data[key])) {
148
- values.push(...data[key]);
148
+ // one at a time, spreading a long enough list into the arguments throws
149
+ for (const entry of data[key]) {
150
+ values.push(entry);
151
+ }
149
152
  }
150
153
  }
151
154
  for (const value of values) {
@@ -21,6 +21,12 @@ export function isPlainText(value, isParam) {
21
21
  const re = isParam ? /[\x00-\x1f\x7f"\u0080-\uFFFF]/ : /[\x00-\x08\x0b\x0c\x0e-\x1f\u0080-\uFFFF]/;
22
22
  return typeof value === 'string' && !re.test(value);
23
23
  }
24
+ // A parameter value goes out as is only when it is plain text that does not look like an encoded
25
+ // word. Receivers decode encoded words found in parameter values (libmime does so for unencoded
26
+ // continuations), so as plain text it would come back as something else
27
+ function isPlainParamValue(value) {
28
+ return isPlainText(value, true) && !value.includes('=?');
29
+ }
24
30
  /**
25
31
  * Wraps a value into a quoted-string. Inside one a quote would end the string early
26
32
  * and a backslash would escape whatever follows it, so both go out as quoted-pairs.
@@ -188,7 +194,7 @@ export function buildHeaderValue(structured) {
188
194
  const value = structured.params[key];
189
195
  // a parameter name is a token too and it is emitted without any quoting around it
190
196
  const param = key.replace(/[\x00-\x1f\x7f]/g, '');
191
- if (!isPlainText(value, true) || value.length >= 75) {
197
+ if (!isPlainParamValue(value) || value.length >= 75) {
192
198
  buildHeaderParam(param, value, 50).forEach(encodedParam => {
193
199
  if (!/[\s"\\;:/=(),<>@[\]?]|^[-']|'$/.test(encodedParam.value) || encodedParam.key.substr(-1) === '*') {
194
200
  paramsArray.push(encodedParam.key + '=' + encodedParam.value);
@@ -237,7 +243,7 @@ export function buildHeaderParam(key, data, maxLength) {
237
243
  let i, len;
238
244
  maxLength = maxLength || 50;
239
245
  // process ascii only text
240
- if (isPlainText(data, true)) {
246
+ if (isPlainParamValue(data)) {
241
247
  // check if conversion is even needed
242
248
  if (encodedStr.length <= maxLength) {
243
249
  return [
@@ -26,6 +26,35 @@ const QUOTED_STRING = /^"(?:[^"\\]|\\[\s\S])*"$/;
26
26
  // else goes into angle brackets so that the header can not be read as more addresses than
27
27
  // the envelope carries
28
28
  const PLAIN_ADDRESS = /^[^\s"(),:;<>@[\\\]]+@[^\s"(),:;<>@[\\\]]+$/;
29
+ /**
30
+ * A domain literal that ends an address, see _normalizeAddress
31
+ */
32
+ const DOMAIN_LITERAL_TAIL = /@(\[[^[\]\\]*\])$/;
33
+ /**
34
+ * Removes the whitespace inside every <...> of a References value. A "<" with no ">" after
35
+ * it is left as it is. An index scan, the regex /<[^>]*>/g rescans the rest of the value
36
+ * from every such "<"
37
+ *
38
+ * @param value References header value
39
+ * @returns The value with the msg-ids closed up
40
+ */
41
+ function stripWhitespaceInAngleBrackets(value) {
42
+ let result = '';
43
+ let pos = 0;
44
+ for (;;) {
45
+ const open = value.indexOf('<', pos);
46
+ if (open < 0) {
47
+ break;
48
+ }
49
+ const close = value.indexOf('>', open + 1);
50
+ if (close < 0) {
51
+ break;
52
+ }
53
+ result += value.slice(pos, open) + value.slice(open, close + 1).replace(/\s/g, '');
54
+ pos = close + 1;
55
+ }
56
+ return result + value.slice(pos);
57
+ }
29
58
  // domainToASCII and domainToUnicode are WHATWG host parsers rather than plain IDNA
30
59
  // mappers, so they do more than map: they cut the host at '/', '\\', '?' and '#', drop C0
31
60
  // controls, and percent-decode. Handing them 'evil.example/mail.corp.example' returns the
@@ -1319,26 +1348,26 @@ class MimeNode {
1319
1348
  }
1320
1349
  return value;
1321
1350
  // space separated list of values enclosed in <>
1322
- case 'References':
1323
- value = [].concat
1324
- .apply([], [].concat(value || '').map(elm => {
1325
- elm = (elm || '')
1351
+ case 'References': {
1352
+ const ids = [];
1353
+ for (const entry of [].concat(value || '')) {
1354
+ const elm = (entry || '')
1326
1355
  .toString()
1327
1356
  .replace(/\r?\n|\r/g, ' ')
1328
1357
  .replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '')
1329
1358
  .trim();
1330
- return elm.replace(/<[^>]*>/g, str => str.replace(/\s/g, '')).split(/\s+/);
1331
- }))
1332
- .map(elm => {
1333
- if (elm.charAt(0) !== '<') {
1334
- elm = '<' + elm;
1335
- }
1336
- if (elm.charAt(elm.length - 1) !== '>') {
1337
- elm = elm + '>';
1359
+ for (let id of stripWhitespaceInAngleBrackets(elm).split(/\s+/)) {
1360
+ if (id.charAt(0) !== '<') {
1361
+ id = '<' + id;
1362
+ }
1363
+ if (id.charAt(id.length - 1) !== '>') {
1364
+ id = id + '>';
1365
+ }
1366
+ ids.push(id);
1338
1367
  }
1339
- return elm;
1340
- });
1341
- return value.join(' ').trim();
1368
+ }
1369
+ return ids.join(' ').trim();
1370
+ }
1342
1371
  case 'Date':
1343
1372
  if (Object.prototype.toString.call(value) === '[object Date]') {
1344
1373
  return value.toUTCString().replace(/GMT/, '+0000');
@@ -1417,7 +1446,10 @@ class MimeNode {
1417
1446
  // callers use an empty value to detect a missing address
1418
1447
  return address;
1419
1448
  }
1420
- const lastAt = address.lastIndexOf('@');
1449
+ // dtext includes '@', so a domain literal is split off at the '@' in front of it and
1450
+ // not at the last one, which delivered 'a@[x@evil.com]' to evil.com
1451
+ const literal = address.charAt(address.length - 1) === ']' ? DOMAIN_LITERAL_TAIL.exec(address) : null;
1452
+ const lastAt = literal ? address.length - literal[1].length - 1 : address.lastIndexOf('@');
1421
1453
  if (lastAt < 0) {
1422
1454
  // Bare username, there is no domain to split off
1423
1455
  return this._normalizeLocalPart(address);
@@ -1,3 +1,3 @@
1
1
  export declare const name = "nodemailer";
2
- export declare const version = "10.1.2";
2
+ export declare const version = "10.1.7";
3
3
  export declare const homepage = "https://nodemailer.com/";
@@ -1,4 +1,4 @@
1
1
  // Generated by scripts/build.js from package.json. Do not edit by hand.
2
2
  export const name = 'nodemailer';
3
- export const version = '10.1.2';
3
+ export const version = '10.1.7';
4
4
  export const homepage = 'https://nodemailer.com/';
@@ -19,10 +19,27 @@ import * as punycode from '../punycode/index.js';
19
19
  // Matches a "scheme:" not followed by "//" (and with something after it), used
20
20
  // to re-insert the authority separator the legacy parser did not require.
21
21
  const SLASHLESS_AUTHORITY = /^([a-zA-Z][a-zA-Z0-9+.-]*:)(?!\/\/)([\s\S]+)$/;
22
- // Leading and trailing C0 controls and spaces, which the WHATWG parser strips before it
23
- // looks at the input. Stripped up front so that the slash-less form is recognized in a
24
- // value read from a file with a trailing newline as well.
25
- const SURROUNDING_WHITESPACE = /^[\x00-\x20]+|[\x00-\x20]+$/g;
22
+ /**
23
+ * Drops the leading and trailing C0 controls and spaces, which the WHATWG parser strips
24
+ * before it looks at the input. Stripped up front so that the slash-less form is recognized
25
+ * in a value read from a file with a trailing newline as well. An index scan, the regex
26
+ * /^[\x00-\x20]+|[\x00-\x20]+$/g retried a run of spaces inside the value from every
27
+ * position in it
28
+ *
29
+ * @param input URL string
30
+ * @returns The string without the surrounding controls and spaces
31
+ */
32
+ function stripSurroundingWhitespace(input) {
33
+ let start = 0;
34
+ let end = input.length;
35
+ while (start < end && input.charCodeAt(start) <= 0x20) {
36
+ start++;
37
+ }
38
+ while (end > start && input.charCodeAt(end - 1) <= 0x20) {
39
+ end--;
40
+ }
41
+ return input.slice(start, end);
42
+ }
26
43
  // Leading characters legacy url.parse() skips before it reads the scheme
27
44
  const LEGACY_TRIM = /^[\x00-\x20\u00a0\ufeff]+/;
28
45
  // The authority of a "scheme://authority/..." or a scheme-relative "//authority/..."
@@ -117,7 +134,7 @@ function normalizeHostname(raw, href) {
117
134
  return mapped;
118
135
  }
119
136
  export const parse = (input, parseQueryString) => {
120
- input = (input || '').replace(SURROUNDING_WHITESPACE, '');
137
+ input = stripSurroundingWhitespace(input || '');
121
138
  // Legacy url.parse() parses a "user:pass@host:port" authority that follows
122
139
  // the scheme even without the "//" separator, for schemes outside its
123
140
  // built-in slashed-protocol list (smtp:/smtps:/socks:/...). The WHATWG
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodemailer",
3
- "version": "10.1.2",
3
+ "version": "10.1.7",
4
4
  "description": "Easy as cake e-mail sending from your Node.js applications",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/nodemailer.js",
package/package.json CHANGED
@@ -87,7 +87,7 @@
87
87
  "@mavogel/mvc-projen": "^0.0.61",
88
88
  "cdk-nag": "^3.0.1",
89
89
  "constructs": "^10.5.1",
90
- "mailparser": "^3.9.40",
90
+ "mailparser": "^3.9.46",
91
91
  "uuid": "^14.0.3"
92
92
  },
93
93
  "bundledDependencies": [
@@ -122,7 +122,7 @@
122
122
  "publishConfig": {
123
123
  "access": "public"
124
124
  },
125
- "version": "0.1.24",
125
+ "version": "0.1.25",
126
126
  "jest": {
127
127
  "coverageProvider": "v8",
128
128
  "transformIgnorePatterns": [
@@ -1,11 +0,0 @@
1
- {
2
- "rules": {
3
- "indent": 0,
4
- "global-require": 0,
5
- "no-await-in-loop": 0
6
- },
7
- "extends": ["nodemailer", "prettier"],
8
- "parserOptions": {
9
- "ecmaVersion": 2017
10
- }
11
- }
@@ -1,4 +0,0 @@
1
- # These are supported funding model platforms
2
-
3
- github: [andris9] # enable once enrolled
4
- custom: ['https://www.paypal.me/nodemailer']
@@ -1,75 +0,0 @@
1
- name: "libbase64 security vulnerability report"
2
- description: "Report an exploitable security vulnerability in libbase64"
3
-
4
- body:
5
- - type: markdown
6
- attributes:
7
- value: |
8
- Before reporting, read our
9
- [Security Policy](https://github.com/nodemailer/libbase64/security/policy).
10
-
11
- Reports must demonstrate a credible security impact.
12
- Technically valid bugs without a realistic attack
13
- scenario belong in the regular issue tracker.
14
-
15
- - type: textarea
16
- id: summary
17
- attributes:
18
- label: Vulnerability summary
19
- description: Describe the vulnerability and affected versions.
20
- validations:
21
- required: true
22
-
23
- - type: textarea
24
- id: attacker
25
- attributes:
26
- label: Attacker capabilities
27
- description: |
28
- What can an attacker control without already having
29
- privileged access to the application or its configuration?
30
- validations:
31
- required: true
32
- min_length: 100
33
-
34
- - type: textarea
35
- id: exploit
36
- attributes:
37
- label: Realistic exploitation scenario
38
- description: |
39
- Describe how this can be exploited in a real application.
40
- Explain the prerequisites and security boundary crossed.
41
- validations:
42
- required: true
43
- min_length: 150
44
-
45
- - type: textarea
46
- id: poc
47
- attributes:
48
- label: Proof of concept
49
- description: Provide reproducible steps or working code.
50
- validations:
51
- required: true
52
-
53
- - type: textarea
54
- id: impact
55
- attributes:
56
- label: Security impact
57
- description: |
58
- What can the attacker achieve? Who is affected?
59
- Explain why this is a security vulnerability rather
60
- than an ordinary bug.
61
- validations:
62
- required: true
63
- min_length: 100
64
-
65
- - type: checkboxes
66
- id: confirmation
67
- attributes:
68
- label: Reporting requirements
69
- options:
70
- - label: I have read the Security Policy.
71
- required: true
72
- - label: I have verified the finding against a supported version.
73
- required: true
74
- - label: I have described a credible attacker-controlled scenario.
75
- required: true
@@ -1,39 +0,0 @@
1
- on:
2
- push:
3
- branches:
4
- - master
5
- # Manual run: publish the version currently on master (used when a release was cut
6
- # but the publish step failed)
7
- workflow_dispatch:
8
-
9
- permissions:
10
- contents: write
11
- pull-requests: write
12
- id-token: write
13
-
14
- name: release
15
- jobs:
16
- release-please:
17
- runs-on: ubuntu-latest
18
- steps:
19
- - uses: google-github-actions/release-please-action@v3
20
- id: release
21
- if: ${{ github.event_name == 'push' }}
22
- with:
23
- release-type: node
24
- package-name: ${{vars.NPM_MODULE_NAME}}
25
- pull-request-title-pattern: 'chore${scope}: release ${version} [skip-ci]'
26
- # The logic below handles the npm publication through npm trusted publishing
27
- # (OIDC, no token secret): it runs when a new release is created, or on a
28
- # manual dispatch.
29
- - uses: actions/checkout@v4
30
- if: ${{ steps.release.outputs.release_created || github.event_name == 'workflow_dispatch' }}
31
- - uses: actions/setup-node@v4
32
- with:
33
- node-version: 24
34
- registry-url: 'https://registry.npmjs.org'
35
- if: ${{ steps.release.outputs.release_created || github.event_name == 'workflow_dispatch' }}
36
- - run: npm ci
37
- if: ${{ steps.release.outputs.release_created || github.event_name == 'workflow_dispatch' }}
38
- - run: npm publish --provenance --access public
39
- if: ${{ steps.release.outputs.release_created || github.event_name == 'workflow_dispatch' }}
@@ -1,21 +0,0 @@
1
- name: Run tests
2
-
3
- on:
4
- push:
5
- pull_request:
6
-
7
- jobs:
8
- test:
9
- strategy:
10
- matrix:
11
- node: [16.x, 18.x, 20.x, 21.x]
12
- os: [ubuntu-latest]
13
- runs-on: ${{ matrix.os }}
14
- steps:
15
- - uses: actions/checkout@v2
16
- - name: Use Node.js ${{ matrix.node }}
17
- uses: actions/setup-node@v4
18
- with:
19
- node-version: ${{ matrix.node }}
20
- - run: npm install
21
- - run: npm test
@@ -1,13 +0,0 @@
1
- module.exports = {
2
- upgrade: true,
3
- reject: [
4
- // 12 is esm only ("type": "module"), and grunt-mocha-test require()s it as a
5
- // constructor - "Mocha is not a constructor". Node 24 hides this through
6
- // require(esm); CI on Node 22 does not. Lift it when the runner drops grunt.
7
- 'mocha',
8
- // 5x is esm only
9
- 'chai',
10
- // api changes in newer eslint
11
- 'grunt-eslint'
12
- ]
13
- };
@@ -1,8 +0,0 @@
1
- module.exports = {
2
- printWidth: 160,
3
- tabWidth: 4,
4
- singleQuote: true,
5
- endOfLine: 'lf',
6
- trailingComma: 'none',
7
- arrowParens: 'avoid'
8
- };
@@ -1,131 +0,0 @@
1
- 'use strict';
2
-
3
- const { Buffer } = require('node:buffer');
4
- const iconv = require('iconv-lite');
5
- const encodingJapanese = require('encoding-japanese');
6
- const charsets = require('./charsets');
7
-
8
- // iconv-lite codecs that are not character sets a message could be written in. UTF-7 is a known
9
- // way to smuggle markup past filters (=?utf-7?Q?+ADw-script+AD4-?= decodes to "<script>"), base64
10
- // and hex are transfer encodings. A name resolving to one of them is treated like a charset
11
- // iconv-lite does not know. Compared in the canonical form iconv-lite itself resolves names in
12
- const UNSUPPORTED_CODECS = new Set(['utf7', 'utf7imap', 'base64', 'hex']);
13
- const isUnsupportedCodec = name => UNSUPPORTED_CODECS.has(name.toLowerCase().replace(/:\d{4}$|[^0-9a-z]/g, ''));
14
-
15
- /**
16
- * Character set encoding and decoding functions
17
- */
18
- const charset = (module.exports = {
19
- /**
20
- * Encodes an unicode string into an Buffer object as UTF-8
21
- *
22
- * We force UTF-8 here, no strange encodings allowed.
23
- *
24
- * @param {String} str String to be encoded
25
- * @return {Buffer} UTF-8 encoded typed array
26
- */
27
- encode(str) {
28
- return Buffer.from(str, 'utf-8');
29
- },
30
-
31
- /**
32
- * Decodes a string from Buffer to an unicode string using specified encoding
33
- * NB! Throws if unknown charset is used
34
- *
35
- * @param {Buffer} buf Binary data to be decoded
36
- * @param {String} [fromCharset='UTF-8'] Binary data is decoded into string using this charset
37
- * @return {String} Decoded string
38
- */
39
- decode(buf, fromCharset) {
40
- fromCharset = charset.normalizeCharset(fromCharset || 'UTF-8');
41
-
42
- if (/^(?:(?:us-)?ascii|utf-8|7bit)$/i.test(fromCharset)) {
43
- return buf.toString('utf-8');
44
- }
45
-
46
- if (isUnsupportedCodec(fromCharset)) {
47
- // enforce utf-8, the same as for a charset iconv-lite does not know
48
- return buf.toString();
49
- }
50
-
51
- try {
52
- if (/^jis|^iso-?2022-?jp|^EUCJP/i.test(fromCharset)) {
53
- if (typeof buf === 'string') {
54
- buf = Buffer.from(buf);
55
- }
56
- try {
57
- let output = encodingJapanese.convert(buf, {
58
- to: 'UNICODE',
59
- from: fromCharset,
60
- type: 'string'
61
- });
62
- if (typeof output === 'string') {
63
- return output;
64
- }
65
- // fall through to iconv-lite if convert returned something unexpected
66
- } catch (err) {
67
- // ignore, defaults to iconv-lite on error
68
- }
69
- }
70
-
71
- return iconv.decode(buf, fromCharset);
72
- } catch (err) {
73
- // enforce utf-8, data loss might occur
74
- return buf.toString();
75
- }
76
- },
77
-
78
- /**
79
- * Convert a string from specific encoding to UTF-8 Buffer
80
- *
81
- * @param {String|Buffer} data String or Buffer to be encoded
82
- * @param {String} [fromCharset='UTF-8'] Source encoding for the string
83
- * @return {Buffer} UTF-8 encoded typed array
84
- */
85
- convert(data, fromCharset) {
86
- fromCharset = charset.normalizeCharset(fromCharset || 'UTF-8');
87
-
88
- let bufString;
89
-
90
- if (typeof data !== 'string') {
91
- if (/^(?:(?:us-)?ascii|utf-8|7bit)$/i.test(fromCharset)) {
92
- return data;
93
- }
94
-
95
- bufString = charset.decode(data, fromCharset);
96
- return charset.encode(bufString);
97
- }
98
- return charset.encode(data);
99
- },
100
-
101
- /**
102
- * Converts well known invalid character set names to proper names.
103
- * eg. win-1257 will be converted to windows-1257. Missing or non-string
104
- * input defaults to UTF-8.
105
- *
106
- * @param {String} charset Charset name to convert
107
- * @return {String} Canonicalized charset name
108
- */
109
- normalizeCharset(charset) {
110
- charset = (charset || 'UTF-8').toString().toLowerCase().trim();
111
-
112
- // first pass
113
- if (charsets.hasOwnProperty(charset) && charsets[charset]) {
114
- return charsets[charset];
115
- }
116
-
117
- charset = charset
118
- .replace(/^utf[-_]?(\d+)/, 'utf-$1')
119
- .replace(/^(?:us[-_]?)ascii/, 'windows-1252')
120
- .replace(/^win(?:dows)?[-_]?(\d+)/, 'windows-$1')
121
- .replace(/^(?:latin|iso[-_]?8859)?[-_]?(\d+)/, 'iso-8859-$1')
122
- .replace(/^l[-_]?(\d+)/, 'iso-8859-$1');
123
-
124
- // updated pass
125
- if (charsets.hasOwnProperty(charset) && charsets[charset]) {
126
- return charsets[charset];
127
- }
128
-
129
- return charset.toUpperCase();
130
- }
131
- });